¿Cómo usar XPath contiene () aquí?

142

Estoy tratando de aprender XPath. Miré los otros contains()ejemplos por aquí, pero nada que use un operador AND . No puedo hacer que esto funcione:

//ul[@class='featureList' and contains(li, 'Model')]

En:

...
<ul class="featureList">

<li><b>Type:</b> Clip Fan</li><li><b>Feature:</b> Air Moved: 65 ft.
    Amps: 1.1
    Clip: Grips any surface up to 1.63"
    Plug: 3 prong grounded plug on heavy duty model
    Usage: Garage, Workshop, Dorm, Work-out room, Deck, Office & more.</li><li><b>Speed Setting:</b> 2 speeds</li><li><b>Color:</b> Black</li><li><b>Power Consumption:</b> 62 W</li><li><b>Height:</b> 14.5"</li><li><b>Width:</b> Grill Diameter: 9.5"</li><li><b>Length:</b> 11.5"</li>

<li><b>Model #: </b>CR1-0081-06</li>
<li><b>Item #: </b>N82E16896817007</li>
<li><b>Return Policy: </b></li>
</ul>
...
ryeguy
fuente
esto funciona para mí, lo probé en whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm
mihi

Respuestas:

199

Sólo se busca en el primer liniño en la consulta que tiene lugar de buscar cualquier lielemento secundario que pueda contener el texto, 'Model'. Lo que necesita es una consulta como la siguiente:

//ul[@class='featureList' and ./li[contains(.,'Model')]]

Esta consulta le dará los elementos que tienen una classde las featureListcon uno o más lihijos que contienen el texto, 'Model'.

Jeff Yates
fuente
13
+1 - El "./" es un poco engañoso: sugiere que cualquier cosa que no sea el nodo actual se tendría en cuenta cuando lo deja fuera, pero de hecho es redundante: "// ul [@ class = ' featureList 'y li [contiene (.,' Model ')]] "es lo mismo.
Tomalak
44
Sí, solo estaba siendo específico. Muy posiblemente demasiado específico.
Jeff Yates
Si no hay licon Modelen ul, entonces la andcondición fallará. Entonces la andcondición regresa falseen el conjunto vacío, ¿es correcto?
Damluar
58

Ya le di mi +1 a la solución de Jeff Yates.

Aquí hay una explicación rápida de por qué su enfoque no funciona. Esta:

// ul [@ class = 'featureList' y contiene (li, 'Model')]

encuentra una limitación de la contains()función (o cualquier otra función de cadena en XPath, para el caso).

Se supone que el primer argumento es una cadena. Si lo alimenta con una lista de nodos (darle " li" hace eso), debe realizarse una conversión a cadena. Pero esta conversión se realiza solo para el primer nodo de la lista.

En su caso, el primer nodo de la lista es <li><b>Type:</b> Clip Fan</li>(convertido a una cadena: " Type: Clip Fan") lo que significa que esto:

// ul [@ class = 'featureList' y contiene (li, 'Type')]

en realidad seleccionaría un nodo!

Tomalak
fuente
1
bueno, uno ha estado luchando por descubrir por qué las consultas como: ".//td[contains(.//*,'something ')]" solo funcionan a una profundidad de 1. Había descubierto cómo hacerlo funcionar pero no estaba seguro de cómo funcionaba todo lo anterior. Lo que realmente necesitaba era ".//td[.//*[contains(.,'something ')]]"
JonnyRaa
11

Esta es una nueva respuesta a una vieja pregunta sobre un error común sobre contains()XPath ...

Resumen: contains()significa que contiene una subcadena , no contiene un nodo .

Explicación detallada

Este XPath a menudo se malinterpreta:

//ul[contains(li, 'Model')]

Interpretación incorrecta: seleccione aquellos ulelementos que contengan un lielemento con Modelél.

Esto está mal porque

  1. contains(x,y)espera xser una cadena y
  2. La regla XPath para convertir múltiples elementos en una cadena es esta :

    Un conjunto de nodos se convierte en una cadena al devolver el valor de cadena del nodo en el conjunto de nodos que está primero en el orden del documento . Si el conjunto de nodos está vacío, se devuelve una cadena vacía.

Interpretación correcta: seleccione aquellos ulelementos cuyo primer li hijo tenga un valor de cadena que contenga una Modelsubcadena.

Ejemplos

XML

<r>
  <ul id="one">
    <li>Model A</li>
    <li>Foo</li>
  </ul>
  <ul id="two">
    <li>Foo</li>
    <li>Model A</li>
  </ul>
</r> 

XPaths

  • //ul[contains(li, 'Model')]selecciona el one ulelemento

    Nota: El two ulelemento no está seleccionado porque el valor de cadena del primer elemento lisecundario de two ules Foo, que no contiene la Modelsubcadena.

  • //ul[li[contains(.,'Model')]]selecciona los elementos oney two ul.

    Nota: Ambos ulelementos se seleccionan porque contains()se aplica a cada uno liindividualmente. (Por lo tanto, se evita la difícil regla de conversión de elementos múltiples a cadenas). Ambos ulelementos tienen un lihijo cuyo valor de cadena contiene la Modelsubcadena: la posición del lielemento ya no importa.

Ver también

kjhughes
fuente
-2
//ul[@class="featureList" and li//text()[contains(., "Model")]]
runrig
fuente
-5

Pega mi containsejemplo aquí:

//table[contains(@class, "EC_result")]/tbody
hahakubile
fuente
2
No hay ningún tableelemento o EC_resultvalor de clase en el código de OP. Esta respuesta no tiene sentido aquí y debe eliminarse.
kjhughes