Re: [xsl] Identifier attribute (was: Re: [xsl] Creating Hierarchy)

Subject: Re: [xsl] Identifier attribute (was: Re: [xsl] Creating Hierarchy)
From: "Rowan Sylvester-Bradley" <rowan@xxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 23 Oct 2008 15:15:09 +0100
Thanks for your help with this. Using the technique you've suggested I've been able to successfully add the id values with two separate XSL transform documents, but I can't get it to work as a two-pass process in a single stylesheet. My input file is this:
<?xml version="1.0"?>
<mytree>
<node>
<name>Root of my tree</name>
<level>0</level>
</node>
<node>
<name>Child of root</name>
<level>1</level>
</node>
<node>
<name>Another child of root</name>
<level>1</level>
</node>
<node>
<name>Grandchild of root</name>
<level>2</level>
</node>
<node>
<name>Yet another child of root</name>
<level>1</level>
</node>
</mytree>


My fisrt transform is:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:call-template name="next-level">
<xsl:with-param name="level" select="0"/>
<xsl:with-param name="nodes" select="//node"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="next-level">
<xsl:param name="level"/>
<xsl:param name="nodes"/>
<xsl:if test="$nodes/level[.=$level]">
<!-- then group the nodes at this level -->
<xsl:for-each-group select="$nodes" group-starting-with="node[level[.=$level]]">
<!-- act on the first of each group only, passing others to next level -->
<newnode id="">
<xsl:copy-of select="name"/>
<!-- group at the next level assuming monotonically increasing level -->
<xsl:call-template name="next-level">
<xsl:with-param name="level" select="$level + 1"/>
<xsl:with-param name="nodes" select="current-group()[position()&gt;1]"/>
</xsl:call-template>
</newnode>
</xsl:for-each-group>
</xsl:if>
</xsl:template>
</xsl:stylesheet>


Which produces:
<?xml version="1.0" encoding="UTF-8"?>
<newnode id="">
  <name>Root of my tree</name>
  <newnode id="">
     <name>Child of root</name>
  </newnode>
  <newnode id="">
     <name>Another child of root</name>
     <newnode id="">
        <name>Grandchild of root</name>
     </newnode>
  </newnode>
  <newnode id="">
     <name>Yet another child of root</name>
  </newnode>
</newnode>

My second transform is:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema";>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*[@id]">
<xsl:copy>
<xsl:attribute name="id">
<xsl:number level="any" count="*[@id]"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>


Which when run on the intermediate result produces:
<?xml version="1.0" encoding="UTF-8"?>
<newnode id="1">
  <name>Root of my tree</name>
  <newnode id="2">
     <name>Child of root</name>
  </newnode>
  <newnode id="3">
     <name>Another child of root</name>
     <newnode id="4">
        <name>Grandchild of root</name>
     </newnode>
  </newnode>
  <newnode id="5">
     <name>Yet another child of root</name>
  </newnode>
</newnode>

This is the correct result.

How do I combine these two transforms into a single stylesheet using the two-pass approach? I can't get this to work...

Many thanks - Rowan

Current Thread