XPath: obtener el nodo primario del nodo secundario

157

Necesito obtener el nodo primario para el nodo secundario title 50

Por el momento solo estoy usando

//*[title="50"]

¿Cómo podría obtener su padre? El resultado debe ser el storenodo.


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

Respuestas:

297

Use los parentejes con el nombre del nodo principal.

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

Este XPath solo seleccionará el nodo principal si es un store.

Pero también puedes usar uno de estos

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

Estas xpaths seleccionarán cualquier nodo padre. Entonces, si el documento cambia, siempre seleccionará un nodo, incluso si no es el nodo que espera.

EDITAR

¿Qué sucede en el ejemplo dado donde el padre es una bicicleta pero el padre del padre es una tienda?

¿Asciende?

No, solo selecciona la tienda si es un padre del nodo que coincide //*[title="50"].

Si no, ¿hay un método para ascender en tales casos y devolver Ninguno si no existe tal padre?

Sí, puedes usar ancestorhachas

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

Esto seleccionará todos los antepasados ​​del nodo //*[title="50"]que coincidan con `tiendas. P.ej

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

Resultado de la selección XPath

René Link
fuente
77
También puede utilizar la parent::*sintaxis abreviada ..(ejemplo: //*[title="50"]/..) o un predicado anidado (ejemplo: //*[*[title="50"]])
Daniel Haley
1
Información adicional: w3.org/TR/xpath/#axes y w3.org/TR/xpath/#path-abbrev
Daniel Haley
3
O parent::node()que corresponde al atajo ..y es mejor en mi opinión. De hecho, parent::*se limita al tipo de nodo principal del eje, que en la mayoría de los casos no es un problema.
Ludovic Kuty
3
Si está utilizando probar .xpath('..')oxpath('parent::node()')
briankip
"Esta XPath solo seleccionará el nodo principal si es una tienda". - ¿Y qué sucede en el ejemplo dado donde el padre es bicyclepero el padre del padre es store? ¿Asciende? Si no es así, ¿hay algún método para ascender en tales casos y regresar Nonesi no existe tal padre?
Martin Thoma
31

Solo como alternativa, puedes usar ancestor.

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

Es más poderoso que parentya que puede llegar incluso al abuelo o al tatarabuelo

Aminah Nuraini
fuente
20
No es "más poderoso". Es solo diferente. Por lo tanto, la elección del eje depende del caso de uso.
Ludovic Kuty
11

También puedes usar los dos puntos al final de la expresión. Ver este ejemplo:

//*[title="50"]/..
phduarte
fuente
2

Respuesta nueva y mejorada a una vieja pregunta frecuente ...

¿Cómo podría obtener su padre? El resultado debe ser el storenodo.

Use un predicado en lugar del eje parent::oancestor::

La mayoría de las respuestas aquí seleccionan titley luego atraviesan el elemento padre o ancestro ( store) objetivo . Un enfoque más simple, directa es seleccionar padre o ancestro elemento directamente en el primer lugar, obviando la necesidad de recorrer a una parent::o ancestor::ejes:

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

Si los elementos que intervienen varían en nombre:

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

O, en nombre y profundidad:

//*[.//title = "50"]
kjhughes
fuente
Esto no responde la pregunta. El autor no necesariamente conoce el nombre del padre antes de tiempo.
Kenn Sebesta
1
@KennSebesta: He actualizado la respuesta para abordar su inquietud. Elimine su voto negativo si su objeción ha sido abordada, o avíseme si siente que algo sigue mal con la respuesta. Gracias.
kjhughes
0

Esto funciona en mi caso. Espero que puedas extraer significado de ello.

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