ChatGPT解决这个技术问题 Extra ChatGPT

XPath: Get parent node from child node

I need get the parent node for child node title 50

At the moment I am using only

//*[title="50"]

How could I get its parent? Result should be the store node.

<?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>

R
René Link

Use the parent axes with the parent node's name.

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

This XPath will only select the parent node if it is a store.

But you can also use one of these

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

These xpaths will select any parent node. So if the document changes you will always select a node, even if it is not the node you expect.

EDIT

What happens in the given example where the parent is a bicycle but the parent of the parent is a store? Does it ascent?

No, it only selects the store if it is a parent of the node that matches //*[title="50"].

If not, is there a method to ascent in such cases and return None if there is no such parent?

Yes, you can use ancestor axes

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

This will select all ancestors of the node matching //*[title="50"] that are ` stores. E.g.

<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>

https://i.stack.imgur.com/uzcSX.png


You could also use the parent::* abbreviated syntax .. (example: //*[title="50"]/..) or a nested predicate (example: //*[*[title="50"]])
Or parent::node() which corresponds to the shortcut .. and is better in my opinion. In fact parent::* is limited to the principal node type of the axis which in most cases is not a problem.
If you are using try .xpath('..') or xpath('parent::node()')
"This XPath will only select the parent node if it is a store." - and what happens in the given example where the parent is bicycle but the parent of the parent is store? Does it ascent? If not, is there a method to ascent in such cases and return None if there is no such parent?
A
Aminah Nuraini

Just as an alternative, you can use ancestor.

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

It's more powerful than parent since it can get even the grandparent or great great grandparent


It is not "more powerful". It is just different. Thus the choice of the axis depends on the use case.
@LudovicKuty it's more "flexible", there are you "happy" now?
No, it's just wrong. Judging from op's xpath he asked for a parent, not ancestor.
k
kjhughes

New, improved answer to an old, frequently asked question...

How could I get its parent? Result should be the store node.

Use a predicate rather than the parent:: or ancestor:: axis

Most answers here select the title and then traverse up to the targeted parent or ancestor (store) element. A simpler, direct approach is to select parent or ancestor element directly in the first place, obviating the need to traverse to a parent:: or ancestor:: axes:

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

Should the intervening elements vary in name:

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

Or, in name and depth:

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

p
phduarte

You can use the two dots at the end of expression, too. See this example:

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