Daniel Silveira
Daniel Silveira

Reputation: 42543

How-to break a for-each loop in XSLT?

How-to break a for-each loop in XSLT?

Upvotes: 23

Views: 101077

Answers (6)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

A "break" from the body of an <xsl:for-each> XSLT instruction cannot be specified using a syntactic construct, however it can be simulated.

Essentially two techniques are discussed:

  1. Performing something inside the body of <xsl:for-each> only if a specific condition is satisfied. This can be improved if the condition can be specified in the select attribute of <xsl:for-each> -- in this case only the necessary nodes will be processed. See for example: https://stackoverflow.com/a/7532602/36305

  2. Specifying the processing not using <xsl:for-each> but with recursion. There are many examples of recursive processing with XSLT. See the code at: https://fxsl.sf.net/

The second method has the benefit of being able to perform the exit immediately, contrasted with the first method having to still perform many "empty cycles" even after the exit-condition has been satisfied.

Upvotes: 6

rjose
rjose

Reputation: 615

I had a similar situation and here is the code I had written. For logical reasons, I couldn't fit in the other conditions with condition01.

<xsl:for-each select="msxsl:node-set($DATA6)[condition01]"> 
<xsl:choose>
<xsl:when test="not((condtion02 or  condition03) and condition04)">
--body of for loop 
</xsl:when>
</xsl:choose>
</xsl:for-each>

Upvotes: 1

orophine
orophine

Reputation: 9

Hello I kwow this is an old post but maybe it can help other developers. I have found a way to break a for each in XSLT it is not litteraly a break but if you see the code you will get it. As you know or not know you can use inline C# code in xslt. In this example i want to loop al the nodes and take the first NTE node with Value RC But if I get a node that differs from the NTE node i want to stop looking at the condition. So I set a global variable in C# code and I ask the value each time I go through a node:

    <xsl:value-of select="userCSharp:SetStopForeach('true')" />
<xsl:for-each select="following-sibling::node()">

        <xsl:if test="local-name()='NTE_NotesAndComments_3' and userCSharp:GetStopForeach()" >

        <xsl:for-each select="NTE_4_CommentType">
            <xsl:if test="(CE_0364_0_IdentifierSt)[text()=&quot;RC&quot;]"> 
        <ns0:RESULTAAT_COMMENTAAR>
                    <xsl:for-each select="../NTE_3_Comment">

                        <xsl:value-of select="./text()" />
                    </xsl:for-each>
                </ns0:RESULTAAT_COMMENTAAR> 
            </xsl:if>
        </xsl:for-each>
        </xsl:if>
        <xsl:if test="local-name()='ORC_CommonOrder'" >
            <xsl:value-of select="userCSharp:SetStopForeach('false')" />
        </xsl:if>
    </xsl:for-each>


    .....

    <msxsl:script language="C#" implements-prefix="userCSharp">
 <![CDATA[ 

    public bool StopForeach=false;
    public bool GetStopForeach() {
        return StopForeach;
    }
    public string SetStopForeach(bool aValue) {
         StopForeach=aValue;
         return "";
    }

      ]]> 
      </msxsl:script>

Upvotes: 0

user663031
user663031

Reputation:

Put the condition for stopping the "loop" in the select attribute of the for-each element. For instance, to "break" after four elements:

<xsl:for-each select="nodes[position()&lt;=4]">

To iterate up to but not including a node that satisfied some particular condition:

<xsl:for-each select="preceding-sibling::node[condition]">

Upvotes: 20

Jacob Mattison
Jacob Mattison

Reputation: 51052

XSLT isn't a procedural language; don't think of for-each as being a "loop" in the way you have a loop in Java. For-each is a way to apply a template to each of a bunch of items. It doesn't necessarily happen in a particular order, so you can't think of it as "apply this template to each of a bunch of items until such-and-such happens, then stop".

That said, you can use the select attribute to filter the results, so it becomes more like "apply a template to each of a bunch of items, but only if such-and-such is true of them".

If what you really want is "apply a template to each of a bunch of items, where such-and-such is true of them, but only to the first one this is true of", you can combine the select attribute with the position() function.

Upvotes: 9

Greg Hewgill
Greg Hewgill

Reputation: 992707

XSLT is written in a very functional style, and in this style there is no equivalent of a break statement. What you can do is something like this:

<xsl:for-each select="...nodes...">
    <xsl:if test="...some condition...">
        ...body of loop...
    </xsl:if>
</xsl:for-each>

That way the for-each will still iterate through all the nodes, but the body of the loop will only be executed if the condition is true.

Upvotes: 31

Related Questions