Using XSLT/XPATH 1.0, I want to create HTML where the class
attribute of a span
element indicates the depth in the original XML hierarchy.
For example, with this XML fragment:
<text>
<div type="Book" n="3">
<div type="Chapter" n="6">
<div type="Verse" n="12">
</div>
</div>
</div>
</text>
I want this HTML:
<span class="level1">Book 3</span>
<span class="level2">Chapter 6</span>
<span class="level3">Verse 12</span>
How deep these div
elements could go is not known a priori. The div
s could be Book -> Chapter. They could be Volume -> Book -> Chapter -> Paragraph -> Line.
I cannot rely on the values of @type. Some or all could be NULLs.
This has a very simple and short solution -- no recursion, no parameters, no xsl:element
, no xsl:attribute
:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="div">
<span class="level{count(ancestor::*)}">
<xsl:value-of select="concat(@type, ' ', @n)"/>
</span>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<text>
<div type="Book" n="3">
<div type="Chapter" n="6">
<div type="Verse" n="12"></div></div></div>
</text>
the wanted, correct result is produced:
<span class="level1">Book 3</span>
<span class="level2">Chapter 6</span>
<span class="level3">Verse 12</span>
Explanation: Proper use of templates, AVT and the count()
function.
Or without using recursion - but Dimitre's answer is better than my one
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/text">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="//div">
<xsl:variable name="depth" select="count(ancestor::*)"/>
<xsl:if test="$depth > 0">
<xsl:element name="span">
<xsl:attribute name="class">
<xsl:value-of select="concat('level',$depth)"/>
</xsl:attribute>
<xsl:value-of select="concat(@type, ' ' , @n)"/>
</xsl:element>
</xsl:if>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With