2010-06-09 35 views
15

ancestor::foo[bar[@attr="val"]]XPath para encontrar más cercana elemento antecesor que contiene un elemento que tiene un atributo con un cierto valor

pensé que esto iba a funcionar, pero no lo es. Necesito encontrar el elemento foo más cercano en el árbol que tiene un elemento hijo bar, que a su vez tiene un atributo attr de val.

+0

¿Qué obtienes? –

+0

Nada. No se corresponde con el elemento que describí. ¿Debería funcionar esa expresión? –

+8

Proporcione el documento XML (mínimo) en el que esto "no funciona". Solo sabemos que estás "metiendo la mano en la bolsa y no encuentras lo que quieres allí", pero no sabemos "qué hay en la bolsa" :) –

Respuesta

28

Esto debería funcionar:

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

o alternativamente

root/foo/bar[ancestor::foo[bar[@attr="val"]]] 

coincide con el segundo elemento

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

¿Esto realmente responde la pregunta? El OP desea seleccionar el ancestro (el foo). Este ejemplo selecciona el descendiente (la barra) cuyo antecesor coincide con algunos criterios. –

+3

Esto no responde la pregunta. No estoy seguro de por qué ha sido votado. – geoidesic

+1

@geoidesic porque aparentemente resolvió el problema de OP – Gordon

9

<bar> Actualizado para reflejar una solución prevista por OP.

Véase la respuesta de @ David

Para un xml de ejemplo a continuación,

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

un XPath válida en el eje inversa con <tres> como el nodo de contexto, una válida la solución es

./ancestor::foo[bar[@attr='val']][position() = 1] 

"./" es opcional. position() = 1 no es opcional, ya que de lo contrario también se devolverá el ancestro foo que satisfaga los predicados.

vieja respuesta: ignorar

Ésta es una cuestión de edad. pero cualquiera que esté interesado, lo siguiente debería conseguirte lo que la pregunta original pretendía.

eje inversa

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

eje Delantero

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

El reverso de "ancestro" es "descendiente", no "hijo". "niño" es el reverso de "padre" en lugar de "ancestro" – wybe

+0

@wybe Creo que estás confundiendo las direcciones de los ejes xpath con los antónimos de un eje. Cualquier eje que encuentre nodos en orden de documento después del nodo de contexto es un eje de avance. Un eje que encuentra nodos en orden de documento antes del nodo contextual es un eje inverso. Si eso no resuelve lo que pretendía, ¿podría proporcionarnos lo que realmente quiso decir con eso? – santon

+0

@wybe Consulte https://www.w3.org/TR/xpath/#axes y en la sección 2.4 Predicados – santon

1

En mi opinión la mejor respuesta fue proporcionado por la persona que hizo la pregunta. Se suponía que su solución devolvería todos los ancestros foos. Él sólo quiere lo más cercano que es el que tiene la posición() = 1, por lo que su expresión XPath necesita ser modificado ligeramente a:

ancestor::foo[bar[@attr="val"] and position() = 1] 

Si escribe que el ancestor::foo[bar[@attr="val"]] no arrojó nada, por lo que tuvo algún otro problema en su xml o en su suposición sobre el elemento actual de su contexto de evaluación XPath.

Las otras respuestas (comenzando con //) realmente no responden a la pregunta e incluso si por casualidad satisfacen la necesidad de alguien, entonces no son eficientes: eligen TODOS los elementos en el archivo xml, aplicando filtro en ellos después Mientras que el xpath relativo propuesto por mí o por la persona que hizo esta pregunta solo va a buscar a través de pocos elementos comenzando desde el nodo actual hasta el padre y su padre, etc. - será muy eficiente incluso con archivos XML grandes .

+0

Estoy de acuerdo con su evaluación. Mi respuesta trató el problema de arriba hacia abajo y no lo aborda desde el nodo de contexto. Actualizaré mi respuesta para reflejar eso. Gracias – santon

Cuestiones relacionadas