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

Yos*_*ale 42 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())
Run Code Online (Sandbox Code Playgroud)

有什么建议?

Tom*_*lak 62

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

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

这取决于两个互斥字符串的串联,如果条件为false(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]更具防御性.


Nol*_*rin 23

W3.org上XPath 2.0的官方语言规范详细说明了该语言确实支持if语句.特别参见第3.8节"条件表达式".除了语法格式和解释,它还给出了以下示例:

if ($widget1/unit-cost < $widget2/unit-cost) 
  then $widget1
  else $widget2
Run Code Online (Sandbox Code Playgroud)

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

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

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

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