Reputation: 175
EDIT:
I think I found a way around this issue while still using XSLT 1.0, although very verbose and probably prone to errors.
Is there a way to use the <xsl:number>
element but start counting at zero instead of one, especially when using level="multiple"
?
I'm using XSLT 1.0.
Current result: 1.2.2. Subitem_B
Expected result: 0.1.1. Subitem_B
I tried format="0"
but it only outputs the points (i.e. ... Subitem_B
)
<xsl:number level="multiple" format="0. "/>
Bonus question:
I found a way around it using translate($number,'.','-')
, but I'd still be curious to know if there is a way use a custom character instead of the points as delimiters, or even a custom format
altogether.
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 match="item"/>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<xsl:number level="multiple" format="1. "/>
<xsl:apply-templates match="item"/>
</xsl:template>
</xsl:stylesheet>
HTML Output
<html>
<body>
1. Main_A
1.1. Item_A
1.2. Item_B
1.2.1. Subitem_A
1.2.2. Subitem_B
1.3. Item_C
2. Main_B
2.1. Item_A
2.1.1. Subitem_A
2.2. Item_B
</body>
</html>
Upvotes: 0
Views: 1034
Reputation: 117003
If your processor supports the EXSLT str:tokenize()
extension function (as I believe it does), you can do:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:template match="/root">
<html>
<body>
<ul>
<xsl:apply-templates select="item"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<xsl:variable name="num">
<xsl:number level="multiple" format="1."/>
</xsl:variable>
<li>
<xsl:text>path:</xsl:text>
<xsl:for-each select="str:tokenize($num, '.')">
<xsl:value-of select=". - 1" />
<xsl:if test="position()!=last()">
<xsl:text>:</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text> = </xsl:text>
<xsl:value-of select="text()" />
<xsl:if test="item">
<ul>
<xsl:apply-templates select="item"/>
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
Applied to your input example, the result will be:
<html>
<body>
<ul>
<li>path:0 = Main_A
<ul>
<li>path:0:0 = Item_A</li>
<li>path:0:1 = Item_B
<ul>
<li>path:0:1:0 = Subitem_A</li>
<li>path:0:1:1 = Subitem_B</li>
</ul>
</li>
<li>path:0:2 = Item_C</li>
</ul>
</li>
<li>path:1 = Main_B
<ul>
<li>path:1:0 = Item_A
<ul>
<li>path:1:0:0 = Subitem_A</li>
</ul>
</li>
<li>path:1:1 = Item_B</li>
</ul>
</li>
</ul>
</body>
</html>
rendered as:
which I believe is the result you asked for in your other question.
Note that match
is not a valid attribute of xsl:apply-templates
.
Upvotes: 1
Reputation: 167581
I think you would need to move to XSLT 3.0 and use https://www.w3.org/TR/xslt-30/#start-at e.g.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:template match="root">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<xsl:number level="multiple" format="1. " start-at="0"/>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
with oXygen 19 and Saxon 9.7 PE gives the result
<html>
<body>
0. Main_A
0.0. Item_A
0.1. Item_B
0.1.0. Subitem_A
0.1.1. Subitem_B
0.2. Item_C
1. Main_B
1.0. Item_A
1.0.0. Subitem_A
1.1. Item_B
</body>
</html>
for your input sample.
Upvotes: 1