How to break XSLT for-each loop?

2019-07-27 05:26发布

问题:

I know break is not possible in XSLT for-each loop. But from following example, If I want to show 'something' element exist or not. Then I will go through loop and once I got it I want to break loop.

  1. I will make one bool variable say isExist=false;
  2. I will go through all nodes one by one.
  3. Once I got 'something', I will change its value to isExist=true
  4. want to break loop here.

Now I want to break loop bcoz I want to show status as true or false. But If I will not use break after step 3, it will go to loop and make change it to false and I will get status as false.

My question is: If break not possible then How to achieve this result?

I am following this link How to interrupt an XSLT for-each loop for not contiguos elements?

According to this link I will get first two occurrence but it doen't say 'something' exist or not.

<root>
  <item/>
  <item/>
  <something/>
  <item/>
</root>

回答1:

That's not how variables work in XSLT - variables are always lexically scoped to their containing element, and once set they cannot be changed.

You need to learn to think more declaratively rather than procedurally - tell the processor what you want it to find rather than how you would look for it. The XPath expression boolean(/root/something) will give you what you want - true if there is a something element as a child of the root and false otherwise.



回答2:

If all you're after is whether <something/> exists or not, you could also just check using

<xsl:if test="/root/something">
    // do fancy stuff...
</xsl:if>


回答3:

When you write a XSLT template that matches an element selector, for example:

<xsl:template match="entry"> .... </entry>

and you have a XML file like this one:

<entries>
    <entry number="345" type="A"/>
    <entry number="123" type="B"/>
    <entry number="334" type="A"/>
    <entry number="322" type="C"/>
</entries>

The XSLT template will be processed for all entry elements. So most of the time, you never need to use a for-each in XSLT. In the above example, the template will be processed 4 times, since there are 4 entry elements to match. Inside each one you can extract or print the data that's available in that context (such as the attributes, in this example).

You can usually also perform many conditional expressions without ever using an <xsl:if> or <xsl:choose>, by restricting what you need via XPath predicates.

If you add another template for the entry elements with a predicate like this:

<xsl:template match="entry[@type='A']"> .... </entry>

then it will override the entry templates for the entry elements that have a type attribute with the value A. The others will be processed by the template that has no predicate.

Giving preference to these tools, instead of for-each, if and choose, will help you think in a more functional oriented way and understand how to use XSLT better.

Since variables and params can't be changed, you can't use a regular for-loop to increment or decrement it, but in case you need one, it is possible to write a for loop that increments a variable in XSLT 1.0, but it has to be done recursively (using xsl:call-template). In this strategy, you don't assign a different value to a variable, but perform an operation inside a variable block which will set the final value for that variable.

See, for example, this stylesheet which calculates a factorial of a number. The param n in each recursion has a final value which doesn't change but is used as the data for another n param in the next recursion:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>

    <xsl:param name="number">5</xsl:param>

    <xsl:template match="/">
        <xsl:variable name="fac">
            <xsl:call-template name="factorial">
                <xsl:with-param name="n" select="$number"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:value-of select="$fac"/>
    </xsl:template>

    <xsl:template name="factorial">
        <xsl:param name="n"/>
        <xsl:choose>
            <xsl:when test="$n &gt; 1">
                <xsl:call-template name="factorial">
                    <xsl:with-param name="n-1"/>
                </xsl:call-template>
                <xsl:value-of select="$n * $n - 1"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="1"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>


标签: xslt xslt-1.0