XPath:从子节点获取父节点

270

我需要获取子节点title 50的父节点。

目前我仅在使用:

//*[title="50"]

我该如何获取它的父节点? 结果应该是store节点。


<?xml version="1.0" encoding="utf-8"?>
<d:data xmlns:d="defiant-namespace" d:mi="23">
    <store d:mi="22">
        <book price="12.99" d:price="Number" d:mi="4">
            <title d:constr="String" d:mi="1">Sword of Honour</title>
            <category d:constr="String" d:mi="2">fiction</category>
            <author d:constr="String" d:mi="3">Evelyn Waugh</author>
        </book>
        <book price="8.99" d:price="Number" d:mi="9">
            <title d:constr="String" d:mi="5">Moby Dick</title>
            <category d:constr="String" d:mi="6">fiction</category>
            <author d:constr="String" d:mi="7">Herman Melville</author>
            <isbn d:constr="String" d:mi="8">0-553-21311-3</isbn>
        </book>
        <book price="8.95" d:price="Number" d:mi="13">
            <title d:constr="String" d:mi="10">50</title>
            <category d:constr="String" d:mi="11">reference</category>
            <author d:constr="String" d:mi="12">Nigel Rees</author>
        </book>
        <book price="22.99" d:price="Number" d:mi="18">
            <title d:constr="String" d:mi="14">The Lord of the Rings</title>
            <category d:constr="String" d:mi="15">fiction</category>
            <author d:constr="String" d:mi="16">J. R. R. Tolkien</author>
            <isbn d:constr="String" d:mi="17">0-395-19395-8</isbn>
        </book>
        <bicycle price="19.95" d:price="Number" d:mi="21">
            <brand d:constr="String" d:mi="19">Cannondale</brand>
            <color d:constr="String" d:mi="20">red</color>
        </bicycle>
    </store>
</d:data>

XPATH/..XPATH/parent::* 会选择由 XPATH 选择的节点的父节点,但通常直接选择父节点而不先下降到其子节点会更好。请参见下方链接:https://stackoverflow.com/a/58065057/290085。 - undefined
5个回答

467

使用parent和父节点名称。

//*[title="50"]/parent::store

如果父节点是一个store,那么这个XPath将仅选择它。

但你也可以使用其中之一。

//*[title="50"]/parent::*
//*[title="50"]/..

这些XPath将选择任何父节点。因此,如果文档发生更改,您将始终选择一个节点,即使它不是您期望的节点。

编辑

在给定的示例中,如果父级是自行车而父级的父级是商店会发生什么?

它会向上移动吗?

不会,它只会选择作为匹配//*[title="50"]的节点的父节点的商店。

如果不行,在这种情况下是否有提升的方法并返回无父项时为空?

是的,您可以使用ancestor轴。

//*[title="50"]/ancestor::store

这将选择与//*[title="50"]匹配的节点的所有祖先节点,这些祖先节点是“stores”。例如:

<data xmlns:d="defiant-namespace" d:mi="23">
    <store mi="1">
        <store mi="22">
            <book price="8.95" d:price="Number" d:mi="13">
                <title d:constr="String" d:mi="10">50</title>
                <category d:constr="String" d:mi="11">reference</category>
                <author d:constr="String" d:mi="12">Nigel Rees</author>
            </book>
        </store>
    </store>
</data>

XPath选择结果


9
你也可以使用缩写语法 parent::* 的简写 ..(例如://*[title="50"]/..)或者嵌套谓词语法(例如://*[*[title="50"]])。 - Daniel Haley
1
附加信息:http://www.w3.org/TR/xpath/#axes 和 http://www.w3.org/TR/xpath/#path-abbrev - Daniel Haley
3
或者使用 parent::node() 作为 .. 的简写,我认为这更好。实际上,parent::* 只适用于轴的主节点类型,在大多数情况下这不是问题。 - Ludovic Kuty
5
如果你正在使用,尝试使用.xpath('..')xpath('parent::node()') - briankip
1
这个XPath只会选择父节点,如果它是一个商店。在给定的例子中,如果父节点是“自行车”,但父节点的父节点是“商店”,那么会上升吗?如果不是,是否有一种方法可以在这种情况下上升并返回“None”,如果没有这样的父节点? - Martin Thoma
显示剩余2条评论

50

正如一个替代方案,你可以使用ancestor

//*[title="50"]/ancestor::store

它比 parent 更强大,因为它可以获取父级、祖父级甚至曾祖父级别的元素


28
它并不是“更强大”,它只是不同而已。因此,轴线的选择取决于使用情况。 - Ludovic Kuty
@LudovicKuty 它更加“灵活”,现在你“满意”了吗? - Robert Sinclair
2
不,这是错误的。从 OP 的 XPath 来看,他要求的是父级,而不是祖先级。 - Nakilon
2
这个回答虽然不完全正确,但对于许多人可能会搜索“parent”时实际上是指“任何父级”,它仍然是有帮助的。我认为这是一个合适的答案。 - Silidrone

24

针对一个经常被问到的旧问题,这是一个新而改进的答案...

我该如何获取它的父节点?结果应该是store节点。

使用谓词而不是parent::ancestor::

大多数答案在选择title后向上遍历到目标父元素或祖先(store)元素。一个更简单、直接的方法是直接选择父元素或祖先元素,从而省略了遍历到parent::ancestor::轴的需要:

//*[book/title = "50"]

如果干预的元素名称不同:

//*[*/title = "50"]

或者,用名称和深度表示:

//*[.//title = "50"]

19

你也可以在表达式结尾使用两个点。例如:

//*[title="50"]/..

0
    //store[book[title[text()="50"]]]

或者

    //store[*[title[text()="50"]]]

你为什么更喜欢这个选项而不是其他选项?特别是被450名社区成员验证过的那个被接受的答案,其中包括了详细的解释。请修改你的回答以帮助解释这种方法的好处,特别是与先前已建立的提议相比较。 - Jeremy Caney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接