似乎xpath中所有丰富的函数都可以执行“if”。但是,我的引擎一直坚持“没有这样的功能”,我几乎没有在网上找到任何文档(我发现了一些可疑的来源,但他们的语法不起作用)
我需要从字符串的末尾删除':'(如果存在),所以我想这样做:
if (fn:ends-with(//div [@id='head']/text(),': '))
then (fn:substring-before(//div [@id='head']/text(),': ') )
else (//div [@id='head']/text())
有什么建议吗?
答案 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
将是抛出。
最后,您的输出结果为praba
,karan
。
答案 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处理器的类型匹配严格程度,您可能不需要它。