xsl-list
[Top] [All Lists]

Grouping hierarchy path elements, part 2

2004-08-24 01:58:20

Hi all,

I am a great deal further now, since I can re-create the tree structure
from a path string. Now again, my task has become a bit more complicated.
Instead of extracting the path of an element right from the source document
root, references to elements containing the path information are grouped in
other elements.
Elements containing paths are to be transformed into the destination
document selectively.

To make things clearer, here is an example of the source file:
<?xml version="1.0" encoding="UTF-8"?>
<sourceDocument>
  <items>
     <item id="1">
       <path>root\folderA\folderB\folderC</path>
     </item>
     <item id="2">
       <path>root\folderA\folderB\folderD</path>
     </item>
     <item id="3">
       <path>root\folderA\folderE\folderF</path>
     </item>
     <item id="4">
       <path>root\folderG</path>
     </item>
     <item id="5">
       <path>root\folderA\folderB\folderD</path>
     </item>
  </items>
  <otherItems>
     <otherItem id="A">
       <referenceItemId>2</referenceItemId>
       <referenceItemId>3</referenceItemId>
       <referenceItemId>5</referenceItemId>
     </otherItem>
     <otherItem id="B">
       <referenceItemId>5</referenceItemId>
     </otherItem>
  </otherItems>
</sourceDocument>

This is what the transformed file should look like:
<?xml version="1.0" encoding="UTF-8"?>
<transformedDocument>
  <Chapter id="A">
     <path name="root">
       <path name="folderA">
          <path name="folderB">
            <path name="folderD">
               <item id="2" />
               <item id="5" />
            </path>
          </path>
          <path name="folderE">
            <path name="folderF">
               <item id="3" />
            </path>
          </path>
       </path>
     </path>
  </Chapter>
  <Chapter id="B">
     <path name="root">
       <path name="folderA">
          <path name="folderB">
            <path name="folderD">
               <item id="5" />
            </path>
          </path>
       </path>
     </path>
  </Chapter>
</transformedDocument>

My current XSLT looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform";>
  <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
  <!-- Match the source document root -->
  <xsl:template match="/sourceDocument">
     <transformedDocument>
       <xsl:apply-templates select="otherItems"/>
       <!-- Uncomment line below to check wheather template items is
working. -->
       <!--xsl:apply-templates select="items"/-->
     </transformedDocument>
  </xsl:template>
  <xsl:template match="otherItems">
     <xsl:apply-templates/>
  </xsl:template>
  <xsl:template match="otherItem">
     <!-- Create a node 'Chapter' for each element 'otherItem'. -->
     <Chapter>
       <xsl:attribute name="id"><xsl:value-of select="attribute::id"/></
xsl:attribute>
       <xsl:variable name="root" select="
substring-before(//items/item[1]/path, '\')"/>
       <path name="{$root}">
          <xsl:call-template name="transformDocument">
            <xsl:with-param name="path" select="$root"/>
            <xsl:with-param name="items" select="
//item[attribute::id=referenceItemId]"/>
          </xsl:call-template>
       </path>
       <xsl:comment>
          <xsl:text>//item[attribute::id]: </xsl:text>
          <xsl:value-of select="//item[attribute::id]"/>
          <xsl:text>
          </xsl:text>
          <xsl:text>referenceItemId: </xsl:text>
          <xsl:value-of select="referenceItemId"/>
       </xsl:comment>
     </Chapter>
  </xsl:template>
  <xsl:template match="items">
     <xsl:variable name="root" select="substring-before(item[1]/path, '\')
"/>
     <path name="{$root}">
       <xsl:call-template name="transformDocument">
          <xsl:with-param name="path" select="$root"/>
          <xsl:with-param name="items" select="item"/>
       </xsl:call-template>
     </path>
  </xsl:template>
  <xsl:template name="transformDocument">
     <xsl:param name="path"/>
     <xsl:param name="items" select="$items"/>
     <xsl:comment>
       <xsl:text>transformDocument called with items param='</xsl:text>
       <xsl:value-of select="$items"/>
       <xsl:text>'</xsl:text>
     </xsl:comment>
     <xsl:if test="$items">
       <xsl:variable name="step">
          <xsl:variable name="rest" select="substring-after($items[1]/path,
concat($path, '\'))"/>
          <xsl:choose>
            <xsl:when test="contains($rest, '\')">
               <xsl:value-of select="substring-before($rest, '\')"/>
            </xsl:when>
            <xsl:otherwise>
               <xsl:value-of select="$rest"/>
            </xsl:otherwise>
          </xsl:choose>
       </xsl:variable>
       <xsl:variable name="newPath" select="concat($path, '\', $step)"/>
       <path name="{$step}">
          <xsl:apply-templates select="$items[path = $newPath]"/>
          <xsl:call-template name="transformDocument">
            <xsl:with-param name="path" select="$newPath"/>
            <xsl:with-param name="items" select="$items[starts-with(path,
concat($newPath, '\'))]"/>
          </xsl:call-template>
       </path>
       <xsl:call-template name="transformDocument">
          <xsl:with-param name="path" select="$path"/>
          <xsl:with-param name="items" select="$items[path != $newPath and
                                                  not(starts-with(path,
concat($newPath, '\')))]"/>
       </xsl:call-template>
     </xsl:if>
  </xsl:template>
  <xsl:template match="item">
     <xsl:comment>
       <xsl:text>Item path=</xsl:text>
       <xsl:value-of select="path"/>
     </xsl:comment>
     <item id="{(_at_)id}"/>
  </xsl:template>
</xsl:stylesheet>

It seems as if there is something wrong with my items parameter for the
transformDocument template called from the template 'otherItem'.
If you run the above, you will notice that <xsl:value-of select="
//item[attribute::id]"/> actually does not return the id-Attribute element
of all items, but instead returns the child elements of the first
referenced item. Finding a solution to this would get me a big step ahead I
think.

Maybe anybody could point me the right direction?
Thanks a lot.

Mit freundlichen Grüßen / Sincerely

Daniel Geske


Telematik/Infotainment, AE-V32
Telematics/Infotainment, AE-V32

IAV GmbH
Ingenieurgesellschaft Auto und Verkehr
Carnotstraße 1
10587 Berlin
Germany

Tel.:  +49  (30)  3 99 78 - 90 44
Fax: +49  (30)  3 99 78 - 94 11

E-mail: <mailto:daniel(_dot_)geske(_at_)iav(_dot_)de>
Internet: http://www.iav.de




<Prev in Thread] Current Thread [Next in Thread>