I'm writing a Chrome extension that will search the DOM and highlight all email addresses on the page. I found this to look for at symbols on the page but it only returns correctly when there is one email address, it breaks when there are multiple addresses found.
found = document.evaluate('//*[contains(text(),"@")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);
What is the correct way to have this return multiples if more than one is found?
If you want to handle multiple results, don’t call .snapshotItem(0)
on document.evaluate()
but instead loop through the results using a for
loop and snapshotLength()
:
snapshotLength()
with 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) );
}
Either that, or specify the XPathResult.UNORDERED_NODE_ITERATOR_TYPE
argument (instead of XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
), and use a while
loop with 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 );
}
In cases that are sorta the reverse of the one in this question—cases when you really do want just get the first matching node—you can specify the XPathResult.FIRST_ORDERED_NODE_TYPE
value, to return just a single node, and then use the property (not method) singleNodeValue
:
XPathResult.FIRST_ORDERED_NODE_TYPE
and singleNodeValue
var firstMatchingNode = document.evaluate('// [contains(text(),"@")]',
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null );
console.dir( firstMatchingNode.singleNodeValue );
Note that among the other values (constants) you can specify as the second-to-last argument to document.evaluate()
to get other results types, you can make it directly return:
XPathResult.STRING_TYPE
) slurped from some part of the documentXPathResult.NUMBER_TYPE
); for example, a count of the number of
e-mail addresses found in the documentXPathResult.BOOLEAN_TYPE
) representing some true/false aspect of the document; e.g., an indicator whether or not the document contains any e-mail addressesOf course to get those other result types back, the XPath expression you give as the first argument to document.evaluate()
needs to be an expression that will actually return a string, or a number, or a boolean value (instead of returning a set of attribute nodes or element nodes).
The examples above are all based on the MDN Introduction to using XPath in JavaScript tutorial, which is highly recommended to anybody trying to work with XPath and document.evaluate()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With