XPath查找最近的祖先元素,该元素包含具有特定值属性的元素

XPath查找最近的祖先元素,该元素包含具有特定值属性的元素,xpath,Xpath,祖先::foo[bar[@attr=“val”]] 我原以为这样行得通,但事实并非如此。我需要在树中找到最近的foo元素,该元素具有bar子元素,而子元素又具有attr属性val,这应该可以: //*[ancestor::foo[bar[@attr="val"]]] 或者 root/foo/bar[ancestor::foo[bar[@attr="val"]]] 匹配第二个元素 <root> <foo> <bar attr="xxx"&g

祖先::foo[bar[@attr=“val”]]

我原以为这样行得通,但事实并非如此。我需要在树中找到最近的
foo
元素,该元素具有
bar
子元素,而子元素又具有
attr
属性
val
,这应该可以:

//*[ancestor::foo[bar[@attr="val"]]]
或者

root/foo/bar[ancestor::foo[bar[@attr="val"]]]
匹配第二个
元素

<root>
    <foo>
        <bar attr="xxx"></bar>
    </foo>
    <foo>
        <bar attr="val"></bar>
    </foo>
    <foo>
        <bar attr="zzz"></bar>
    </foo>
</root>

更新以反映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>
“/”是可选的。position()=1不是可选的,否则满足谓词的祖先
foo
也将返回

旧答案:忽略

这是一个老问题。但是,任何感兴趣的人,下面都应该了解原始问题的意图

反向轴

//bar[@attr='val']/ancestor::*[position()=1]
前进轴

//*[child::bar[@attr='val']]

在我看来,提出问题的人提供了最好的答案。他的解决方案应该是归还所有祖先的食物。他只需要最接近的一个,即position()=1的表达式,因此他的xpath表达式需要稍微修改为:

ancestor::foo[bar[@attr="val"] and position() = 1]
如果他写到
祖先::foo[bar[@attr=“val”]]
没有返回任何内容,那么他在xml中或者在关于XPath计算上下文的当前元素的假设中还有其他问题

其他答案(以//)开头)并不能真正回答问题,即使它们碰巧满足了某人的需要,也没有效率: 他们选择xml文件中的所有元素,然后对它们应用过滤器。
而我或问这个问题的人提出的相对xpath只需搜索从当前节点到父节点及其父节点等的几个元素,即使是大型XML文件,也会非常有效。

如果您有这样的文件:

<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为
0
foo

在我的例子的一般情况下,其他答案不适用于我

您可以使用以下方法在Python中对其进行测试:

从lxml导入etree
tree=etree.parse('example.xml')
foos=tree.xpath('//foo[genderant::bar[@attr=“val”]和not(genderant::foo)])
对于foos中的foo:
打印(foo.attrib)
其中打印:

{'id': '2'}
{'id': '3'}

请注意,使用的xpath效率不高。我很想学一门效率更高的。

没什么。它与我描述的元素不匹配。该表达式是否有效?请提供此“无效”的(最小)XML文档。我们只知道你“把手放在袋子里,却找不到你想要的东西”,但我们不知道“袋子里有什么”:(虽然这是一个公平的请求,但我100%肯定它应该对我的XML起作用。大多数情况下,我只是想找人指出我表情中的一个明显缺陷。在任何地方都很难找到丰富的XPath示例,特别是在树中向上移动而不是向下移动,所以我只是想知道我在这里是否做错了什么。@corexi您所要做的就是给出一个xml示例,以及您所期望的,对我们来说,看一看这个问题会容易得多。这是否真的回答了这个问题?OP想要选择祖先(foo)。。本例选择祖先符合某些条件的后代(条形图)。这并不能回答问题。不知道为什么它会被投票支持。@geoidesic因为它显然解决了老年退休金计划的问题,“祖先”的反面是“后代”,而不是“孩子”。“child”是“parent”的反面,而不是“祖先”@wybe我想你把xpath轴的方向和轴的反义词混淆了。在上下文节点之后按文档顺序查找节点的任何轴都是向前轴。在上下文节点之前按文档顺序查找节点的轴是反向轴。如果这不符合您的意图,请您提供您真正的意思。@wybe参考第2.4节谓词,我的意思是“祖先的对立面是后代”,如“父母的对立面是孩子的孩子”。同样,“直接父母”的另一个方向是“直接子女”。谢谢你清理这个up@wybe我同意你的发言,但对该发言的背景感到困惑。孩子、后代、跟随兄弟姐妹、跟随、后代或自我都是前进轴。我同意你的评估。我的回答自上而下地解决了这个问题,而不是从上下文节点解决它。我将更新我的答案以反映这一点。谢谢
//foo[descendant::bar[@attr="val"] and not(descendant::foo)]
{'id': '2'}
{'id': '3'}