Reputation: 109
I have an xml structure like this:
<nav>
<group>
<menu>
<item>
<nav>
<item></item>
</nav>
</item>
</menu>
</group>
<group>
<item></item>
<item></item>
</group>
</nav>
I want to get this result using XSLT 1.0:
<nav id="1">
<group>
<menu id="1-1">
<item id="1-1-1">
<nav id="1-1-1-1">
<item id="1-1-1-1-1"></item>
</nav>
</item>
</menu>
</group>
<group>
<item id="1-2"></item>
<item id="1-3"></item>
</group>
</nav>
It is a bit tricky.
I have been trying using xsl:number but it insists on including the 'group' in the numbering.
Thanks in advance.
Upvotes: 0
Views: 309
Reputation: 29022
Now this answer is complete and satisfies your desired output requirements, but I guess it's still not perfect. However, it's the best answer that could be achieved by the given data:
XSLT-1.0:
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" />
<xsl:strip-space elements="*" />
<!-- modified identity transform -->
<xsl:template match="@*|node()">
<xsl:variable name="depth" select="count(ancestor::*) - count(ancestor::group)" />
<xsl:element name="{name()}">
<xsl:if test="not(../group)">
<xsl:attribute name="id">
<xsl:call-template name="num">
<xsl:with-param name="cnt" select="$depth" />
</xsl:call-template>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template name="num">
<xsl:param name="cnt" />
<xsl:choose>
<xsl:when test="self::item and $cnt = 0">
<xsl:variable name="itm" select="count(preceding::item)" />
<xsl:variable name="grp" select="count(preceding::group) = 0" />
<xsl:value-of select="$itm + $grp" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'1'" />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$cnt != 0">
<xsl:value-of select="'-'"/>
<xsl:call-template name="num">
<xsl:with-param name="cnt" select="$cnt - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The result of this XSLT is:
<?xml version="1.0"?>
<nav id="1">
<group>
<menu id="1-1">
<item id="1-1-1">
<nav id="1-1-1-1">
<item id="1-1-1-1-1"/>
</nav>
</item>
</menu>
</group>
<group>
<item id="1-2"/>
<item id="1-3"/>
</group>
</nav>
as desired.
Upvotes: 1