Is there a clever way to simplify the following stylesheet in order to avoid repeating a whole when
block when only one variable is changing between each of those?
Ideally I would like something like this, looping 6 times on $i
:
<xsl:when test="$depth > $i">
[...]
<xsl:value-of select="substring($npath,($nlength - $i*2),1) - 1"/>
[...]
</xsl:when>
I'm using XSLT 1.0.
XML Input
<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="stylesheet.xsl" version="1.0"?>
<root>
<item>Main_A
<item>Item_A</item>
<item>Item_B
<item>Subitem_A</item>
<item>Subitem_B</item>
</item>
<item>Item_C</item>
</item>
<item>Main_B
<item>Item_A
<item>Subitem_A</item>
</item>
<item>Item_B</item>
</item>
</root>
XSLT 1.0 Stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="root">
<html>
<body>
<xsl:apply-templates select="item">
<xsl:with-param name="depth" select="1"/>
</xsl:apply-templates>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<xsl:param name="depth" select="1"/>
<xsl:if test="$depth < 10">
<ul>
<li>
<xsl:text>path</xsl:text>
<xsl:call-template name="loopnumformat">
<xsl:with-param name="depth" select="$depth"/>
</xsl:call-template>
<xsl:text> = </xsl:text>
<xsl:apply-templates match="item">
<xsl:with-param name="depth" select="$depth + 1"/>
</xsl:apply-templates>
</li>
</ul>
</xsl:if>
</xsl:template>
<xsl:template name="loopnumformat">
<xsl:param name="depth" select="1"/>
<xsl:variable name="npath">
<xsl:number level="multiple" from="*[10]"/>
</xsl:variable>
<xsl:variable name="nlength">
<xsl:value-of select="string-length($npath)"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$depth > 2">
<xsl:text>:</xsl:text>
<xsl:value-of select="substring($npath,($nlength - 2*2),1) - 1"/>
<xsl:call-template name="loopnumformat">
<xsl:with-param name="depth" select="$depth - 1"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$depth > 1">
<xsl:text>:</xsl:text>
<xsl:value-of select="substring($npath,($nlength - 1*2),1) - 1"/>
<xsl:call-template name="loopnumformat">
<xsl:with-param name="depth" select="$depth - 1"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$depth > 0">
<xsl:text>:</xsl:text>
<xsl:value-of select="substring($npath,($nlength - 0*2),1) - 1"/>
<xsl:call-template name="loopnumformat">
<xsl:with-param name="depth" select="$depth - 1"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
HTML Output
<html>
<body>
<ul>
<li>path:0 = Main_A
<ul>
<li>path:0:0 = Item_A</li>
</ul>
<ul>
<li>path:0:1 = Item_B
<ul>
<li>path:0:1:0 = Subitem_A</li>
</ul>
<ul>
<li>path:0:1:1 = Subitem_B</li>
</ul>
</li>
</ul>
<ul>
<li>path:0:2 = Item_C</li>
</ul>
</li>
</ul>
<ul>
<li>path:1 = Main_B
<ul>
<li>path:1:0 = Item_A
<ul>
<li>path:1:0:0 = Subitem_A</li>
</ul>
</li>
</ul>
<ul>
<li>path:1:1 = Item_B</li>
</ul>
</li>
</ul>
</body>
</html>
It depends on the circumstances, but in your particular case, one way you could do it would be to move the
xsl:choose
inside, so that the parts that are the same in every case are expressed only once each:But you seem to be going to extreme lengths to use
xsl:number
when it doesn't quite meet your needs. It appears that you can do the whole thing much more simply:Perhaps you could even get rid of the
xsl:if
, which seems as if it may have been present to serve the limitations of theloopnumformat
template in your original stylesheet -- this version has no inherent depth limitation. Note that it does assume that the text nodes you want to copy into the output document will be limited to the first in each<item>
, but it would be easy enough to modify the stylesheet to instead copy all of them.It looks like you are over-engineering here. You are simply looking for a way to count preceding
<item>
nodes, recursively up the document tree.This simple transformation:
results in: