I have a block of XSLT that may be applied several times throughout a transform. But I want to it actually run only the first time it is applied, it shoul be skipped all subsiquent times. How do I do this?
As an example, this is the sort of thing I want to do: In the stylesheet I define a global variable:
<xsl:variable name="run_once" select="0"/>
Then I have a template which is called several times:
<xsl:template name="some_template">
<xsl:if test="$run_once != 1">
<xsl:variable name="run_once" select="1"/>
<xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text>
</xsl:if>
</xsl:template>
This does not work of course, because variables cannot be changed, only overloaded. So, once the some_template exits $run_once is once again 0 and the text is applied every time the template is called. Is there some type of ifdef functionality or other global object I can set?
If you are interested in why I want to do this, below is a more detailed explanation of my problem and the solution I used:
- My input is data in raw XML, my output is a report in WordML format.
- In the input I have a series of nodes (named theNode). Some, but not all, of these nodes need to be displayed in the output. The node should be displayed only if the XPATH hairyLogic is true (hairyLogic is obviously long and complex).
- theNode's also have a type (stored in a sub-node). In the input, all theNode's of the same type will always be grouped together. In the output, all theNode's of the same type should be grouped under a specific heading for that type (there should be only one heading for each type).
This is the solution I ended up using:
...
<xsl:apply-templates select="theNode[hairyLogic]"/>
...
<xsl:template match="theNode">
<xsl:if test="count(preceding-sibling::theNode[type = current()/type and hairyLogic])=0">
<xsl:choose>
<xsl:when test="type = 'TYPE1a' or type = 'TYPE1b'">
<xsl:call-template name="TYPE1Heading"/>
</xsl:when>
<xsl:when test="type = 'TYPE2'">
<xsl:call-template name="TYPE2Heading"/>
</xsl:when>
</xsl:choose>
</xsl:if>
...
</xsl:template>
I chose to use named templates for the headings because they contain basic WordML that does not depend on any data in the input XML.
I don't like this solution because hairyLogic is repeated and the if statement is convoluted and hard to read. Maybe you have a better solution that doesn't require mutable variables?