Jak tutaj używać XPath zawiera ()?


142

Próbuję się nauczyć XPath. Spojrzałem na inne contains()przykłady tutaj, ale nie ma nic, co używa operatora AND . Nie mogę tego uruchomić:

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

Na:

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

to działa dla mnie, przetestowałem to na whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm
— mihi

Odpowiedzi:


199

Szukasz tylko przy pierwszym lidziecku w zapytaniu masz zamiast szukać jakiegokolwiek lielementu podrzędnego, które mogą zawierać tekst 'Model'. Potrzebujesz zapytania, takiego jak następujące:

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

To zapytanie daje elementy, które mają działanie classz featureListjednym lub większą liczbą lidzieci, które zawierają tekst 'Model'.


13
+1 - „./” jest nieco mylące - sugeruje, że po opuszczeniu go pod uwagę brane byłoby wszystko inne niż bieżący węzeł, ale w rzeczywistości jest to zbędne: "// ul [@ class = ' featureList 'i li [zawiera (.,' Model ')]] ”to to samo.
— Tomalak

4
Tak, po prostu byłem konkretny. Całkiem możliwe, że zbyt szczegółowe.
— Jeff Yates,

Jeśli nie ma liz Modelin ul, andstan się nie powiedzie. Zatem andwarunek powraca falsena pusty zbiór, czy jest poprawny?
— damluar,

58

Dałem już +1 rozwiązaniu Jeffa Yatesa.

Oto krótkie wyjaśnienie, dlaczego Twoje podejście nie działa. To:

// ul [@ class = 'featureList' i zawiera (li, 'Model')]

napotyka ograniczenie contains()funkcji (lub dowolną inną funkcję tekstową w XPath, jeśli o to chodzi).

Pierwszy argument ma być łańcuchem. Jeśli podasz mu listę węzłów (dając mu to " li"), konwersja na łańcuch musi mieć miejsce. Ale ta konwersja jest wykonywana tylko dla pierwszego węzła na liście.

W Twoim przypadku pierwszy węzeł na liście jest <li><b>Type:</b> Clip Fan</li>(konwertowany na ciąg: „ Type: Clip Fan”), co oznacza, że:

// ul [@ class = 'featureList' i zawiera (li, 'Type')]

faktycznie wybierze węzeł!


1
miło, trudno było zrozumieć, dlaczego zapytania takie jak: ".//td[contains(.//*,'something ')]" działają tylko do głębokości 1. Wymyśliłem, jak to działa, ale nie udało mi się jestem pewien, jak powyższe w ogóle działało. Właściwie potrzebowałem „.//td[.//*[contains(.,'something ')]]”
— JonnyRaa,

11

To nowa odpowiedź na stare pytanie dotyczące powszechnego nieporozumienia dotyczącego contains()XPath ...

Podsumowanie: contains()oznacza, że zawiera podciąg , a nie zawiera węzła .

Szczegółowe wyjaśnienie

Ten XPath jest często błędnie interpretowany:

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

Błędna interpretacja: wybrać te ulelementy, które zawierają takie lielementy ze Modelw nim.

To jest złe, ponieważ

  1. contains(x,y)oczekuje, xże będzie ciągiem, a
  2. reguła XPath dotycząca konwersji wielu elementów na ciąg jest następująca :

    Zestaw węzłów jest konwertowany na łańcuch przez zwrócenie wartości ciągu węzła w zestawie węzłów, który jest pierwszy w kolejności dokumentu . Jeśli zestaw węzłów jest pusty, zwracany jest pusty ciąg.

Prawo interpretacji: wybrać te ulelementy, których pierwsze li dziecko ma String wartość , która zawiera się Modelpodciąg.

Przykłady

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')]wybiera one ulelement.

    Uwaga:two ul element nie jest wybrany, ponieważ ciąg wartości pierwszego lidzieckiem two uljest Foo, który nie zawiera Modelpodciąg.

  • //ul[li[contains(.,'Model')]]wybiera elementy onei two ul.

    Uwaga: oba ulelementy są zaznaczone, ponieważ contains()są stosowane do każdego z nich liosobno. (W ten sposób unika się skomplikowanej reguły konwersji wielu elementów na ciąg znaków). Oba ulelementy mają element lipotomny, którego wartość ciągu zawiera Modelpodłańcuch - pozycja lielementu nie ma już znaczenia.

Zobacz też


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

-5

Wklej mój containsprzykład tutaj:

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

2
W kodzie OP nie ma wartości tableelementu ani EC_resultklasy. Ta odpowiedź nie ma tutaj sensu i powinna zostać usunięta.
— kjhughes
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.