XPath: obtenir le nœud parent du nœud enfant

157

J'ai besoin d'obtenir le nœud parent du nœud enfant title 50

Pour le moment, je n'utilise que

//*[title="50"]

Comment pourrais-je avoir son parent? Le résultat doit être le storenœud.


<?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>
GibboK
la source

Réponses:

297

Utilisez les parentaxes portant le nom du nœud parent.

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

Ce XPath ne sélectionnera le nœud parent que s'il s'agit d'un store.

Mais vous pouvez également utiliser l'un de ces

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

Ces xpaths sélectionneront n'importe quel nœud parent. Donc, si le document change, vous sélectionnerez toujours un nœud, même si ce n'est pas le nœud que vous attendez.

ÉDITER

Que se passe-t-il dans l'exemple donné où le parent est un vélo mais le parent du parent est un magasin?

Est-ce qu'il monte?

Non, il ne sélectionne le magasin que s'il s'agit d'un parent du nœud correspondant //*[title="50"].

Si non, existe-t-il une méthode pour remonter dans de tels cas et renvoyer None s'il n'y a pas de tel parent?

Oui, vous pouvez utiliser des ancestoraxes

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

Cela sélectionnera tous les ancêtres du nœud correspondant //*[title="50"]qui sont `stores. Par exemple

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

Résultat de la sélection XPath

René Link
la source
7
Vous pouvez également utiliser la parent::*syntaxe abrégée ..(exemple: //*[title="50"]/..) ou un prédicat imbriqué (exemple: //*[*[title="50"]])
Daniel Haley
1
Informations supplémentaires: w3.org/TR/xpath/#axes et w3.org/TR/xpath/#path-abbrev
Daniel Haley
3
Ou parent::node()qui correspond au raccourci ..et qui est mieux à mon avis. En fait, parent::*se limite au type de nœud principal de l'axe ce qui dans la plupart des cas ne pose pas de problème.
Ludovic Kuty
3
Si vous utilisez try .xpath('..')orxpath('parent::node()')
briankip
"Ce XPath ne sélectionnera le nœud parent que s'il s'agit d'un magasin." - et que se passe-t-il dans l'exemple donné où le parent est bicyclemais que le parent du parent est store? Est-ce qu'il monte? Sinon, y a-t-il une méthode pour remonter dans de tels cas et revenir en l' Noneabsence d'un tel parent?
Martin Thoma
31

Juste comme alternative, vous pouvez utiliser ancestor.

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

C'est plus puissant que parentcar il peut même obtenir le grand-parent ou l'arrière-arrière-grand-parent

Aminah Nuraini
la source
20
Ce n'est pas "plus puissant". C'est juste différent. Ainsi le choix de l'axe dépend du cas d'utilisation.
Ludovic Kuty
11

Vous pouvez également utiliser les deux points à la fin de l'expression. Voir cet exemple:

//*[title="50"]/..
Phduarte
la source
2

Nouvelle réponse améliorée à une ancienne question fréquemment posée ...

Comment pourrais-je avoir son parent? Le résultat doit être le storenœud.

Utilisez un prédicat plutôt que l' axe parent::ouancestor::

La plupart des réponses ici sélectionnent le title, puis remontent jusqu'à l' storeélément parent ou ancestor ( ) ciblé . Une approche plus simple et directe consiste à sélectionner l'élément parent ou ancêtre directement en premier lieu, évitant ainsi d'avoir à parcourir les axes a parent::ou ancestor:::

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

Si le nom des éléments intermédiaires varie:

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

Ou, en nom et en profondeur:

//*[.//title = "50"]
kjhughes
la source
Cela ne répond pas à la question. L'auteur ne connaît pas nécessairement le nom du parent à l'avance.
Kenn Sebesta le
1
@KennSebesta: J'ai mis à jour la réponse pour répondre à votre préoccupation. Veuillez supprimer votre vote négatif si votre objection a été traitée, ou faites-moi savoir si vous pensez que quelque chose ne va pas avec la réponse. Merci.
kjhughes le
0

Cela fonctionne dans mon cas. J'espère que vous pourrez en tirer un sens.

//div[text()='building1' and @class='wrap']/ancestor::tr/td/div/div[@class='x-grid-row-checker']
Shivam Bharadwaj
la source