Simulating a while loop
> 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.
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)])"/> <!-- 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.