Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Array.from with a XPathResult?

When I use querySelectorAll, I can find 138 td nodes in my sample document.

Array.from(document.querySelectorAll('td')).length
138

When I do the same with XPath, I get no result:

Array.from(document.evaluate(".//td", document.body, null, XPathResult.ANY_TYPE, null)).length
0

Although there is at least one match:

document.evaluate(".//td", document.body, null, XPathResult.ANY_TYPE, null).iterateNext().nodeName
"TD"

The problem seems to be that Array.from can not iterate over a XPathResult. Even this returns 0:

Array.from(document.evaluate('.', document.body, null, XPathResult.ANY_TYPE, null)).length
0

How to make a XPathResult suitable for Array.from?

like image 676
ceving Avatar asked Dec 15 '25 18:12

ceving


2 Answers

Unfortunately you can't. Array.from can convert two types of objects into arrays:

  1. Those that are "array-like" that have a .length property.
  2. Those that implement the iterator protocol and allow you to get all of their elements.

XPathResult doesn't do any of these. You could do this by manually iterating over the result and storing the results in an array such as:

const nodes = [];
let node;

while ((node = xPathResult.iterateNext())) {
  nodes.push(node);
}

...but if you're going to loop over the nodes anyway, you can probably do whatever array operations you wanted to do in the loop.

like image 134
Explosion Pills Avatar answered Dec 17 '25 08:12

Explosion Pills


Building up on the answer from @JamesTheAwesomeDude, you can use Array.from (or the spread operator) if you polyfill the iterator onto XPathResult. This iterator is just a bit better because it can operate on all types of XPathResult:

if (!XPathResult.prototype[Symbol.iterator]) XPathResult.prototype[Symbol.iterator] = function* () {
    switch (this.resultType) {
        case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
        case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
            let result;
            while ( (result = this.iterateNext()) != null ) yield result;
            break;
        case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
        case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
            for (let i=0; i < this.snapshotLength; i++) yield this.snapshotItem(i);
            break;
        default:
            yield this.singleNodeValue;
            break;
    }
};
like image 25
Sérgio Carvalho Avatar answered Dec 17 '25 08:12

Sérgio Carvalho



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!