XPath中是否有“if -then - else”语句?

时间:2009-06-09 16:13:18

标签: xpath if-statement

似乎xpath中所有丰富的函数都可以执行“if”。但是,我的引擎一直坚持“没有这样的功能”,我几乎没有在网上找到任何文档(我发现了一些可疑的来源,但他们的语法不起作用)

我需要从字符串的末尾删除':'(如果存在),所以我想这样做:

if (fn:ends-with(//div [@id='head']/text(),': '))
            then (fn:substring-before(//div [@id='head']/text(),': ') )
            else (//div [@id='head']/text())

有什么建议吗?

7 个答案:

答案 0 :(得分:59)

是的,有一种方法可以在XPath 1.0中实现:

concat(
  substring($s1, 1, number($condition)      * string-length($s1)),
  substring($s2, 1, number(not($condition)) * string-length($s2))
)

这取决于两个互斥字符串的串联,如果条件为假(0 * string-length(...)),则第一个为空,如果条件为真,则第二个为空。这被称为“Becker的方法”,归因于Oliver Becker

在你的情况下:

concat(
  substring(
    substring-before(//div[@id='head']/text(), ': '),
    1, 
    number(
      ends-with(//div[@id='head']/text(), ': ')
    )
    * string-length(substring-before(//div [@id='head']/text(), ': '))
  ),
  substring(
    //div[@id='head']/text(), 
    1, 
    number(not(
      ends-with(//div[@id='head']/text(), ': ')
    ))
    * string-length(//div[@id='head']/text())
  )
)

虽然我会尝试摆脱之前的所有"//"

此外,//div[@id='head']可能会返回多个节点 请注意这一点 - 使用//div[@id='head'][1]更具防御性。

答案 1 :(得分:21)

W3.org上XPath 2.0的官方语言规范详细说明了语言确实支持if语句。特别参见Section 3.8 Conditional Expressions。除语法格式和说​​明外,还给出了以下示例:

if ($widget1/unit-cost < $widget2/unit-cost) 
  then $widget1
  else $widget2

这表明你不应该有你的表达式的括号(否则语法看起来是正确的)。我并不完全自信,但这肯定值得一试。因此,您需要将查询更改为:

if (fn:ends-with(//div [@id='head']/text(),': '))
  then fn:substring-before(//div [@id='head']/text(),': ')
  else //div [@id='head']/text()

我强烈怀疑这可能会解决它,因为你的XPath引擎似乎试图将if解释为一个函数,它实际上是一种特殊的语言结构。

最后,要指出显而易见的,确保您的XPath引擎确实支持XPath 2.0(而不是早期版本)!我不相信条件表达式是以前版本的XPath的一部分。

答案 2 :(得分:3)

根据pkarat的规定,你可以在版本1.0中实现条件XPath。

对于您的情况,请遵循以下概念:

concat(substring-before(your-xpath[contains(.,':')],':'),your-xpath[not(contains(.,':'))])

这肯定会奏效。看看它怎么运作。提供两个输入

praba:
karan

对于第一个输入:它包含:因此条件为true,:之前的字符串将是输出,说praba是您的输出。第二个条件是假的,所以没有问题。

对于第二个输入:它不包含:因此条件失败,进入第二个条件字符串不包含:所以条件为真...因此输出karan将是抛出。

最后,您的输出结果为prabakaran

答案 3 :(得分:3)

就个人而言,我会使用XSLT转换XML并删除尾随冒号。例如,假设我有这个输入:

<?xml version="1.0" encoding="UTF-8"?>
<Document>
    <Paragraph>This paragraph ends in a period.</Paragraph>
    <Paragraph>This one ends in a colon:</Paragraph>
    <Paragraph>This one has a : in the middle.</Paragraph>
</Document>

如果我想删除段落中的尾随冒号,我会使用这个XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions"
    version="2.0">
    <!-- identity -->
    <xsl:template match="/|@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- strip out colons at the end of paragraphs -->
    <xsl:template match="Paragraph">
        <xsl:choose>
            <!-- if it ends with a : -->
            <xsl:when test="fn:ends-with(.,':')">
                <xsl:copy>
                    <!-- copy everything but the last character -->
                    <xsl:value-of select="substring(., 1, string-length(.)-1)"></xsl:value-of>
                </xsl:copy>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:apply-templates/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet> 

答案 4 :(得分:1)

如何使用fn:replace(string,pattern,replace)呢?

XPATH经常在XSLT中使用,如果您处于这种情况并且没有XPATH 2.0,则可以使用:

  <xsl:choose>
    <xsl:when test="condition1">
      condition1-statements
    </xsl:when>
    <xsl:when test="condition2">
      condition2-statements
    </xsl:when>
    <xsl:otherwise>
      otherwise-statements
    </xsl:otherwise>
  </xsl:choose>

答案 5 :(得分:1)

不幸的是,以前的答案对我来说都没有选择,所以我研究了一段时间并找到了这个解决方案:

http://blog.alessio.marchetti.name/post/2011/02/12/the-Oliver-Becker-s-XPath-method

如果某个节点存在,我用它来输出文本。 4是文本foo的长度。所以我想更优雅的解决方案是使用变量。

substring('foo',number(not(normalize-space(/elements/the/element/)))*4)

答案 6 :(得分:0)

更简单的XPath 1.0解决方案,改编自Tomalek(在此处发布)和Dimitre(here):

concat(substring($s1, 1 div number($cond)), substring($s2, 1 div number(not($cond))))

注意:我发现将bool转换为int需要显式数字(),否则某些XPath求值程序会抛出类型不匹配错误。根据XPath处理器的类型匹配严格程度,您可能不需要它。