Wie benutzt man XPath enthält () hier?

142

Ich versuche XPath zu lernen. Ich habe mir die anderen contains()Beispiele hier angesehen, aber nichts, das einen AND- Operator verwendet. Ich kann das nicht zum Laufen bringen:

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

Auf:

...
<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
quelle
Das funktioniert bei mir. Ich habe es auf whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm
mihi

Antworten:

199

Sie betrachten nur das erste liuntergeordnete liElement in Ihrer Abfrage, anstatt nach einem untergeordneten Element zu suchen , das den Text enthalten kann 'Model'. Was Sie brauchen, ist eine Abfrage wie die folgende:

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

Diese Abfrage gibt Ihnen die Elemente, die ein classvon featureListmit einem oder mehreren liuntergeordneten Elementen haben , die den Text enthalten 'Model'.

Jeff Yates
quelle
13
+1 - Das "./" ist etwas irreführend - es deutet darauf hin, dass alles andere als der aktuelle Knoten berücksichtigt wird, wenn Sie ihn weglassen, aber tatsächlich ist es redundant: "// ul [@ class = ' featureList 'und li [enthält (.,' Model ')]] "ist dasselbe.
Tomalak
4
Ja, ich war nur spezifisch. Möglicherweise zu spezifisch.
Jeff Yates
Wenn es kein limit Modelin gibt ul, schlägt die andBedingung fehl. Die andBedingung kehrt also falseauf dem leeren Satz zurück. Ist sie korrekt?
Damluar
58

Ich habe Jeff Yates 'Lösung bereits meine +1 gegeben.

Hier finden Sie eine kurze Erklärung, warum Ihr Ansatz nicht funktioniert. Dies:

// ul [@ class = 'featureList' und enthält (li, 'Model')]

stößt auf eine Einschränkung der contains()Funktion (oder einer anderen Zeichenfolgenfunktion in XPath).

Das erste Argument soll eine Zeichenfolge sein. Wenn Sie ihm eine Knotenliste zuführen (wenn Sie ihm " li" geben), muss eine Konvertierung in einen String erfolgen. Diese Konvertierung wird jedoch nur für den ersten Knoten in der Liste durchgeführt.

In Ihrem Fall ist der erste Knoten in der Liste <li><b>Type:</b> Clip Fan</li>(in eine Zeichenfolge konvertiert: " Type: Clip Fan"), was bedeutet, dass dies:

// ul [@ class = 'featureList' und enthält (li, 'Type')]

würde tatsächlich einen Knoten auswählen!

Tomalak
quelle
1
Der nette hat sich bemüht herauszufinden, warum Abfragen wie: ".//td[contains(.//*,'something ')]" nur bis zu einer Tiefe von 1 funktionieren. Ich hatte herausgefunden, wie es funktioniert, war es aber nicht sicher, wie das oben überhaupt funktionierte. Was ich tatsächlich brauchte, war ".//td[.//*[contains(.,'something ')]]"
JonnyRaa
11

Dies ist eine neue Antwort auf eine alte Frage zu einem häufigen Missverständnis übercontains() in XPath ...

Zusammenfassung: contains()Mittel enthalten einen Teil , nicht enthält einen Knoten .

Ausführliche Erklärung

Dieser XPath wird oft falsch interpretiert:

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

Falsche Interpretation: Wählen Sie die ulElemente aus, die ein liElement enthaltenModel .

Das ist falsch, weil

  1. contains(x,y)erwartet x, eine Zeichenfolge zu sein, und
  2. die XPath Regel mehrere Elemente in einen String für die Umwandlung ist dies :

    Ein Knotensatz wird in eine Zeichenfolge konvertiert, indem der Zeichenfolgenwert des Knotens in dem Knotensatz zurückgegeben wird, der zuerst in der Dokumentreihenfolge steht . Wenn der Knotensatz leer ist, wird eine leere Zeichenfolge zurückgegeben.

Richtige Interpretation: Wählen Sie diejenigen ulElemente aus, deren erstes untergeordnetes Element lieinen Zeichenfolgenwert hat , der eine ModelTeilzeichenfolge enthält .

Beispiele

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')]wählt das one ulElement aus.

    Hinweis: Das two ulElement wird nicht ausgewählt, da der Zeichenfolgenwert des ersten liuntergeordneten Elements von is two ulist Foo, das den ModelTeilstring nicht enthält .

  • //ul[li[contains(.,'Model')]]wählt das oneund austwo ul Elemente aus.

    Hinweis: Beide ulElemente werden ausgewählt, da contains()sie lieinzeln angewendet werden . (Somit wird die schwierige Konvertierungsregel für mehrere Elemente in Zeichenfolgen vermieden.) Beide ulElemente haben ein untergeordnetes Element, lidessen Zeichenfolgenwert die ModelTeilzeichenfolge enthält - die Position des liElements spielt keine Rolle mehr.

Siehe auch

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

Fügen Sie hier mein containsBeispiel ein:

//table[contains(@class, "EC_result")]/tbody
hahakubile
quelle
2
Der OP-Code enthält kein tableElement oder keinen EC_resultKlassenwert. Diese Antwort macht hier keinen Sinn und sollte gelöscht werden.
kjhughes