为什么XPath CONTAINS(text(),';substring';)不能按预期工作?
假设我有一段HTML,如下所示:
<a>Ask Question<other/>more text</a>
我可以匹配这段XPath:
//a[text() = 'Ask Question']
或.
//a[text() = 'more text']
或者我可以使用点来匹配整个内容:
//a[. = 'Ask Questionmore text']
This post描述了.
(点)和text()
之间的区别,但简而言之,第一个返回单个元素,而后者返回一个元素列表。但这就是我觉得有点奇怪的地方。因为text()
可以用来匹配列表中的任何一个元素,但是对于XPath函数contains()
就不是这样了。如果我这样做:
//a[contains(text(), 'Ask Question')]
.我收到以下错误:
错误:CONTAINS()的第一个参数要求的基数为1或0
使用完全匹配(等于)时text()
如何起作用,但在部分匹配(包含)时不起作用?
解决方案
对于此标记,
<a>Ask Question<other/>more text</a>
请注意,a
元素有一个文本节点子元素("Ask Question"
)、一个空元素子元素(other
)和第二个文本节点子元素("more text"
)。
下面是如何根据标记对//a[contains(text(),'Ask Question')]
求值时所发生情况进行推理:
contains(x,y)
预期x
为字符串,但text()
匹配两个文本节点。- 在XPath 1.0中,将多个节点转换为字符串的规则为this:
通过返回的string-value将节点集转换为字符串 节点集中在document order中的第一个节点。如果 节点集为空,则返回空字符串。[已添加强调]
- 在XPath 2.0+中,向需要字符串的函数提供文本节点序列是错误的,因此
contains(text(),'substr')
将导致多个匹配的文本节点出错。
在您的情况下.
XPath 1.0会将
contains(text(),'Ask Question')
视为contains('Ask Question','Ask Question')
,即
true
。另一方面,请务必注意,在XPath 1.0中,contains(text(),'more text')
的计算结果将为false
。如果不知道上面的(1)-(3),这可能是违反直觉的。XPath 2.0会将其视为错误。
更好的替代方案
如果目标是查找字符串值包含子字符串的所有
a
元素,"Ask Question"
://a[contains(.,'Ask Question')]
这是最常见的要求。
如果目标是查找直接文本节点子级等于
"Ask Question"
的所有a
元素://a[text()='Ask Question']
当希望从
),这会很有用a
中的后代元素中排除字符串时(例如,如果您想要a
,<a>Ask Question<other/>more text</a>
但不是这个
a
:<a>more text before <not>Ask Question</not> more text after</a>
另请参阅
- How
contains()
handles a nodeset first arg - How to use XPath contains() for specific text?
- Testing text() nodes vs string values in XPath
相关文章