如何将 Array.from 与 XPathResult 一起使用?

cev*_*ing 2 javascript arrays xpath

当我使用 时querySelectorAll,我可以td在我的示例文档中找到 138 个节点。

Array.from(document.querySelectorAll('td')).length
138
Run Code Online (Sandbox Code Playgroud)

当我对 XPath 做同样的事情时,我没有得到任何结果:

Array.from(document.evaluate(".//td", document.body, null, XPathResult.ANY_TYPE, null)).length
0
Run Code Online (Sandbox Code Playgroud)

虽然至少有一场比赛:

document.evaluate(".//td", document.body, null, XPathResult.ANY_TYPE, null).iterateNext().nodeName
"TD"
Run Code Online (Sandbox Code Playgroud)

问题似乎是Array.from无法迭代 a XPathResult。即使这样也返回 0:

Array.from(document.evaluate('.', document.body, null, XPathResult.ANY_TYPE, null)).length
0
Run Code Online (Sandbox Code Playgroud)

如何制作XPathResult适合的Array.from

Exp*_*lls 8

不幸的是你不能。Array.from可以将两种类型的对象转换为数组:

  1. 那些具有.length属性的“类数组” 。
  2. 实现迭代器协议并允许您获取所有元素的那些。

XPathResult不做任何这些。您可以通过手动迭代结果并将结果存储在一个数组中来做到这一点,例如:

const nodes = [];
let node = xPathResult.iterateNext();
while (node) {
  nodes.push(node);
  node = xPathResult.iterateNext();
}
Run Code Online (Sandbox Code Playgroud)

...但如果你无论如何都要循环遍历节点,你可能可以在循环中执行任何你想做的数组操作。

  • 为了避免重复并(imo)使其更清晰,您可以改为执行 `const Nodes = []; 让节点;while (node = xPathResult.iterateNext()) {nodes.push(node);}`。太糟糕了,你不能只说“while (const node = xPathResult.iterateNext()) {...}”,因为该值不在循环之外使用。 (2认同)

Sér*_*lho 5

根据@JamesTheAwesomeDude答案,如果将迭代器填充到 XPathResult 上,则可以使用Array.from(或扩展运算符)。这个迭代器稍微好一点,因为它可以对所有类型的 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;
    }
};
Run Code Online (Sandbox Code Playgroud)