48

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

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

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

有什么建议吗?

4

7 回答 7

65

是的,在 XPath 1.0 中有一种方法可以做到这一点:

连接(
  substring($s1, 1, number($condition) * 字符串长度($s1)),
  substring($s2, 1, number(not($condition)) * 字符串长度($s2))
)

这依赖于两个互斥字符串的连接,如果条件为假 ( 0 * string-length(...)),第一个为空,如果条件为真,第二个为空。这被称为“Becker 方法”,归功于Oliver Becker (原始链接现已失效,网络存档有副本

在你的情况下:

连接(
  子串(
    substring-before(//div[@id='head']/text(), ':'),
    1、
    数字(
      以(//div[@id='head']/text(), ':') 结尾
    )
    * string-length(substring-before(//div [@id='head']/text(), ':'))
  ),
  子串(
    //div[@id='head']/text(),
    1、
    数(不是(
      以(//div[@id='head']/text(), ':') 结尾
    ))
    * string-length(//div[@id='head']/text())
  )
)

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

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

于 2009-06-09T18:14:54.833 回答
26

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

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 的一部分。

于 2009-06-09T16:28:35.080 回答
4

根据 pkarat 的法律,您可以在 1.0 版中实现条件 XPath。

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

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

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

praba:
karan

对于第一个输入:它包含:条件为真,之前的字符串: 将是输出,比如说praba是你的输出。第二个条件将是错误的,所以没有问题。

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

最后你的输出将是praba, karan

于 2010-11-16T03:07:33.713 回答
3

如何使用 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>
于 2009-06-09T16:24:16.513 回答
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> 
于 2011-02-18T20:02:16.873 回答
2

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

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)
于 2013-03-15T13:41:31.537 回答
0

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

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

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

于 2017-10-06T02:08:48.387 回答