JavaScript: как получить доступ к n-му результату поиска xpath?

описание проблемы

Я пытаюсь использовать xpath, чтобы найти узел «Месси» из приведенного ниже HTML. Чтобы свести к минимуму усилия по кодированию, я надеюсь на решение, которое использует индекс массива вместо циклического прохождения через итератор.

Я предполагаю, что самый стандартный и простой API — это XPathExpression.evaluate(). Если есть лучшие API, пожалуйста, поделитесь.

Кстати, мне нужно внести изменения в DOM Node из возвращенного результата. Таким образом, для XPathResult.resultType будет установлено значение ORDERED_NODE_ITERATOR_TYPE, и поэтому XPathResult.snapshotItem() использовать нельзя.

Пример HTML

<html>
<body>

<div>
    <div>NumberOne</div>
    <div>NumberTwo_Mbappe</div>
    <div>NumberOne</div>
    <div>NumberTwo_Ronaldo</div>
    <div>NumberTwo_Messi</div>
</div>

</body>
</html>

Код для получения результатов XPath

Выполнение приведенного ниже кода вернет итератор из приведенного выше html.

let xpathIterator = new XPathEvaluator()
                        .createExpression("//*[starts-with(text(), 'NumberTwo')]")
                        .evaluate(
                            document, 
                            XPathResult.ORDERED_NODE_ITERATOR_TYPE
                        );

Существующее решение итератора для извлечения n-го элемента

Существующий интерфейс XPathResult имеет только метод iterateNext(), поэтому для извлечения n-го элемента потребуется шесть строк кода:

let n = 3;
while (n > 0) { 
    xpathIterator.iterateNext(); 
    n--; 
}
xpathIterator.iterateNext();

Идеальное решение массива для извлечения n-го элемента

Поскольку XPath и Chrome ежедневно используются миллионами людей, в идеале должен быть способ получить n-й элемент напрямую с помощью индекса массива (как показано в следующем коде). Я был бы удивлен, если бы такого API еще не существовало.

let v = xpathResult[2];

Идеальное решение не обязательно должно использовать XPathExpression.evaluate(). Я открыт для любых решений, использующих стандартные функции JavaScript, поддерживаемые Chrome.

(Надеюсь, нам не нужно использовать функцию. Если функция должна использоваться, было бы хорошо иметь не более 2-3 строк кода с ESLint-lint.)

Спасибо!

Похожие сообщения

Поскольку XPathResult.resultType не является итерируемым, следующие сообщения не применяются:

Отвечает ли это на ваш вопрос? Как использовать Array.from с XPathResult?

Earlee 10.05.2023 03:07

Зачем вам использовать XPath при работе с HTML-страницами, а не просто использовать обычный подход к селектору запросов, например. document.querySelectorAll(`.wikitable tr`)? Нет причин рассматривать страницу как XML, если это не XML?

Mike 'Pomax' Kamermans 10.05.2023 03:09

Привет @Earlee, Does this answer your question? How to use Array.from with a XPathResult? Array.from() не работает, потому что для этого требуется итерируемый или подобный массиву объект. Объекты, подобные массивам, должны иметь свойство «длина».

Emma 10.05.2023 03:30

@Emma Эмма, да, там обсуждается, как вы можете преобразовать его в массив, создав свою собственную функцию. тогда вы, наконец, можете индексировать массив.

Earlee 10.05.2023 03:32

Привет, @Mike'Pomax'Kamermans, Why would you use XPath when working with HTML pages, instead of just using the normal query selector approach, e.g. document.querySelectorAll, цель моего вопроса - выполнить поиск через XPath, потому что в моей отрасли (QA Selenium Development) у нас часто нет такой роскоши, как использование селекторов CSS. Иногда фронтенд-разработчики создавали веб-сайт с огромными таблицами и без атрибутов (без класса и без идентификатора). Единственный способ найти что-то — это использовать xpath для поиска нужных текстов в строке таблицы. Селекторы CSS не работают с текстовыми узлами.

Emma 10.05.2023 03:46

Привет @Earlee yes they have a discussion there as to how you could convert it to array by creating your own function. then you can finally array indexing. Они сделали преобразование с 6 строками кода, что не короче «существующего» решения, которое я предоставил выше. Цель этого вопроса - помочь людям, которым нужно вручную выполнять поиск xpath тысячи раз в день и которые не могут позволить себе 6 строк кода.

Emma 10.05.2023 03:49

Привет @Mike'Pomax'Kamermans Why would you use XPath Я обновил свой пост, чтобы выполнить текстовый поиск XPath. Это сработает, если вы вставите коды в Chrome. Спасибо!

Emma 10.05.2023 03:53

Привет @Earlee yes they have a discussion there as to how you could convert it to array by creating your own function. Я надеюсь избежать необходимости создавать функцию, потому что коды будут запускаться в консоли Chrome, а окно Chrome будет закрываться и открываться снова сотни раз в день, а это значит, что функция понадобится создавать вручную сотни раз в день.

Emma 10.05.2023 04:01

@Эмма, спасибо. Хотя, конечно, это все еще очень легко сделать с «не xpath» с помощью Array.from(document.querySelector(`....`)).filter(e => e.textContent.contains(`be`)), поэтому я все еще не уверен, что xpath имеет больше смысла, чем выбор запроса, а затем сопоставление/фильтрация по мере необходимости =) Это может помочь объяснить, что вы на самом деле пытаемся достичь, конкретно, на тот случай, если есть какой-нибудь простой «нормальный» JS, который может так же легко достичь этой цели.

Mike 'Pomax' Kamermans 10.05.2023 04:20

Привет @Mike'Pomax'Kamermans, спасибо за предложение Array.filter(). Я добавил пример HTML. Пожалуйста ознакомтесь. Как бы вы использовали CssSelector для получения трех узлов «NumberTwo»? Получив три узла, как бы вы напрямую получили доступ к 3-му узлу (узлу «Месси»)? Кстати, пять текстовых узлов не обязательно расположены в <ul><li>; они с одинаковой вероятностью могут быть заключены в <ol><li> или <table><tr>. Кроме того, узлы «NumberTwo» не обязательно являются 2-м, 4-м и 5-м узлами; они с одинаковой вероятностью могут оказаться на позициях 1-2-5, 1-4-5 или 3-4-5. Спасибо!

Emma 10.05.2023 06:47

Конечно, есть библиотеки, которые предоставляют консольные функции, такие как $ или $x, для «нормального» сценария, например. github.com/WebReflection/basic-devtools/blob/main/esm/index.‌​js делает это. Кроме того, XPath претерпел значительные изменения по сравнению с XPath 1, который представляет собой всю поддержку браузера, до XPath 3.1, которую поддерживают современные библиотеки, такие как SaxonJS или FontoXPath. Например, SaxonJS.XPath.evaluate можно использовать для возврата массива.

Martin Honnen 10.05.2023 11:35

Привет @MartinHonnen, спасибо за предложение. Как установить SaxonJS в консоли Google Chrome? Будет ли работать «npm install SaxonJS»?

Emma 10.05.2023 16:42
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
12
106
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

введите это в консоль:

document.querySelector(".wikitable >  tbody").children[6];

Спасибо! Цель моего вопроса - выполнить поиск через XPath, потому что для моей отрасли (QA Selenium Development) у нас часто нет такой роскоши, как использование селекторов CSS. Иногда фронтенд-разработчики создавали веб-сайт с огромными таблицами и без атрибутов (без класса и без идентификатора). Единственный способ найти что-то — это использовать xpath для поиска нужных текстов в строке таблицы. Селекторы CSS не работают с текстовыми узлами.

Emma 10.05.2023 03:57

Я обновил свой пост, чтобы выполнить текстовый поиск XPath. Это сработает, если вы вставите коды в Chrome. Спасибо!

Emma 10.05.2023 03:57

Как бы вы использовали CssSelector для получения трех узлов «NumberTwo»? Получив три узла, как бы вы напрямую получили доступ к 3-му узлу (узлу «Месси»)? Кстати, пять текстовых узлов не обязательно расположены в <ul><li>, они с одинаковой вероятностью могут быть заключены в <ol><li> или <table><tr>.

Учитывая HTML, который вы показываете в своих изменениях, например:

const allNodes = Array.from(document.querySelectorAll(`ul li, ol li, table tr`))
const allNumberTwoNodes = allNodes.filter(e =>
                              e.textContent.includes(`NumberTwo`)
                          );
console.info(allNumberTwoNodes);
<html>
  <body>
    <ul>
      <li>NumberOne</li>
      <li>NumberTwo_Mbappe</li>
      <li>NumberOne</li>
      <li>NumberTwo_Ronaldo</li>
      <li>NumberTwo_Messi</li>
    </ul>

    <ol>
      <li>NumberOne</li>
      <li>NumberTwo_Mbappe</li>
      <li>NumberOne</li>
      <li>NumberTwo_Ronaldo</li>
      <li>NumberTwo_Messi</li>
    </ol>
    
    <table>
      <tr><td>NumberOne</td></tr>
      <tr><td>NumberTwo_Mbappe</td></tr>
      <tr><td>NumberOne</td></tr>
      <tr><td>NumberTwo_Ronaldo</td></tr>
      <tr><td>NumberTwo_Messi</td></tr>
    </table>
  </body>
</html>

Здесь мы полагаемся на textContent, который дает нам (что неудивительно) текстовое содержимое узла, игнорируя теги, поэтому, хотя в этих строках таблицы есть ячейки данных таблицы, textContent <tr> дает нам строку, как если бы <td> разметки нет.

Кроме того, узлы «NumberTwo» не обязательно являются 2-м, 4-м и 5-м узлами; они с одинаковой вероятностью могут оказаться на позициях 1-2-5, 1-4-5 или 3-4-5.

Селекторы запросов, как и XPath, не заботятся о том, в каком порядке находится HTML, они будут находить «то, что соответствует», а не «то, что находится в x-й позиции» (если вы не запекаете дочернюю позицию в селектор, как XPath).

Спасибо, Майк. Я обновил свой пример HTML. Как бы вы использовали CssSelector, чтобы найти три «NumberTwo» в «SectionTwo», пропуская те, что в «SectionOne»? Спасибо.

Emma 10.05.2023 17:06

Сначала исправив этот HTML, потому что <ul> позволяет только <li> быть дочерними, а не текст. Кроме того, не могли бы вы отредактировать свой пост, чтобы просто показать примеры реальных данных, с которыми вы работаете? HTML, который вы показываете, не имеет классов, хотя страница, о которой вы спрашивали, имеет: использование селекторов запросов является одной из основ современной веб-работы, поэтому вопрос «как выбрать X из HTML Y» почти наверняка встретится с « просто посмотрев, как запросить-выбрать для этого "с миллионами сообщений на SO уже и тоннами руководств в Интернете. Так что ваш пост должен быть о вашей конкретной проблеме, а не только вроде =)

Mike 'Pomax' Kamermans 10.05.2023 17:08

Исправлено с помощью <div>.

Emma 10.05.2023 17:11

Привет Майк, я использовал реальные данные. Для внутренних веб-сайтов компании веб-разработчики не заботятся о классах, идентификаторах или атрибутах. Они пытаются доставить работающий веб-сайт в кратчайшие сроки. (Спросите любого разработчика Selenium, как часто он сталкивался с таким веб-сайтом.) Мы не можем просить веб-разработчиков изменить веб-сайты, потому что у них нет времени.

Emma 10.05.2023 17:18

Привет, Майк, даже на многомиллиардных веб-сайтах часто есть элементы, которые можно отличить только по тексту. Попробуйте этот сайт: quora.com/What-is-the-average-cost-of-a-laptop. Quora недавно добавила новый узел «Sage» вверху. Как бы вы использовали CSS, чтобы найти это? Конечно, вы можете получить все узлы, а затем Array.filter(). Но что, если я создаю свой XPath (или Css) на вкладке «Элемент» и не хочу переключаться между «Элементом» и «Консолью»? Можем ли мы запустить JavaScript на вкладке «Элемент»?

Emma 10.05.2023 17:25

Попытка упростить пример HTML Вопроса, вернув его... если вам нужен исходный HTML, вот вам: <html> <body> <div> SectionOne <div>NumberOne</div> <div>NumberTwo_MbappeSectionOne</div> <div>NumberOne</div> <div>NumberTwo_RonaldoSectionOne</div> <div>NumberTwo_MessiSectionOne</div> </div> <div> SectionTwo <div>NumberOne</div> <div>NumberTwo_MbappeSectionTwo</div> <div>NumberOne</div> <div>NumberTwo_RonaldoSectionTwo</div> <div>NumberTwo_MessiSectionTwo</div> </div> </body> </html>

Emma 10.05.2023 17:52

Пожалуйста, не используйте ветки комментариев для подробностей сообщения: просто укажите эти сведения в своем сообщении. Поскольку вы на самом деле не разговариваете со «мной», когда предоставляете подробности, вы разговариваете со всеми, кто может помочь ответить на ваш пост, и они не увидят, что вы сказали, если вы скажете это в комментариях. (Помните правила публикации).

Mike 'Pomax' Kamermans 10.05.2023 18:20
Ответ принят как подходящий

Это получит третий элемент в вашем примере:

let v = [...new Array(3)].map( () => xpathIterator.iterateNext() ); 
v[2];

Другие вопросы по теме