当我使用querySelectorAll
时,我可以在示例文档中找到138个td
个节点。
Array.from(document.querySelectorAll('td')).length
138
当我对XPath做同样的事情时,我得不到任何结果:
Array.from(document.evaluate(".//td", document.body, null, XPathResult.ANY_TYPE, null)).length
0
虽然至少有一场比赛:
document.evaluate(".//td", document.body, null, XPathResult.ANY_TYPE, null).iterateNext().nodeName
"TD"
问题似乎是Array.from
无法迭代XPathResult
。即便这样也会返回0:
Array.from(document.evaluate('.', document.body, null, XPathResult.ANY_TYPE, null)).length
0
如何使XPathResult
适合Array.from
?
答案 0 :(得分:4)
不幸的是你做不到。 Array.from
可以将两种类型的对象转换为数组:
.length
属性的“数组类似”。 XPathResult
没有做任何这些。您可以通过手动迭代结果并将结果存储在数组中来实现:
const nodes = [];
let node = xPathResult.iterateNext();
while (node) {
nodes.push(node);
node = xPathResult.iterateNext();
}
...但是如果你要在节点上循环,你可以在循环中做你想要做的任何数组操作。
答案 1 :(得分:0)
正如现有答案所述,这本身并不“受支持”,因为(出于某种奇怪的原因)XPathResult
不支持 iterable protocol,即使您使用 ORDERED_NODE_ITERATOR_TYPE
.
如果您真的想将有序节点迭代器类型 XPath 结果用作 JavaScript 迭代器,那么这当然是可行的:
xpr => ({[Symbol.iterator]: () => ({next: () => {
let node = xpr.iterateNext();
return {value: node, done: !node}
}})})
这自然适用于您的用例Array.from
:
// As an example, pull the top child elements -- should just be the <head> and <body>
let example = document.evaluate('/html/*', document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
Array.from((xpr => ({[Symbol.iterator]: () => ({next: () => {
let node = xpr.iterateNext();
return {value: node, done: !node}
}})}))(example))
...不过,它也支持for...of
:
let example2 = document.evaluate('/html/*', document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
for( let e of (xpr => ({[Symbol.iterator]: () => ({next: () => {
let node = xpr.iterateNext();
return {value: node, done: !node}
}})}))(example2) ) {
// It's iterable!
console.log(e.tagName);
}
因此,这个解决方案稍微更通用(并且在不实例化数组的情况下迭代大量节点时,它也应该使用更少的内存)。