首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将Array.from与XPathResult结合使用?

如何将Array.from与XPathResult结合使用?
EN

Stack Overflow用户
提问于 2017-10-30 14:14:15
回答 3查看 3.7K关注 0票数 8

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

代码语言:javascript
运行
复制
Array.from(document.querySelectorAll('td')).length
138

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

代码语言:javascript
运行
复制
Array.from(document.evaluate(".//td", document.body, null, XPathResult.ANY_TYPE, null)).length
0

尽管至少有一场比赛:

代码语言:javascript
运行
复制
document.evaluate(".//td", document.body, null, XPathResult.ANY_TYPE, null).iterateNext().nodeName
"TD"

问题似乎是Array.from不能在XPathResult上迭代。即使这样,也会返回0:

代码语言:javascript
运行
复制
Array.from(document.evaluate('.', document.body, null, XPathResult.ANY_TYPE, null)).length
0

如何制作适合于XPathResultArray.from

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-10-30 14:27:17

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

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

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

代码语言:javascript
运行
复制
const nodes = [];
let node = xPathResult.iterateNext();
while (node) {
  nodes.push(node);
  node = xPathResult.iterateNext();
}

...but --如果您无论如何都要在节点上循环,那么您可能可以在循环中执行任何您想做的数组操作。

票数 14
EN

Stack Overflow用户

发布于 2021-07-23 17:23:04

正如现有的答案所述,这本身并不“支持”,因为(由于一些奇怪的原因) XPathResult根本不支持JS的标准迭代协议

我想,你总是可以自己动手,这很自然,可以用你的用例Array.from

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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问题,并且您只是试图找到匹配的数量,则可以通过非迭代器类型的属性直接得到(或者您可以“手动”计算迭代器类型,如果您愿意):

代码语言:javascript
运行
复制
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);

票数 1
EN

Stack Overflow用户

发布于 2022-06-08 15:10:15

@JamesTheAwesomeDude@JamesTheAwesomeDude基础上构建,如果您将迭代器填充到XPathResult上,则可以使用Array.from (或扩展算子)。这个迭代器更好一些,因为它可以对所有类型的XPathResult进行操作:

代码语言:javascript
运行
复制
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;
    }
};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47017441

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档