JavaScript - web browser built-in XPath API example
In this short article we would like to show how to use built-in XPath API in Web Browser JavaScript.
Simple example:
xxxxxxxxxx
<html>
<body>
<div id="element">Empty</div>
<script>
var result = document.evaluate("//*[@id='element']", document.body);
var element = result.iterateNext();
if (element) {
console.log(element.outerHTML);
}
</script>
</body>
</html>
Note: above example shows how to get element by id with XPath.
XPath 1.0 appeard in 1990. Since begining 3 additional versions of XPath appeard: 2.0 in 2007, 3.0 in 2014 and 3.1 in 2017. The web browsers that provide XPath API are: Chrome, Firefox, Edge, Opera, Internet Explorer, and Safari.
As once of web browsers, Internet Explorer provides different API for XPath usage - at this time IE is not supported and it is not recommended to support that browser in web projects (we have 2020). So we will not focus on, how to use XPath in IE.
Practical example:
xxxxxxxxxx
<html>
<body>
<div id="element">
<span class="text">Empty</span>
<span class="text">Some text ...</span>
<span class="info">Empty</span>
<span class="info">Some text ...</span>
</div>
<script>
var element = document.querySelector('#element');
var result = document.evaluate("//span[@class='text']", element);
var element = null;
while (element = result.iterateNext()) {
console.log(element.outerHTML);
}
</script>
</body>
</html>
The example shows how to get elements by class name and containing text using XPath.
xxxxxxxxxx
<html>
<body>
<div id="element">
<span class="text">Empty</span>
<span class="text">Some text ...</span>
<span class="info">Empty</span>
<span class="info">Some text ...</span>
</div>
<script>
var element = document.querySelector('#element');
var result1 = document.evaluate("//span", element);
var result2 = document.evaluate("//span[@class='text']", element);
var result3 = document.evaluate("//span[@class='info']", element);
var result4 = document.evaluate("//span[text()='Some text ...']", element);
function printElements(result) {
var element = null;
while (element = result.iterateNext()) {
console.log(' ' + element.outerHTML);
}
}
console.log('\n//span -------------------------------------');
printElements(result1);
console.log('\n//span[@class=\'text\'] --------------------');
printElements(result2);
console.log('\n//span[@class=\'info\'] --------------------');
printElements(result3);
console.log('\n//span[text()=\'Some text ...\'] -----------');
printElements(result4);
</script>
</body>
</html>
Note: when we use AJAX,
document
can be replaced withxhr.responseXML
object.
Sometimes it is necessary to to find XML Document before XPath querring. That situation appears when we have node that can be located in different document. The solution is to use documentElement
property that can be used to create XPath evaluator.
Check below example to see how it works:
xxxxxxxxxx
<html>
<body>
<div id="element">
<span class="text">Empty</span>
<span class="text">Some text ...</span>
<span class="info">Empty</span>
<span class="info">Some text ...</span>
</div>
<script>
function findDocument(node) {
var tmp = node.ownerDocument || node;
return tmp.documentElement;
}
function NodeEvaluator(node) {
var document = findDocument(node);
var evaluator = new XPathEvaluator();
var resolver = evaluator.createNSResolver(document);
this.evaluate = function(expression) {
return evaluator.evaluate(expression, node, resolver, XPathResult.ANY_TYPE, null);
};
}
var element = document.querySelector('#element');
var evaluator = new NodeEvaluator(element);
var result1 = evaluator.evaluate("//span");
var result2 = evaluator.evaluate("//span[@class='text']");
var result3 = evaluator.evaluate("//span[@class='info']");
var result4 = evaluator.evaluate("//span[text()='Some text ...']");
function printElements(result) {
var element = null;
while (element = result.iterateNext()) {
console.log(' ' + element.outerHTML);
}
}
console.log('\n//span -------------------------------------');
printElements(result1);
console.log('\n//span[@class=\'text\'] --------------------');
printElements(result2);
console.log('\n//span[@class=\'info\'] --------------------');
printElements(result3);
console.log('\n//span[text()=\'Some text ...\'] -----------');
printElements(result4);
</script>
</body>
</html>