function getElementByXPath(path, context=null, document=null, namespaceResolver=null, first_ordered=true) {
if (context === null) context = window.document.documentElement;
if (document === null) document = context.ownerDocument;
if (namespaceResolver === null) namespaceResolver = document.createNSResolver(context);
const result = document.evaluate(
path,
context,
namespaceResolver,
first_ordered ? XPathResult.FIRST_ORDERED_NODE_TYPE : XPathResult.ANY_UNORDERED_NODE_TYPE,
null);
return result.singleNodeValue || null;
}
function getElementsByXPath(path, context=null, document=null, namespaceResolver=null, ordered=true) {
if (context === null) context = window.document.documentElement;
if (document === null) document = context.ownerDocument;
if (namespaceResolver === null) namespaceResolver = document.createNSResolver(context);
const result = document.evaluate(
path,
context,
namespaceResolver,
ordered ? XPathResult.ORDERED_NODE_SNAPSHOT_TYPE : XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
return Array.from(new Proxy(result, {
get(target, property, receiver) {
if (typeof property === "string") {
if (property === "length") return target.snapshotLength;
if (!isNaN(property)) return target.snapshotItem(property);
}
return Reflect.get(...arguments);
}
}));
}
// Alternate possibilities:
function getElementsByXPath(path, context=null, document=null, namespaceResolver=null, ordered=true, snapshot=true) {
if (context === null) context = window.document.documentElement;
if (document === null) document = context.ownerDocument;
if (namespaceResolver === null) namespaceResolver = document.createNSResolver(context);
if (!snapshot) {
// Optional codepath to allow streaming iteration
const result = document.evaluate(
path,
context,
namespaceResolver,
ordered ? XPathResult.ORDERED_NODE_ITERATOR_TYPE : XPathResult.UNORDERED_NODE_ITERATOR_TYPE,
null);
return Object.assign(result, ({
next() {
const value = this.iterateNext();
return { value, done: !value };
},
[Symbol.iterator]() {
return this;
}
}));
}
const result = document.evaluate(path,
context,
namespaceResolver,
ordered ? XPathResult.ORDERED_NODE_SNAPSHOT_TYPE : XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
return Array.from(new Proxy(result, {
get(target, property, receiver) {
if (typeof property === "string") {
if (property === "length") return target.snapshotLength;
if (!isNaN(property)) return target.snapshotItem(property);
}
return Reflect.get(...arguments);
/*
// TODO compare performance:
return Array.from(Object.assign(result, {
[Symbol.iterator]() {
var i = 0;
return {
next() {
const value = this.snapshotItem(i++);
return { value, done: !value };
}
};
}
}));
*/
}