Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.5k views
in Technique[技术] by (71.8m points)

xml - How to break out of xsl:for-each loop in XSLT?

I understand that XSLT doesn't allow one to directly break out of a xsl:for-each loop, but there must be an easy way to add more conditions to achieve it. I've seen much online on the same context but unable to proceed further.

I want to iterate through a set of XML tags and come out of the iteration on finding a value in one XML tag and use that value in another xsl:template. For example,

<xsl:template name="categoryCheckTemplate">
 <xsl:for-each select="TEST/ABC/DEF/GHI/Row">
    <xsl:variable name="category">
        <xsl:choose>
            <xsl:when test="JKL/Category">
                <xsl:value-of select="JKL/Category"/>                           
            </xsl:when>
            <xsl:when test="MNO/Category">
                <xsl:value-of select="MNO/Category"/>                           
            </xsl:when>
        </xsl:choose>
    </xsl:variable>
    <xsl:choose>
        <xsl:when test="(contains($category,'123'))">
            <xsl:value-of select="'true'"/>    
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="'false'"/>
        </xsl:otherwise>
    </xsl:choose>
 </xsl:for-each>
</xsl:template>

I want to use the 'true' value of this template in another template but don't want to iterate it all the way. Anytime it is true, I need to come out of the iteration.

XML Input

<xml>
    <TEST>
        <ABC>
            <DEF>
                <GHI>
                    <Row>
                        <JKL>
                            <Category>123</Category>
                        </JKL>
                    </Row>
                    <Row>
                        <JKL>
                            <Category>456</Category>
                        </JKL>
                    </Row>
                    <Row>
                        <JKL>
                            <Category>789</Category>
                        </JKL>
                    </Row>
                    <Row>
                        <JKL>
                            <Category>012</Category>
                        </JKL>
                    </Row>
                </GHI>
            </DEF>
        </ABC>
    </TEST>
</xml>

Desired Output

<item>
    <cat>123</cat>
</item>

Can anyone help on this XSLT 1.0?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You're thinking too procedurally. You don't need to break; you don't even need to loop.

Your entire procedure can and should be reduced to a single XPath expression:

string(contains(TEST/ABC/DEF/GHI/Row/*[self::JKL or self::MNO]/Category, '123'))

That's it. No loop. No break. Just tests against the input XML and an optional conversion to string (which may or may not be necessary in your actual context).


Update after OP added input XML and desired output XML:

This XSLT,

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <item>
      <xsl:if test="/xml/TEST/ABC/DEF/GHI/Row/
                    *[self::JKL or self::MNO]/Category = 123">
        <cat>123</cat>
      </xsl:if>
    </item>
  </xsl:template>
</xsl:stylesheet>

will produce the requested output XML,

<item>
   <cat>123</cat>
</item>

if the original procedurally specified condition is true1, or this output XML,

<item/>

otherwise.


1 I took the liberty of also switching from a string contains test to a string value equality test, which is more likely what's desired here (else "1234" et al would also satisfy the test).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...