假设我有:
<A>
<B>C</B>
<D>E</D>
</A>
然后我可以输出B元素(包括标签):
//B
将返回
<B>C</B>
但为什么谓词中不需要text()?以下两行给出相同的输出:
/A[B = 'C']/D
/A[B/text() = 'C']/D
如果XPATH是干净的构造我会期望它(或在某种其他元素结构中):
/A[B = <B>C></B>]/D
和
/A[B/text()='C']/D
有人可以给我一个理由,为什么输出需要text(),但谓词不需要它?
答案 0 :(得分:7)
我认为这是一个合理而自然的问题。我宁愿看到人们提出像这样的概念性问题来理解XPath是如何工作的,而不是解决对XPath的浅层理解,最后问一些浅薄的问题,为什么他们的XPath表达式没有做到他们在从数据库中抓取数据时的预期。某个网页。
让我们首先澄清一些条款。通过&#34;输出&#34;,我假设你的意思与&#34;返回&#34;:XPath表达式选择的值相同。 (XPath本身没有直接输出功能。) 通过&#34;干净的构造&#34;我会假设你的意思是简单而一致的设计。&#34;
简短的回答是XPath是一致的,但是像大多数灵活而强大的工具一样,它并不简单。
接下来,我们可能需要询问您正在考虑哪个版本的XPath。版本1,2和3之间存在很大差异。我将重点关注XPath 1.0,因为它是最知名且广泛实现的,我也不知道2.0或3.0。
B
在谓词中是否与谓词相同。在//B
和/A[B = 'C']
中,它都是node test。它匹配(选择)名为B
的元素节点。 XPath对标签一无所知。它在抽象树文档模型上运行。 XPath表达式可以选择元素和其他节点,但不能选择标记。
所以我认为你的问题会减少,为什么/A[B = 'C']/D
成功选择你提供的XML示例中的D
元素,当B
选择一个元素而不仅仅是文本时'C'
?为了进一步减少它,当B = 'C'
是一个元素而不仅仅是一个包含{{1}的文本节点时,为什么A
评估为 true 为元素B
}?
答案是when performing comparisons,例如'C'
,
如果要比较的一个对象是节点集而另一个是字符串, 那么当且仅当有一个节点时,比较才会成立 node-set使得执行比较的结果 节点的字符串值,另一个字符串为true [强调添加]。
换句话说,如果=
有多个名为B
的子元素,则子表达式/A
可以在此处选择多个元素节点。 (在这种情况下,只有一个这样的子元素。)要评估表达式B
,XPath会查看由B = 'C'
选择的每个节点的字符串值。 According to the docs,
元素节点的字符串值是文档顺序中元素节点的所有文本节点后代的字符串值的串联。
在这种情况下,B
元素节点的唯一文本节点后代是字符串值为B
的文本节点。因此,'C'
的字符串值为B
,因此对于元素'C'
,谓词[B = 'C']
为真。
为什么XPath以这种方式定义元素节点的字符串值?我猜它的部分原因是单文本节点的方便性,但是当涉及到自由格式的标记文本时,比如
/A
为了某些目的,你有时想忽略它的标记,快速检索所有后代文本节点的连接可能非常方便。
你问题的另一部分是,为什么你不会写
<p>HTML that <em>could</em> have <b>arbitrary <tt>nesting</tt></b></p>
或
/A[B = <B>C</B>]/D
第二个答案最短:你可以。它不太方便,功能也不那么强大,但更加明确和准确。它不会一直给你相同的结果,因为这个版本不会询问/A[B/text()='C']/D
的字符串值;它询问(任何)B
是否有任何文本节点子项,其值为B
,而不是询问是否有任何'C'
具有串联的所有产生B
的后代文本节点。
至于'C'
,XPath(至少1.0)并未设计用于创建新节点的语法,例如/A[B = <B>C</B>]/D
。但即使它是,<B>C</B>
意味着什么?你显然不是要求进行身份比较,而是要求一种结构等价。 XPath定义器必须创建比较语义,其中两个节点集之间或节点集和新定义类型(例如&#34;结构模板&#34;)之间的比较为真,当且仅当(如果)例如,在(第一)节点集中存在递归地匹配结构模板的结构或第二节点集中的节点的节点。但是they defined it as follows,
如果要比较的两个对象都是节点集,那么当且仅当第一个节点集中有一个节点而第二个节点集中有一个节点时才进行比较,以便执行两个节点的字符串值的比较是真的。
鉴于他们只能选择两个定义中的一个来比较节点集,为什么他们选择后者而不是你期望的定义呢?我不知道XPath委员会的会议记录,但我怀疑它归结为后者的定义更符合他们分析的最常见的用例,同时还考虑了性能和实现的简单性。
我同意这个定义不是定义B = <B>C</B>
比较最明显的方法。但我认为设计人员是对的,比较整个节点树结构并不是一个非常常见的用例,而常见的用例(例如你提供的用例)则被XPath提供的工具很好地覆盖。例如,在XPath中非常简单地询问是否存在=
元素是根节点的子元素,该元素具有子A
元素,其文本值(忽略全部)当前的子标记)是B
。