[xsl] Re: Tree from a flat list - beginner's question

Subject: [xsl] Re: Tree from a flat list - beginner's question
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Fri, 5 Oct 2001 05:06:06 -0700 (PDT)
> How can I build the corresponding XML tree from a flat 
> element-elementParent list if I do not know
> how many levels will I have:
> 
> <root>
> 	<row id=100 parentid=0   name=A/>
> 	<row id=101 parentid=100 name=A1/>
> 	<row id=102 parentid=100 name=A2/>
> 	<row id=103 parentid=101 name=A11/>
> 	<row id=110 parentid=103 name=A111/>
> 	<row id=111 parentid=110 name=A1111/>
> 	<row id=120 parentid=102 name=A21/>
> <root/>

The above is not well-formed xml document! Should be:

<root>
	<row id="100" parentid="0"  name="A"/>
	<row id="101" parentid="100" name="A1"/>
	<row id="102" parentid="100" name="A2"/>
	<row id="103" parentid="101" name="A11"/>
	<row id="110" parentid="103" name="A111"/>
	<row id="111" parentid="110" name="A1111"/>
	<row id="120" parentid="102" name="A21"/>
</root>

Here's one way to construct the corresponding hierarchy:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:output indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="kRow" match="row" use="@parentid"/>

  <xsl:variable name="manySpaces" select="'                              '"/>
  <xsl:variable name="linkList" select="/root/row" />

  <xsl:template match="/">
    <xsl:call-template name="constructHierarchy"/>
  </xsl:template>

  <xsl:template name="constructHierarchy">
       <xsl:for-each select="key('kRow', '0')">
           <xsl:call-template name="makeElement">
             <xsl:with-param name="pElement" select="."/>
             <xsl:with-param name="indent" select="0"/>
           </xsl:call-template>
      </xsl:for-each>
  </xsl:template>

  <xsl:template name="makeElement">
    <xsl:param name="pElement" select="/.."/>
    <xsl:param name="indent" select="0"/>

    <xsl:text>&#xA;</xsl:text>
    <xsl:value-of select="substring($manySpaces, 1, $indent)"/>
    <xsl:element name="{$pElement/@name}">
      <xsl:for-each select="key('kRow', $pElement/@id)">
           <xsl:call-template name="makeElement">
             <xsl:with-param name="pElement" select="."/>
             <xsl:with-param name="indent" select="$indent + 2"/>
           </xsl:call-template>
      </xsl:for-each>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

The result of the transformation is:


<A>
  
   <A1>
    
      <A11>
      
         <A111>
        
            <A1111/>
         </A111>
      </A11>
   </A1>
  
   <A2>
    
      <A21/>
   </A2>
</A>


Hope this helped.

Cheers,
Dimitre Novatchev.


__________________________________________________
Do You Yahoo!?
NEW from Yahoo! GeoCities - quick and easy web site hosting, just $8.95/month.
http://geocities.yahoo.com/ps/info1

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread