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

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


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!


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


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

-5

Fügen Sie hier mein containsBeispiel ein:

//table[contains(@class, "EC_result")]/tbody

2
Der OP-Code enthält kein tableElement oder keinen EC_resultKlassenwert. Diese Antwort macht hier keinen Sinn und sollte gelöscht werden.
— kjhughes
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.