Como usar o XPath contains () aqui?

142

Estou tentando aprender XPath. Eu olhei para os outros contains()exemplos por aqui, mas nada que usa um operador AND . Não consigo fazer isso funcionar:

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

Em:

...
<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
fonte
Isso funciona para mim, eu testei em whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm
mihi

Respostas:

199

Você está olhando apenas o primeiro lifilho na consulta que possui, em vez de procurar qualquer lielemento filho que possa conter o texto 'Model',. O que você precisa é de uma consulta como a seguinte:

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

Esta consulta vai dar-lhe os elementos que têm uma classde featureListcom um ou mais lifilhos que contêm o texto, 'Model'.

Jeff Yates
fonte
13
+1 - O "./" é um pouco enganador - sugere que qualquer coisa que não seja o nó atual seria levado em consideração quando você o deixar de fora, mas, na verdade, é redundante: "// ul [@ class = ' featureList 'e li [contém (.,' Modelo ')]] "é a mesma coisa.
30511 Tomalak
4
Sim, eu estava apenas sendo específico. Possivelmente muito específico.
911 Jeff Yates
Se não existe licom Modela ul, então a andcondição falhará. Portanto, a andcondição retorna falseno conjunto vazio, está correta?
damluar
58

Eu já dei meu +1 à solução de Jeff Yates.

Aqui está uma explicação rápida por que sua abordagem não funciona. Este:

// ul [@ class = 'featureList' e contém (li, 'Model')]

encontra uma limitação da contains()função (ou qualquer outra função de cadeia no XPath, nesse caso).

O primeiro argumento deve ser uma string. Se você alimentar uma lista de nós (se " li" fizer isso)), uma conversão em string deverá ocorrer. Mas essa conversão é feita apenas para o primeiro nó da lista.

No seu caso, o primeiro nó da lista é <li><b>Type:</b> Clip Fan</li>(convertido em uma string: " Type: Clip Fan"), o que significa que isto:

// ul [@ class = 'featureList' e contém (li, 'Type')]

na verdade selecionaria um nó!

Tomalak
fonte
1
bom estava lutando para descobrir por que consultas como: ".//td[contains(.//*,'sething ')]" funcionam apenas com profundidade 1. Eu descobri como fazê-lo funcionar, mas não foi Certifique-se de como o anterior estava funcionando. O que eu realmente precisava era de ".//td[.//*[contains(., algo) ']]"
JonnyRaa 5/14/14
11

Esta é uma nova resposta para uma pergunta antiga sobre um equívoco comum sobre contains()no XPath ...

Resumo: contains()meios contém uma substring , não contém um nó .

Explicação detalhada

Esse XPath geralmente é mal interpretado:

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

Interpretação incorreta: selecione os ulelementos que contêm um lielemento Modelnele.

Isso está errado porque

  1. contains(x,y)espera xser uma string e
  2. a regra XPath para converter vários elementos em uma sequência é a seguinte :

    Um conjunto de nós é convertido em uma cadeia de caracteres retornando o valor da cadeia de nós no conjunto de nós que é o primeiro na ordem do documento . Se o conjunto de nós estiver vazio, uma sequência vazia será retornada.

Interpretação correta: selecione os ulelementos cujo primeiro li filho possui um valor de sequência que contém uma Modelsubstring.

Exemplos

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')]seleciona o one ulelemento

    Nota: O two ulelemento não está selecionado porque o valor da cadeia do primeiro lifilho de two ulé Foo, que não contém a Modelsubstring.

  • //ul[li[contains(.,'Model')]]seleciona os elementos onee two ul.

    Nota: Os dois ulelementos são selecionados porque contains()são aplicados a cada um liindividualmente. (Portanto, a regra complicada de conversão de vários elementos em cadeia é evitada.) Ambos os ulelementos têm um lifilho cujo valor de cadeia contém a Modelsubstring - a posição do lielemento não importa mais.

Veja também

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

Cole meu containsexemplo aqui:

//table[contains(@class, "EC_result")]/tbody
hahakubile
fonte
2
Não há tableelemento ou EC_resultvalor de classe no código do OP. Esta resposta não faz sentido aqui e deve ser excluída.
Kjhughes # 10/18