找到第一个匹配时,打破每个循环的XSLT

时间:2011-06-07 21:17:08

标签: xslt foreach

我无法显示第一个匹配值,例如

<test>
    <p>30</p>
    <p>30{1{{23{45<p>
    <p>23{34</p>
    <p>30{1{98</p>
</test>
<test2>
    <p1>text</p1>
</test2>

所以我想循环遍历<test></test>并找到字符串长度大于2且包含30的<p>节点的值。我只想要第一个值。  所以我厌倦了以下代码

<xsl:variable name="var_test">
    <xsl:for-each select="*/*/test()>
        <xsl:if string-length(p/text())>2 and contains(p/text(),'30'))
    <xsl:value-of select="xpath">
</xsl:variable>

问题是var_test始终为null。

如果我直接尝试输出任何变量

<xsl:for-each select="*/*/test()>
    <xsl:if string-length(p/text())>2 and contains(p/text(),'30'))
<xsl:value-of select="xpath">

我收到以下输出

<p>30{1{23{4530{1{98</p>

但所需的输出是

<p>0{1{23{45</p>

所以我怎么能实现这个目标呢?

1 个答案:

答案 0 :(得分:3)

使用

而不是for-each
<xsl:copy-of select="(*/*/test/p[string-length() > 2 and
                                 contains(.,'30'))] )[1]" />

[1]仅选择第一个匹配的<p>。 (更新:我更改了上面的XPath以回应@ markusk的评论。)

上面将输出<p>元素及其文本内容,如“所需输出”中所示。如果您实际只想要<p>的值,即其文字内容,请使用<xsl:value-of>代替<xsl:copy-of>

<强>附录:

打破循环的想法不适用于XSLT,因为它不是一种过程语言。在<xsl:for-each>循环中,循环的“第一”实例化(以文档顺序或排序顺序说话)不一定在“最后”实例化之前按时间顺序评估。它们可以以任何顺序或并行地进行评估,因为它们不相互依赖。因此,试图“突破循环”(旨在导致循环的“后续”实例化不被评估)是行不通的:如果确实如此,后续实例化的结果将依赖于早期实例化和并行评估将被排除在外。