looping, xslt

Looping

1. Simulating a while loop

1.

Simulating a while loop

David Carlisle



> Now imagine that when the conditions are such that <xsl:otherwise> is
> matched, one wants to break out of the <xsl:for-each>.
    

It is hard to imagine that because the template instantiated for each node selected by the xsl:for-each has no side effects and so any test that means that you do not want to evaluate the template on some node could have been done before the xsl:for-each.

You only need select the nodes that you want, you don't need to select all of the nodes and then try to `break' the loop.

It is best to think of xsl:for-each evaluating the template on all the nodes _at the same time_. Some xslt engines may in fact evaluate them one at a time, in document order, but they are not obliged to do that.

You can of course implement a while loop using a recursive named template rather than xsl:for-each.

Chris Maden adds

Thinking words like "while" and "until" will get you into trouble with XSLT. Try to rephrase the question: "do this if it's before the first foo where not bar". For example , let's say you have a list of <foo> siblings. One of them has a bar attribute; you only want the <foo>s before the first bar.

<xsl:apply-templates select="foo[following-siblings::*[@bar]]"/>

will only select the <foo>s who have a following sibling with a bar attribute.

Nikolai Grigoriev adds

> Imagine,
> <xsl:for-each select="foo">
>  <xsl:choose>
>   <xsl:when test="bar">blah</xsl:when>
>   <xsl:otherwise>blort</xsl:otherwise>
>  </xsl:choose>
> </xsl:for-each>
> 
> Now imagine that when the conditions are such that <xsl:otherwise> is
> matched, one wants to break out of the <xsl:for-each>.
> 

How about this:

<!-- Identify the stopper - the first node that does not have a bar -->
<xsl:variable name="stop-id" select="generate-id(foo[not(bar)][1])"/>

<!-- Segregate nodes preceding the stopper -->
<xsl:for-each select="foo">
  <xsl:if test="following-sibling::foo[generate-id() = $stop-id]">
    blah
  </xsl:if>
</xsl:for-each>

This is simple but suspicious from the efficiency point of view. I suspect that the recursive solution is more economic.