Comment utiliser XPath contains () ici?

142

J'essaye d'apprendre XPath. J'ai regardé les autres contains()exemples ici, mais rien qui utilise un opérateur AND . Je ne peux pas faire fonctionner ça:

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

Sur:

...
<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
la source
cela fonctionne pour moi, je l'ai testé sur whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm
mihi

Réponses:

199

Vous recherchez uniquement le premier lienfant de la requête que vous avez au lieu de rechercher un liélément enfant pouvant contenir le texte 'Model',. Ce dont vous avez besoin est une requête comme celle-ci:

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

Cette requête vous donnera les éléments qui ont un classde featureListavec un ou plusieurs lienfants qui contiennent le texte, 'Model'.

Jeff Yates
la source
13
+1 - Le "./" est un peu trompeur - il suggère que tout autre élément que le nœud actuel serait pris en compte lorsque vous l'omettez, mais en fait il est redondant: "// ul [@ class = ' featureList 'et li [contient (.,' Model ')]] "est la même chose.
Tomalak
4
Ouais, j'étais juste précis. Très probablement trop spécifique.
Jeff Yates
S'il n'y a aucun liavec Modelin ul, la andcondition échouera. Donc, la andcondition revient falsesur l'ensemble vide, est-ce correct?
damluar
58

J'ai déjà donné mon +1 à la solution de Jeff Yates.

Voici une explication rapide des raisons pour lesquelles votre approche ne fonctionne pas. Ce:

// ul [@ class = 'featureList' et contient (li, 'Model')]

rencontre une limitation de la contains()fonction (ou de toute autre fonction de chaîne dans XPath, d'ailleurs).

Le premier argument est censé être une chaîne. Si vous lui donnez une liste de nœuds (lui donner " li" fait cela), une conversion en chaîne doit avoir lieu. Mais cette conversion n'est effectuée que pour le premier nœud de la liste.

Dans votre cas, le premier nœud de la liste est <li><b>Type:</b> Clip Fan</li>(converti en chaîne: " Type: Clip Fan"), ce qui signifie que ceci:

// ul [@ class = 'featureList' et contient (li, 'Type')]

sélectionnerait en fait un nœud!

Tomalak
la source
1
gentil a eu du mal à comprendre pourquoi les requêtes telles que: ".//td[contains(.//*,'something ')]" ne fonctionnent qu'à une profondeur de 1. J'avais compris comment le faire fonctionner, mais ce n'était pas le cas sûr comment ce qui précède fonctionnait du tout. Ce dont j'avais réellement besoin était ".//td[.//*[contains(.,'something ')]]"
JonnyRaa
11

Ceci est une nouvelle réponse à une vieille question sur une idée fausse courante sur contains()XPath ...

Résumé: contains()signifie contient une sous-chaîne , ne contient pas de nœud .

Explication détaillée

Ce XPath est souvent mal interprété:

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

Mauvaise interprétation: sélectionnez les uléléments qui contiennent un liélément Model.

C'est faux parce que

  1. contains(x,y)s'attend xà être une chaîne, et
  2. la règle XPath pour convertir plusieurs éléments en une chaîne est la suivante :

    Un ensemble de nœuds est converti en chaîne en renvoyant la valeur de chaîne du nœud dans l'ensemble de nœuds qui est le premier dans l' ordre du document . Si l'ensemble de nœuds est vide, une chaîne vide est renvoyée.

Interprétation droite: Sélectionnez les uléléments dont la première li enfant a une valeur de chaîne qui contient une Modelsous - chaîne.

Exemples

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')]sélectionne l' one ulélément.

    Remarque: L' two ulélément n'est pas sélectionné car la valeur de chaîne du premier lienfant de two ulest Foo, qui ne contient pas la Modelsous - chaîne.

  • //ul[li[contains(.,'Model')]]sélectionne les éléments oneet two ul.

    Remarque: les deux uléléments sont sélectionnés car ils contains()sont appliqués à chacun liindividuellement. (Ainsi, la règle de conversion délicate de plusieurs éléments en chaîne est évitée.) Les deux uléléments ont un lienfant dont la valeur de chaîne contient la Modelsous-chaîne - la position de l' liélément n'a plus d'importance.

Voir également

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

Collez mon containsexemple ici:

//table[contains(@class, "EC_result")]/tbody
hahakubile
la source
2
Il n'y a pas d' tableélément ou EC_resultde valeur de classe dans le code d'OP. Cette réponse n'a aucun sens ici et devrait être supprimée.
kjhughes