ancestor::foo[bar[@attr="val"]]
我认为这会奏效,但事实并非如此。我需要找到树中具有foo
子元素的最近的bar
元素,该元素的attr
属性为val
。
答案 0 :(得分:33)
这应该有效:
//*[ancestor::foo[bar[@attr="val"]]]
或者
root/foo/bar[ancestor::foo[bar[@attr="val"]]]
匹配第二个<bar>
元素
<root>
<foo>
<bar attr="xxx"></bar>
</foo>
<foo>
<bar attr="val"></bar>
</foo>
<foo>
<bar attr="zzz"></bar>
</foo>
</root>
答案 1 :(得分:11)
已更新,以反映OP预期的解决方案。
请参阅@ David的回答
对于下面的xml示例,
<root>
<foo id="0">
<bar attr="val"/>
<foo id="1">
<bar attr="xxx"/>
</foo>
<foo id="2">
<bar attr="val">
<one>1</one>
<two>
<three>3</three>
</two>
</bar>
</foo>
</foo>
反轴上的有效xpath,其中&lt; 3&gt;作为上下文节点,有效的解决方案是
./ancestor::foo[bar[@attr='val']][position() = 1]
&#34; ./" 是可选的。 position()= 1不是可选的,否则也会返回满足谓词的祖先foo
。
旧答案:忽略
这是一个老问题。但是任何有兴趣的人,以下内容都应该让你了解原始问题的意图。
反转轴
//bar[@attr='val']/ancestor::*[position()=1]
前轴
//*[child::bar[@attr='val']]
答案 2 :(得分:1)
在我看来,最佳答案是由提出问题的人提供的。他的解决方案应该归还所有的祖先。他只想要最近的一个是position()= 1的那个,所以他的xpath表达式需要稍微修改为:
ancestor::foo[bar[@attr="val"] and position() = 1]
如果他写道ancestor::foo[bar[@attr="val"]]
没有返回任何内容,那么他的xml中或者他对XPath评估上下文的当前元素的假设有其他问题。
其他答案(以//开头)并没有真正回答这个问题,即使他们偶然遇到某人的需要,所以他们效率不高: 他们选择xml文件中的所有元素,然后对它们应用过滤器。 虽然我或提出这个问题的人提出的相对xpath只是搜索从当前节点开始到父节点及其父节点等的几个元素 - 即使使用大型XML文件也会非常有效。
答案 3 :(得分:0)
如果您有这样的文件:
<root>
<foo id="0">
<foo id="1">
<bar attr="xxx" />
</foo>
<foo id="2">
<bar attr="val" />
</foo>
<foo id="3">
<tar>
<bar attr="val" />
</tar>
</foo>
</foo>
</root>
,并且您希望foo
节点具有ID 2
和3
,即与其具有foos
的{{1}}后代最接近的bar
,以下作品:
attr=val
如果省略//foo[descendant::bar[@attr="val"] and not(descendant::foo)]
,则另外获得and not(descendant::foo)
,其ID为foo
。
在我的示例一般情况下,其他答案对我不起作用。
您可以使用以下命令在Python中进行测试:
0
打印:
from lxml import etree
tree = etree.parse('example.xml')
foos = tree.xpath('//foo[descendant::bar[@attr="val"] and not(descendant::foo)]')
for foo in foos:
print(foo.attrib)
请注意,使用的xpath效率不高。我想学习一种更有效的方法。