(Обратный) Запрос обхода XPath для доступа к DIV с определенным текстовым значением

#html #xpath

#HTML #xpath

Вопрос:

Работа с DOM , который имеет один и тот же HTML-цикл более 100 раз, который выглядит следующим образом

 <div class="intro"> 
  <div class="header"> 
     <h1 class="product-code"> <span class="code">ZY001</span> <span class="intro">ZY001 Title/Intro</span> </h1> 
  </div> 
<div> 
<table> 
<tbody>
   <tr> 
        <td>Available</td>
        <td> S </td>
        <td> M </td>
        <td> XL </td>
  </tr> 
  

Ранее я использовал этот запрос XPath для возврата ВСЕХ значений узла (все более 100 экземпляров DOM-запроса в связи с переменными nodes, которые могут содержать в Available

 //div[@class='intro']/div/table/tbody/tr/td[contains(text(),'Available')]/following-sibling::td
  

объект (DOMNodeList)[595]
public ‘length’ => int 591

Теперь мне нужно настроить таргетинг на product-code / code специально для извлечения всех td атрибутов для определенного code

Поскольку div, содержащий уникальный идентификатор (в приведенном выше примере ZY001 ), не является прямым предком, я думаю, что мне нужно выполнить обратный запрос XPath

Вот одна из моих попыток:

 //h1[@class='product-code']/span[contains(@class, 'code') and text() = 'ZY001']/../../div[@class='intro']/div/table/tbody/tr/td[contains(text(),'Available')]/following-sibling::td
  

Поскольку я определяю /span[contains(@class, 'code') and text() = 'ZY001'] , а затем пытаюсь дважды обойти dom в обратном направлении, используя /../../ , я надеялся / ожидал получить обратно div[@class=’intro’] с текстом ZY001 непосредственно над ним, или, скорее, public 'length' => int 1

Но все мои попытки до сих пор приводили к 0 результатам. Не false , указывающий на неправильный XPath, но 0 .

Как я могу изменить свой запрос XPath, чтобы вернуть единственный экземпляр из многих <div class="intro"> , которые содержат <h1 class="product-code"> / <span class="code"> текстовое значение ZY001 ?

Комментарии:

1. Вы хотите получить элементы <td> в <div class=»intro»>, где доступен код us ZY001 и 1st <td>, это правильно?

2. Да, правильно. Моя трудность заключается в том, что он не является прямым потомком.

3. ОК. Взгляните на мой ответ. Могу объяснить больше, если требуется.

Ответ №1:

Используйте

 //h1[@class='product-code']/span[contains(@class, 'code') and text() = 'ZY001']/../../../div/table/tbody
  

вместо

 //h1[@class='product-code']/span[contains(@class, 'code') and text() = 'ZY001']/../../div[@class='intro']/div/table/tbody
  

Комментарии:

1. Спасибо. Я попробую, как только вернусь домой (сейчас на работе и у меня нет доступа к коду)

2. Да, это именно то, к чему я стремился, большое вам спасибо! Более конкретно //h1[@class='product-code']/span[contains(@class, 'code') and text() = 'ZY001']/../../../div/table/tbody/tr/td[contains(text(),'Available')]/following-sibling::td

Ответ №2:

Для этого вы можете использовать любой из приведенных ниже xpath:

 //div[@class='intro' and //h1[@class='product-code']/span[@class='code' and text()='ZY001']]//tbody/tr[td[text()='Available']]/td[2]

//div[@class='intro' and //span[@class='code' and text()='ZY001']]//tbody/tr[td[text()='Available']]/td[2]

//div[@class='intro' and //span[@class='code' and text()='ZY001']]//tr[td[text()='Available']]/td[2]
  

Измените td[2] на td[3] и td[4] , чтобы получить 3-й и 4-й td значения соответственно

Комментарии:

1. Спасибо за разнообразие возможностей, они интересны. Единственное, что им мешает, это то, что все они, похоже, обрабатываются намного медленнее, чем запрос XPath @StevenLiang. Однако они разные, и завтра я собираюсь провести с ними еще несколько тестов и выбрать ответ.

2. На самом деле мне это немного любопытно, но причина, по которой это происходит так медленно, заключается в том, что он получает все узлы (в 99% итераций.. — все еще хочу протестировать его, как я уже сказал, чтобы понять, что я делаю.), что td[2] означает возврат 100 (что соответствует каждой итерации цикла), что означает, что запрос не является эксклюзивным для уникального идентификатора / ZY001 ).. Посмотрю еще раз завтра, но моя правка в ответе ниже вашего работает как ссылка, помимо возврата NULL вместо Available (если вернуть все td ‘ы в nodeValue , как это делает ваш — что не имеет особого значения, но ссылка.

3. Да, это тоже заставило меня задуматься, я никогда не смотрел на xpath как на то, что было бы быстрее, я привык смотреть на это как на то, что, скорее всего, не изменится. Я также собираюсь провести некоторое исследование. Спасибо, что упомянули об этом

4. Это слишком сильно ломает мне голову, чувак: P .. Так что да, запросы игнорируют инкапсуляцию text() = 'whatever' для div класса intro или, другими словами, //div[@class='intro' and //h1[@class='product-code']/span[@class='code' and text()='ZY001']]//tbody/tr[td[text()='Available']] возвращают точно такие же результаты XPath, что и этот запрос //div[@class='intro' and //h1[@class='product-code']/span]//tbody/tr[td[text()='Available']] . Почему это так, я не уверен. Однако это была интересная стратегия, которая заставила меня задуматься в других направлениях. Что касается ответа, я

5. должен согласиться с ответом @StevenLiang, поскольку он работает с text() путем, возвращающим связанные td для per .. и работает так, как необходимо для моего приложения. Еще раз спасибо за попытку 🙂