Поиск DOM для кратных одной и той же строки, используя XPath

Я пишу расширение для Chrome, которое будет искать DOM и выделять все адреса электронной почты на странице. Я нашел это, чтобы искать символы на странице, но он корректно возвращается только при наличии одного адреса электронной почты, он прерывается, когда найдено несколько адресов.

found = document.evaluate('//*[contains(text(),"@")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);

Как правильно получить этот коэффициент возврата, если найдено более одного?

2 ответа

Решение

Если вы хотите обработать несколько результатов, не звоните .snapshotItem(0) на document.evaluate() но вместо этого перебрать результаты с помощью for петля и snapshotLength():

Пример: просмотр результатов с помощью snapshotLength() с snapshotItem()
var nodesSnapshot = document.evaluate('//*[contains(text(),"@")]',
    document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ )
{
  console.dir( nodesSnapshot.snapshotItem(i) );
}

Либо так, либо укажите XPathResult.UNORDERED_NODE_ITERATOR_TYPE аргумент (вместо XPathResult.ORDERED_NODE_SNAPSHOT_TYPE) и использовать while цикл с iterateNext():

Пример: перебрать результаты, используя iterateNext()
var iterator = document.evaluate('//*[contains(text(),"@")]',
    document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null );

try {
  var thisNode = iterator.iterateNext(); 
  while (thisNode) {
    console.dir( thisNode );
    thisNode = iterator.iterateNext();
  } 
}
catch (e) {
  console.log( 'Error: Document tree modified during iteration ' + e );
}

В случаях, которые в некотором роде противоположны приведенным в этом вопросе - в случаях, когда вы действительно хотите получить первый соответствующий узел - вы можете указать XPathResult.FIRST_ORDERED_NODE_TYPE значение, чтобы вернуть только один узел, а затем использовать свойство (не метод) singleNodeValue:

Пример: использование XPathResult.FIRST_ORDERED_NODE_TYPE а также singleNodeValue
var firstMatchingNode = document.evaluate('// [contains(text(),"@")]',
    document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null );

console.dir( firstMatchingNode.singleNodeValue );

Получение текста или обратного отсчета вместо этого, или тестирование истинных / ложных условий

Обратите внимание, что среди других значений (констант) вы можете указать в качестве второго-последнего аргумента document.evaluate() чтобы получить другие типы результатов, вы можете сделать это напрямую:

  • одна строка (XPathResult.STRING_TYPE) текста, взятого из некоторой части документа
  • число, представляющее счет некоторого вида (XPathResult.NUMBER_TYPE); например, подсчет количества адресов электронной почты, найденных в документе
  • логическое значение (XPathResult.BOOLEAN_TYPE) представление некоторого истинного / ложного аспекта документа; например, индикатор того, содержит ли документ какие-либо адреса электронной почты

Конечно, чтобы вернуть эти другие типы результатов, выражение XPath, которое вы даете в качестве первого аргумента document.evaluate() должно быть выражением, которое на самом деле будет возвращать строку, или число, или логическое значение (вместо того, чтобы возвращать набор узлов атрибутов или узлов элементов).


Больше в MDN

Все приведенные выше примеры основаны на MDN Введение в использование XPath в JavaScript, которое настоятельно рекомендуется всем, кто пытается работать с XPath и document.evaluate(),

С помощью приведенного ниже кода вы можете получитьXPathселектор выдает в виде массива.

      const xpath = `//*[contains(text(),"@")]`;//your special XPath
const elements = Array.from((function*(){ let iterator = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null); let current = iterator.iterateNext(); while(current){ yield current; current = iterator.iterateNext(); }  })());
//Use the simple array

Кроме того, вы можете использовать его как функцию для большего количества звонков...

      function getElementsByXPath(xpath) {
    return Array.from((function*(){ let iterator = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null); let current = iterator.iterateNext(); while(current){ yield current; current = iterator.iterateNext(); }  })());
}

Наслаждаться...

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