tags:

views:

107

answers:

2

I have several <xsl:for-each/> which run the one after the other. I would like, at the end, to do something if I did not pass in any of them. For only one for-each, I can manage to make a <xsl:choose/> with an appropriate test based on the selector in the for-each, but for a lot of them, it begins to be very ugly.

Has anyone a solution for keeping track of a passing through several for-each ?

+3  A: 

Assuming you have something like:

<xsl:for-each select="foo[@bar]">
    <!-- do stuff for foo elements having a bar attribute -->
</xsl:for-each>

<xsl:for-each select="foo[@fap]">
    <!-- do stuff for foo elements having a fap attribute -->
</xsl:for-each>

then you can create the union of the nodesets selected in each for-each and, if that nodeset is empty, do something else:

<xsl:if test="not(foo[@bar] | foo[@fap])">
    <!-- there weren't any nodes matched above, so do something else -->
</xsl:if>

EDIT: In the case where your nodeset-selecting XPath expressions are very complex, you can make things easier to follow by using variables with meaningful names; for example:

<xsl:variable name="articles" select="stuff/that/is[3]/very[@deeply-nested and position() &lt; 5]"/>
<xsl:variable name="comments" select="stuff/that/is[1]/very[@deeply-nested and position() &gt; 27]"/>
<xsl:variable name="rants" select="stuff/that/is[17]/even/more[@deeply-nested and position() &lt; 5]/with/some/more/nesting"/>

<h1>Ramblings</h1>

<xsl:for-each select="$articles">
    <!-- do stuff with articles -->
    <h2>Article <xsl:value-of select-"position()"/></h2>
</xsl:for-each>

<xsl:for-each select="$comments">
    <!-- do stuff with comments -->
    <h2>Comment <xsl:value-of select-"position()"/></h2>
</xsl:for-each>

<xsl:for-each select="$rants">
    <!-- do stuff with rants -->
    <h2>Rant <xsl:value-of select-"position()"/></h2>
</xsl:for-each>

<xsl:if test="not($articles | $comments | $rants)">
    <!-- nobody had anything to say... -->
    <h2>Nothing to see here</h2>
</xsl:if>
NickFitz
Yep, that's exactly I was trying to avoid actually... :) Thanks anyways.
subtenante
Out of curiosity, why were you trying to avoid it? Such use of set operations is exactly what XSLT/XPath were defined for :-)
NickFitz
@subtenante: You can't check if a certain part of your script executed or not, XSLT is not designed that way. You can check, however, whether the *conditions* for executing a certain part are met. Which is exactly the same thing, from an XSLT point of view.
Tomalak
@Nick : because the test will be very long and not easy to maintain at all. But if there is no other way, I guess it'll have to do. Thanks a lot.
subtenante
@subtenante: you can make things easier to follow by assigning your nodesets to variables; I'll update my answer with an example.
NickFitz
Aye, far better !
subtenante
A: 

You could use <xsl:variable> to set a local variable according to which for-each you did enter, and then test if with <xsl:if> at the end.

JBRWilkinson
That wouldn't work: the variable would be scoped to the inside of the for-each, and so wouldn't be visible outside. A variable defined outside couldn't have its value changed within the for-each.
NickFitz
Nick is right, I tried this but you have to define the variable before, and thus affect a value to it. Then you can't change it so it's useless.
subtenante
I stand corrected - my mistake.
JBRWilkinson