I have the following XML source:
<element not-relevant="true" bold="true" superscript="true" subscript="false" text="stuff"/>
In any order, I need to loop through specific attributes (i.e. only ones which are related to the HTML I'm building: bold/superscript/subscript, etc.) and where one of these attributes evaluates to 'true', output nested elements to get the following output:
<strong>
<sup>
stuff
</sup>
</strong>
I have a feeling I need to use some sort of recursion like follows (without the infinite loop, of course):
<xsl:template match="element">
<xsl:call-template name="content">
<xsl:with-param name="text" select="@text"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="content">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="@bold = 'true'">
<strong>
<xsl:copy>
<xsl:call-template name="content">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
<xsl:copy>
</strong>
</xsl:when>
<xsl:when test="@subscript = 'true'">
<sub>
<xsl:copy>
<xsl:call-template name="content">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
<xsl:copy>
</sub>
</xsl:when>
<xsl:when test="@superscript = 'true'">
<sup>
<xsl:copy>
<xsl:call-template name="content">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
<xsl:copy>
</sup>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" disable-output-escaping="yes"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Any ideas? I'm looking for the cleanest XSLT 2.0 solution and appreciate the help.
Thanks,
This is a nice use case for <xsl:next-match/>
:
<xsl:template match="element" priority="1">
<xsl:value-of select="@text" />
</xsl:template>
<xsl:template match="element[@superscript = 'true']" priority="2">
<sup><xsl:next-match/></sup>
</xsl:template>
<xsl:template match="element[@subscript = 'true']" priority="3">
<sub><xsl:next-match/></sub>
</xsl:template>
<xsl:template match="element[@bold = 'true']" priority="4">
<strong><xsl:next-match/></strong>
</xsl:template>
When you apply templates to an element
element it'll first fire the highest priority matching template, and if that template uses next-match
it will delegate to the next highest priority, etc. Your example element
in the question matches the first, second and fourth templates above, so initially the "bold" template would be selected, then that would delegate to the "superscript" one and finally to the generic element
one, resulting in <strong><sup>stuff</sup></strong>
.
As you can see from this example, the priority numbers are what determines the order of nesting - if the priorities of the second and fourth templates were reversed you'd get <sup><strong>stuff</strong></sup>
instead.
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