XPath запит на отримання n-го примірника елемента


135

Існує HTML-файл (вміст якого я не контролюю), який містить кілька inputелементів, усі з однаковим фіксованим idатрибутом "search_query". Вміст файлу може змінюватися, але я знаю, що я завжди хочу отримати другий inputелемент з атрибутом id "search_query".

Для цього мені потрібен вираз XPath. Я спробував, //input[@id="search_query"][2]але це не працює. Ось приклад рядка XML, коли цей запит не вдався:

<div>
  <form>
    <input id="search_query" />
   </form>
</div>

<div>
  <form>
    <input id="search_query" />
  </form>
</div>

<div>
  <form>
    <input id="search_query" />
  </form>
</div>

Майте на увазі, що вищезазначене є лише прикладом, а інший HTML-код може бути зовсім іншим, і inputелементи можуть з’являтися в будь-якому місці без узгодженої структури документа (за винятком того, що я впевнений, що завжди буде принаймні два inputелементи з атрибутом id "search_query").

Який правильний вираз XPath?


Добре запитання, +1. Дивіться мою відповідь для повного пояснення проблеми та шуканого рішення.
Димитрій Новатчев

7
Незначна точка: у вас ніколи не повинно бути більше одного елемента із заданим ідентифікатором (а значить, HTML у питанні насправді недійсний). На практиці браузери дозволять вам це робити в будь-якому випадку, але якщо ви цього не робите, ви втрачаєте єдину перевагу використання ідентифікаторів - це те, що вони сигналізують "Я унікальний" (тоді як класи призначені для використання для унікальні позначувачі).
machineghost

Відповіді:


244

Це FAQ :

//somexpression[$N]

означає "Знайти кожен вибраний вузол, //somexpressionякий є $Nдитиною свого батька".

Що ви хочете, це :

(//input[@id="search_query"])[2]

Пам'ятайте : []Оператор має більший пріоритет (пріоритет), ніж //абревіатура.


6
Мені подобається ця відповідь. Я не розглядав питання пріоритетності (я просто припускав простий пріоритет зліва направо).
rlandster

10
@rlandster: Слово "пріоритет" може бути заплутаним. Неаббредованою формою //input[@id='search_query'][2]є:/descendat-or-self::node()/child::input[attribute::id='search_query'][position()=2]

21
Для тих, хто потрапив сюди від Google - нумерація починається з 1 - [1] є першим елементом і так далі
Ян Марес

Дивно, що в запитах XPath такі масиви починаються з 1, мене бентежило.
Ivotje50

@ Ivotje50 Так, послідовності та масиви XPath базуються на 1
Димитрій Новатчев,

21

Це, здається, працює:

/descendant::input[@id="search_query"][2]

Я виходжу з цього посилання "Довідник програміста XSLT 2.0 та XPath 2.0, 4-е видання" Майкла Кей.

Також в розділі "Скорочений синтаксис" є специфікація специфікації мови XML Path http://www.w3.org/TR/xpath/#path-abbrev, яка надала підказку.


Велике спасибі за цю відповідь. У моєму випадку прийняте рішення не працюватиме, оскільки я використовую xpath в робот-рамках, який не приймає шляхи, починаючи з дужок. Цей, однак, повинен зробити трюк
dahui
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.