Поиск 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(); } })());
}
Наслаждаться...