Я пытаюсь использовать xpath, чтобы найти узел «Месси» из приведенного ниже HTML. Чтобы свести к минимуму усилия по кодированию, я надеюсь на решение, которое использует индекс массива вместо циклического прохождения через итератор.
Я предполагаю, что самый стандартный и простой API — это XPathExpression.evaluate(). Если есть лучшие API, пожалуйста, поделитесь.
Кстати, мне нужно внести изменения в DOM Node из возвращенного результата. Таким образом, для XPathResult.resultType будет установлено значение ORDERED_NODE_ITERATOR_TYPE, и поэтому XPathResult.snapshotItem() использовать нельзя.
<html>
<body>
<div>
<div>NumberOne</div>
<div>NumberTwo_Mbappe</div>
<div>NumberOne</div>
<div>NumberTwo_Ronaldo</div>
<div>NumberTwo_Messi</div>
</div>
</body>
</html>
Выполнение приведенного ниже кода вернет итератор из приведенного выше html.
let xpathIterator = new XPathEvaluator()
.createExpression("//*[starts-with(text(), 'NumberTwo')]")
.evaluate(
document,
XPathResult.ORDERED_NODE_ITERATOR_TYPE
);
Существующий интерфейс XPathResult имеет только метод iterateNext(), поэтому для извлечения n-го элемента потребуется шесть строк кода:
let n = 3;
while (n > 0) {
xpathIterator.iterateNext();
n--;
}
xpathIterator.iterateNext();
Поскольку XPath и Chrome ежедневно используются миллионами людей, в идеале должен быть способ получить n-й элемент напрямую с помощью индекса массива (как показано в следующем коде). Я был бы удивлен, если бы такого API еще не существовало.
let v = xpathResult[2];
Идеальное решение не обязательно должно использовать XPathExpression.evaluate(). Я открыт для любых решений, использующих стандартные функции JavaScript, поддерживаемые Chrome.
(Надеюсь, нам не нужно использовать функцию. Если функция должна использоваться, было бы хорошо иметь не более 2-3 строк кода с ESLint-lint.)
Спасибо!
Поскольку XPathResult.resultType не является итерируемым, следующие сообщения не применяются:
Зачем вам использовать XPath при работе с HTML-страницами, а не просто использовать обычный подход к селектору запросов, например. document.querySelectorAll(`.wikitable tr`)? Нет причин рассматривать страницу как XML, если это не XML?
Привет @Earlee, Does this answer your question? How to use Array.from with a XPathResult? Array.from() не работает, потому что для этого требуется итерируемый или подобный массиву объект. Объекты, подобные массивам, должны иметь свойство «длина».
@Emma Эмма, да, там обсуждается, как вы можете преобразовать его в массив, создав свою собственную функцию. тогда вы, наконец, можете индексировать массив.
Привет, @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 не работают с текстовыми узлами.
Привет @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 строк кода.
Привет @Mike'Pomax'Kamermans Why would you use XPath Я обновил свой пост, чтобы выполнить текстовый поиск XPath. Это сработает, если вы вставите коды в Chrome. Спасибо!
Привет @Earlee yes they have a discussion there as to how you could convert it to array by creating your own function. Я надеюсь избежать необходимости создавать функцию, потому что коды будут запускаться в консоли Chrome, а окно Chrome будет закрываться и открываться снова сотни раз в день, а это значит, что функция понадобится создавать вручную сотни раз в день.
@Эмма, спасибо. Хотя, конечно, это все еще очень легко сделать с «не xpath» с помощью Array.from(document.querySelector(`....`)).filter(e => e.textContent.contains(`be`)), поэтому я все еще не уверен, что xpath имеет больше смысла, чем выбор запроса, а затем сопоставление/фильтрация по мере необходимости =) Это может помочь объяснить, что вы на самом деле пытаемся достичь, конкретно, на тот случай, если есть какой-нибудь простой «нормальный» JS, который может так же легко достичь этой цели.
Привет @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. Спасибо!
Конечно, есть библиотеки, которые предоставляют консольные функции, такие как $ или $x, для «нормального» сценария, например. github.com/WebReflection/basic-devtools/blob/main/esm/index.js делает это. Кроме того, XPath претерпел значительные изменения по сравнению с XPath 1, который представляет собой всю поддержку браузера, до XPath 3.1, которую поддерживают современные библиотеки, такие как SaxonJS или FontoXPath. Например, SaxonJS.XPath.evaluate можно использовать для возврата массива.
Привет @MartinHonnen, спасибо за предложение. Как установить SaxonJS в консоли Google Chrome? Будет ли работать «npm install SaxonJS»?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


введите это в консоль:
document.querySelector(".wikitable > tbody").children[6];
Спасибо! Цель моего вопроса - выполнить поиск через XPath, потому что для моей отрасли (QA Selenium Development) у нас часто нет такой роскоши, как использование селекторов CSS. Иногда фронтенд-разработчики создавали веб-сайт с огромными таблицами и без атрибутов (без класса и без идентификатора). Единственный способ найти что-то — это использовать xpath для поиска нужных текстов в строке таблицы. Селекторы CSS не работают с текстовыми узлами.
Я обновил свой пост, чтобы выполнить текстовый поиск XPath. Это сработает, если вы вставите коды в Chrome. Спасибо!
Как бы вы использовали 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»? Спасибо.
Сначала исправив этот HTML, потому что <ul> позволяет только <li> быть дочерними, а не текст. Кроме того, не могли бы вы отредактировать свой пост, чтобы просто показать примеры реальных данных, с которыми вы работаете? HTML, который вы показываете, не имеет классов, хотя страница, о которой вы спрашивали, имеет: использование селекторов запросов является одной из основ современной веб-работы, поэтому вопрос «как выбрать X из HTML Y» почти наверняка встретится с « просто посмотрев, как запросить-выбрать для этого "с миллионами сообщений на SO уже и тоннами руководств в Интернете. Так что ваш пост должен быть о вашей конкретной проблеме, а не только вроде =)
Исправлено с помощью <div>.
Привет Майк, я использовал реальные данные. Для внутренних веб-сайтов компании веб-разработчики не заботятся о классах, идентификаторах или атрибутах. Они пытаются доставить работающий веб-сайт в кратчайшие сроки. (Спросите любого разработчика Selenium, как часто он сталкивался с таким веб-сайтом.) Мы не можем просить веб-разработчиков изменить веб-сайты, потому что у них нет времени.
Привет, Майк, даже на многомиллиардных веб-сайтах часто есть элементы, которые можно отличить только по тексту. Попробуйте этот сайт: quora.com/What-is-the-average-cost-of-a-laptop. Quora недавно добавила новый узел «Sage» вверху. Как бы вы использовали CSS, чтобы найти это? Конечно, вы можете получить все узлы, а затем Array.filter(). Но что, если я создаю свой XPath (или Css) на вкладке «Элемент» и не хочу переключаться между «Элементом» и «Консолью»? Можем ли мы запустить JavaScript на вкладке «Элемент»?
Попытка упростить пример 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>
Пожалуйста, не используйте ветки комментариев для подробностей сообщения: просто укажите эти сведения в своем сообщении. Поскольку вы на самом деле не разговариваете со «мной», когда предоставляете подробности, вы разговариваете со всеми, кто может помочь ответить на ваш пост, и они не увидят, что вы сказали, если вы скажете это в комментариях. (Помните правила публикации).
Это получит третий элемент в вашем примере:
let v = [...new Array(3)].map( () => xpathIterator.iterateNext() );
v[2];
Отвечает ли это на ваш вопрос? Как использовать Array.from с XPathResult?