我有XML文档,如:
<rootelement>
<myelement>test1</myelement>
<myelement>test2</myelement>
<myelement type='specific'>test3</myelement>
</rootelement>
我想检索特定的myelement
,如果它不存在,然后第一个。所以我写道:
/rootelement/myelement[@type='specific' or position()=1]
关于'或表达'的XPath spec状态:
如果是,则不评估右操作数 左操作数计算结果为真
问题是libxml2-2.6.26似乎应用了两个表达式的并集,返回“2节点集”(例如使用xmllint --shell
)。
是libxml2还是我做错了什么?
答案 0 :(得分:10)
简短回答:你的选择器不能表达你的想法。
or
运算符 是一个联盟。
您引用的规范部分(“右侧操作数未评估...”)是标准boolean logic short circuiting的一部分。
这就是为什么你为你的示例输入获得一个2节点集的原因:XPath查看myelement
的每个rootelement
,并将[@type='specific' or position()=1]
部分应用于每个这样的节点确定它是否与选择器匹配。
<myelement>test1</myelement>
与@type='specific'
不匹配,但它与position()=1
匹配,因此它与整个选择器匹配。<myelement>test2</myelement>
与@type='specific'
不匹配,且与position()=1
不匹配,因此与整个选择器不匹配。<myelement type='specific'>test3</myelement>
匹配@type='specific'
(因此XPath不必测试其位置 - 这是短路部分),因此它匹配整个选择器。第一个和最后一个<myelement>
匹配整个选择器,因此返回一个2节点集。
以您希望的方式选择元素的最简单方法是分两步完成。这是伪代码(我不知道你实际使用XPath的上下文,我对编写XPath语法选择器并不熟悉):
elements
/rootelement/myelement[@type='specific']
elements
为空,请选择与elements
/rootelement/myelement[position()=1]
醇>
答案 1 :(得分:7)
@Matt Ball很好地解释了你的问题的原因。
这是一个XPath单线选择你想要的:
/*/myelement[@type='specific'] | /*[not(myelement[@type='specific'])]/myelement[1]