当我使用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
发布于 2017-10-30 14:27:17
不幸的是,您不能这样做。Array.from
可以将两种类型的对象转换为数组:
.length
属性的“类似数组”的。XPathResult
没有做任何这些。您可以通过手动迭代结果并将结果存储在数组中来做到这一点,如:
const nodes = [];
let node = xPathResult.iterateNext();
while (node) {
nodes.push(node);
node = xPathResult.iterateNext();
}
...but --如果您无论如何都要在节点上循环,那么您可能可以在循环中执行任何您想做的数组操作。
发布于 2021-07-23 17:23:04
正如现有的答案所述,这本身并不“支持”,因为(由于一些奇怪的原因) XPathResult
根本不支持JS的标准迭代协议。
我想,你总是可以自己动手,这很自然,可以用你的用例Array.from
。
function xpr2iter (xpr) {
// Produce a JavaScript iterator for an *ITERATOR_TYPE XPathResult
// or a JavaScript iterable for a *SNAPSHOT_TYPE XPathResult
switch (xpr.resultType) {
case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
return {
[Symbol.iterator] () {
var i = 0;
return {
next() {
var node = xpr.snapshotItem(i++);
return {value: node, done: !node};
}
};
},
at(i) {
return xpr.snapshotItem(i) || undefined;
}
};
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
return {
next() {
var node = xpr.iterateNext();
return {value: node, done: !node};
},
[Symbol.iterator] () {
return this;
},
};
}
}
// As an example, pull the top child elements
// -- should just be the <head> and <body>:
let example1_xpr = document.evaluate('/html/*', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
// -- render into an Array:
let example1_arr = Array.from(xpr2iter(example1_xpr));
// Can be rendered to an array!
console.log("length:", example1_arr.length);
console.log("map demo (e => e.tagName):", example1_arr.map(e => e.tagName));
...however,它还直接支持for...of
,而不实例化整个Array
。
function xpr2iter (xpr) {
// Produce a JavaScript iterator for an *ITERATOR_TYPE XPathResult
// or a JavaScript iterable for a *SNAPSHOT_TYPE XPathResult
switch (xpr.resultType) {
case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
return {
[Symbol.iterator] () {
var i = 0;
return {
next() {
var node = xpr.snapshotItem(i++);
return {value: node, done: !node};
}
};
},
at(i) {
return xpr.snapshotItem(i) || undefined;
}
};
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
return {
next() {
var node = xpr.iterateNext();
return {value: node, done: !node};
},
[Symbol.iterator] () {
return this;
},
};
}
}
let example2_xpr = document.evaluate('/html/*', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
for( let e of xpr2iter(example2_xpr) ) {
// It's iterable!
console.log(e.tagName);
}
因此,这个解决方案稍微通用一些(并且在不实例化Array
的情况下迭代大量的节点时也应该使用更少的内存)。
我可以在我的示例文档中找到138个
td
节点。
实际上,如果这是一个A/B问题,并且您只是试图找到匹配的数量,则可以通过非迭代器类型的属性直接得到(或者您可以“手动”计算迭代器类型,如果您愿意):
function xpr2iter (xpr) {
// Produce a JavaScript iterator for an *ITERATOR_TYPE XPathResult
// or a JavaScript iterable for a *SNAPSHOT_TYPE XPathResult
switch (xpr.resultType) {
case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
return {
[Symbol.iterator] () {
var i = 0;
return {
next() {
var node = xpr.snapshotItem(i++);
return {value: node, done: !node};
}
};
},
at(i) {
return xpr.snapshotItem(i) || undefined;
}
};
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
return {
next() {
var node = xpr.iterateNext();
return {value: node, done: !node};
},
[Symbol.iterator] () {
return this;
},
};
}
}
let example3_xpr = document.evaluate('/html/*', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
let example3_n = example3_xpr.snapshotLength;
console.log("number of matches:", example3_n);
let example4_xpr = document.evaluate('/html/*', document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
let example4_n = 0;
for( let e of xpr2iter(example4_xpr) )
example4_n ++;
console.log("number of matches:", example4_n);
发布于 2022-06-08 15:10:15
在@JamesTheAwesomeDude的@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;
}
};
https://stackoverflow.com/questions/47017441
复制相似问题