2011-06-07 73 views
0

我无法显示第一个匹配值,如找到第一个匹配时,打破每个循环的XSLT

<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

您的问题中仍然存在相当多的拼写错误,您可能需要解决此问题。 – LarsH 2011-06-07 21:25:40

+1

'xpath'有一些我没有听说过的特殊价值吗?似乎有很多“坏xslt mojo”在这里进行。谨慎处理.... – 2011-06-07 21:28:47

+0

@Abe:很好的问题。不,它不是一个特殊的关键字或任何东西。在这里它将被解释为一个子元素的名称 - 其中没有。我想知道OP的含义。 – LarsH 2011-06-07 21:32:28

回答

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>循环中,循环的“第一个”实例化(根据文档顺序或排序顺序)并不一定在“最后”实例化之前的时间顺序上进行评估。他们可能会以任何顺序或平行进行评估,因为他们不相互依赖。因此,试图“跳出循环”,意图导致循环的“后续”实例化不能被评估,如果这样做,后来的实例化的结果将依赖于较早的实例化,并行评估将被排除。

+0

好dec! – 2011-06-07 21:51:07

+1

您的表达式在每个“test”节点中选择第一个匹配的“p”节点。如果有多个'test'节点,则表达式可能会返回多个'p'节点。为了确保您最多只能获得一个节点,您需要编写'(*/*/test/p [string-length()> 2并包含(。,'30')])[1]'。 – markusk 2011-06-07 22:46:22

+0

@markusk:你有一个好点。我的问题是,我还不清楚OP是否希望每个测试节点有一个匹配的'p'节点,或者整个匹配'p'。但我认为你的解释是对的。我会改变我的答案。 @Newbie – LarsH 2011-06-08 14:34:05