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:
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?
I'd suggest using match templates over named templates because it's more, well, what's the XSLT equivalent of pythonic? Xslt-y? I think you'll find that you can solve problems easier in that processing methodology.
If you insist on using named templates because of some unknown requirement, you may find that if you refactor your logic to make it easy to detect the first instance, you'll simplify your logic altogether.
Can you clarify as to why you can't detect when the the first instance is needed? We can probably help craft an xpath expression that would let you do want you want to. E.g.
<xsl:template name="some_template">
<xsl:variable name="EXPRESSION" select=".[somelogic='true']"/>
<xsl:if test="$EXPRESSION">
<xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text>
</xsl:if>
</xsl:template>
Since XSLT is deterministic - an effect of being completely functional as Greg put it - (unless you're doing weird extension stuff) you can decide when the first time is appropriate by applying logic to the input. Also, you have access to the context node in the template so you know where it's being called from.
Because XSLT is a purely functional language, there are no global variables that you can set.
You will instead have to choose the circumstances under which you call your some_template
template. If you only want to call it once, then make only one call to it.
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