跟着 MDN 学 HTML day_53:(深入理解 XPathResult 接口)
在前几篇文章中,我们学习了 XPathEvaluator 和 XPathExpression 接口,掌握了如何编译和执行 XPath 表达式。今天我们将聚焦于 XPath 查询的最终产物:XPathResult 接口。
XPathResult 接口代表了在给定节点上下文中对 XPath 表达式求值后生成的结果。由于 XPath 表达式可以产生多种类型的结果,例如数值、字符串、布尔值或节点集合,这个接口提供了相应的属性和方法来处理不同类型的结果。理解 XPathResult 的完整能力,对于高效使用 XPath 至关重要。
一、XPathResult 概述
XPathResult 是一个基线广泛可用的接口,它封装了 XPath 表达式求值后的所有信息。每当调用 evaluate() 方法时,都会返回一个 XPathResult 对象。
这个接口的核心设计理念是:通过 resultType 属性判断结果的具体类型,然后根据类型使用对应的属性来获取值。例如,如果结果是数值类型,就读取 numberValue 属性;如果是布尔类型,就读取 booleanValue 属性。这种设计确保了类型安全的数据访问。
示例:创建 XPathResult 对象
constxpath="//div";constresult=document.evaluate(xpath,document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);console.log(resultinstanceofXPathResult);// trueconsole.log(result.resultType);// 7,对应 ORDERED_NODE_SNAPSHOT_TYPEconsole.log(result.snapshotLength);// 文档中 div 的数量每个 XPath 查询都会返回这样一个结果对象,接下来我们将逐一学习它的各种属性和方法。
二、XPathResult.resultType 属性
定义
resultType 是一个只读属性,返回一个整数值,表示结果的类型。这个整数值对应 XPathResult 接口中定义的类型常量。通过检查 resultType,我们可以在运行时判断结果的具体形式,并采取相应的处理逻辑。
类型常量对照表
| 常量名称 | 值 | 描述 |
|---|---|---|
| ANY_TYPE | 0 | 任意类型,由表达式自然决定 |
| NUMBER_TYPE | 1 | 单个数值结果 |
| STRING_TYPE | 2 | 单个字符串结果 |
| BOOLEAN_TYPE | 3 | 单个布尔值结果 |
| UNORDERED_NODE_ITERATOR_TYPE | 4 | 无序节点迭代器 |
| ORDERED_NODE_ITERATOR_TYPE | 5 | 有序节点迭代器 |
| ORDERED_NODE_SNAPSHOT_TYPE | 6 | 无序节点快照 |
| ORDERED_NODE_SNAPSHOT_TYPE | 7 | 有序节点快照 |
| ANY_UNORDERED_NODE_TYPE | 8 | 任意单个匹配节点 |
| FIRST_ORDERED_NODE_TYPE | 9 | 第一个匹配节点 |
| 示例:判断结果是否为节点集类型 |
<div>XPath example</div><div>Is XPath result a node set:<output></output></div>constxpath="//div";constresult=document.evaluate(xpath,document,null,XPathResult.ANY_TYPE,null);// 判断结果是否为节点集类型(类型 4 到 9)constisNodeSet=result.resultType>=XPathResult.UNORDERED_NODE_ITERATOR_TYPE&&result.resultType<=XPathResult.FIRST_ORDERED_NODE_TYPE;document.querySelector("output").textContent=isNodeSet;// 输出:true通过 resultType 属性,我们可以在处理结果之前先确认其类型,从而避免访问不匹配的属性时抛出异常。
三、XPathResult.numberValue 属性
定义
numberValue 是一个只读属性,当 resultType 为 NUMBER_TYPE 时,返回结果的数值。这个属性通常与 XPath 的聚合函数(如 count()、sum()、floor() 等)一起使用。
异常说明
如果 resultType 不是 NUMBER_TYPE,访问 numberValue 会抛出 TYPE_ERR 类型的 DOMException。
示例:使用 count 函数统计节点数量
<div>XPath example</div><div>Number of<div>s:<output></output></div>constxpath="count(//div)";constresult=document.evaluate(xpath,document,null,XPathResult.NUMBER_TYPE,null);// 获取数值结果constdivCount=result.numberValue;document.querySelector("output").textContent=divCount;// 输出:2在这个例子中,我们使用 XPath 的 count() 函数统计文档中所有
示例:使用 sum 函数计算总和
<divdata-value="10">项目A</div><divdata-value="25">项目B</div><divdata-value="15">项目C</div><div>总和:<output></output></div>constxpath="sum(//div/@data-value)";constresult=document.evaluate(xpath,document,null,XPathResult.NUMBER_TYPE,null);document.querySelector("output").textContent=result.numberValue;// 输出:50XPath 的数值计算能力使得我们在处理数据属性时无需手动遍历节点,一行表达式就能完成统计工作。
四、XPathResult.stringValue 属性
定义
stringValue 是一个只读属性,当 resultType 为 STRING_TYPE 时,返回结果的字符串值。如果 resultType 不是 STRING_TYPE,访问该属性会抛出 TYPE_ERR 异常。
示例:获取节点的文本内容
<divclass="message">Hello World</div><div>文本内容:<output></output></div>constxpath="string(//div[@class='message'])";constresult=document.evaluate(xpath,document,null,XPathResult.STRING_TYPE,null);document.querySelector("output").textContent=result.stringValue;// 输出:Hello WorldstringValue 属性非常适合用于提取特定节点的文本内容,或者获取属性值的字符串表示。
五、XPathResult.booleanValue 属性
定义
booleanValue 是一个只读属性,当 resultType 为 BOOLEAN_TYPE 时,返回结果的布尔值。这个属性通常与 XPath 的逻辑函数(如 not()、true()、false())或条件表达式一起使用。
示例:判断文本是否匹配
<div>XPath example</div><p>Text is 'XPath example':<output></output></p>constxpath="//div/text() = 'XPath example'";constresult=document.evaluate(xpath,document,null,XPathResult.BOOLEAN_TYPE,null);document.querySelector("output").textContent=result.booleanValue;// 输出:true在这个例子中,XPath 表达式判断
示例:判断是否存在特定元素
<divclass="active">活跃项</div><div>存在活跃项:<output></output></div>constxpath="boolean(//div[@class='active'])";constresult=document.evaluate(xpath,document,null,XPathResult.BOOLEAN_TYPE,null);document.querySelector("output").textContent=result.booleanValue?"是":"否";// 输出:是布尔类型的查询在条件判断场景中非常实用,可以快速确认某个节点或状态是否存在。
六、XPathResult.singleNodeValue 属性
定义
singleNodeValue 是一个只读属性,返回结果中的单个节点。如果结果类型为 ANY_UNORDERED_NODE_TYPE 或 FIRST_ORDERED_NODE_TYPE,该属性将返回匹配的节点对象。如果没有匹配的节点,返回 null。
示例:获取第一个匹配的节点
<divclass="item">第一项</div><divclass="item">第二项</div><divclass="item">第三项</div><div>第一项内容:<output></output></div>constxpath="//div[@class='item']";constresult=document.evaluate(xpath,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null);constfirstNode=result.singleNodeValue;if(firstNode){document.querySelector("output").textContent=firstNode.textContent;}// 输出:第一项singleNodeValue 非常适合只需要获取单个节点的场景,比如获取某个特定配置元素或检查某个节点是否存在。
七、XPathResult.snapshotLength 属性
定义
snapshotLength 是一个只读属性,返回结果快照中的节点数量。当结果类型为 UNORDERED_NODE_SNAPSHOT_TYPE 或 ORDERED_NODE_SNAPSHOT_TYPE 时,这个属性表示匹配节点的总数。
示例:获取节点快照的数量
<divclass="box">A</div><divclass="box">B</div><divclass="box">C</div><div>节点总数:<output></output></div>constxpath="//div[@class='box']";constresult=document.evaluate(xpath,document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);document.querySelector("output").textContent=result.snapshotLength;// 输出:3快照类型的结果一次性捕获了所有匹配节点,之后即使 DOM 发生变化,快照中的数据也不会改变,这为数据的一致性提供了保障。
八、XPathResult.snapshotItem() 方法
定义
snapshotItem(index) 方法返回快照集合中指定索引位置的节点。索引从 0 开始,如果索引超出范围则返回 null。
与迭代器不同,快照不会因为 DOM 的修改而失效,但它可能不再反映当前文档的最新状态。这意味着快照适用于需要稳定数据快照的场景。
示例:遍历快照中的所有节点
<ul><liclass="task">任务1</li><liclass="task">任务2</li><liclass="task">任务3</li></ul><ulid="output-list"></ul>constxpath="//li[@class='task']";constresult=document.evaluate(xpath,document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);constoutputList=document.getElementById("output-list");// 遍历快照中的所有节点for(leti=0;i<result.snapshotLength;i++){constnode=result.snapshotItem(i);constnewItem=document.createElement("li");newItem.textContent=`快照项${i}:${node.textContent}`;outputList.appendChild(newItem);}通过组合使用 snapshotLength 和 snapshotItem(),我们可以方便地遍历所有匹配节点,而不用担心遍历过程中 DOM 发生变化导致的问题。
九、XPathResult.iterateNext() 方法
定义
iterateNext() 方法用于迭代节点集结果中的下一个节点。如果结果类型是 UNORDERED_NODE_ITERATOR_TYPE 或 ORDERED_NODE_ITERATOR_TYPE,每次调用该方法都会返回集合中的下一个节点,直到返回 null 表示迭代结束。
示例:使用迭代器遍历节点
<divclass="number">一</div><divclass="number">二</div><divclass="number">三</div><ulid="iter-result"></ul>constxpath="//div[@class='number']";constresult=document.evaluate(xpath,document,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);constoutputList=document.getElementById("iter-result");letnode;// 使用迭代器依次获取节点while((node=result.iterateNext())){constnewItem=document.createElement("li");newItem.textContent=`迭代项:${node.textContent}`;outputList.appendChild(newItem);}迭代器类型的优势在于按需获取节点,不需要一次性创建所有节点的快照,在处理大量节点时可能更节省内存。
十、XPathResult.invalidIteratorState 属性
定义
invalidIteratorState 是一个只读属性,用于指示迭代器是否已失效。当 resultType 为 UNORDERED_NODE_ITERATOR_TYPE 或 ORDERED_NODE_ITERATOR_TYPE 时,如果在结果返回后文档被修改,该属性会变为 true,表示迭代器不再可靠。
示例:检测迭代器状态
<div>XPath example</div><p>Iterator state:<output></output></p>constxpath="//div";constresult=document.evaluate(xpath,document,null,XPathResult.ANY_TYPE,null);// 在迭代之前删除一个 div,使迭代器失效document.querySelector("div").remove();// 检查迭代器状态document.querySelector("output").textContent=result.invalidIteratorState?"invalid":"valid";// 输出:invalid这个属性的存在提醒我们,迭代器类型的 XPath 结果与 DOM 的当前状态紧密关联。如果预计在获取结果后可能会修改 DOM,使用快照类型(SNAPSHOT)会是更安全的选择。
十一、快照与迭代器的选择
在实际开发中,选择合适的 XPath 结果类型非常重要。快照类型和迭代器类型有各自的适用场景。
示例:对比快照和迭代器的行为
<divclass="test">A</div><divclass="test">B</div><divclass="test">C</div><buttonid="modify-btn">删除第一个节点</button><div><p>快照结果数量:<outputid="snapshot-output"></output></p><p>迭代器状态:<outputid="iterator-output"></output></p></div>// 快照类型constsnapshotResult=document.evaluate("//div[@class='test']",document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);// 迭代器类型constiteratorResult=document.evaluate("//div[@class='test']",document,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);document.getElementById("modify-btn").addEventListener("click",()=>{constfirstDiv=document.querySelector(".test");if(firstDiv)firstDiv.remove();// 快照数量不变document.getElementById("snapshot-output").textContent=snapshotResult.snapshotLength;// 迭代器状态变为失效document.getElementById("iterator-output").textContent=iteratorResult.invalidIteratorState?"已失效":"有效";});快照适合需要稳定数据视图的场景,迭代器适合只需一次性顺序读取且内存敏感的场合。根据具体需求选择合适的类型,可以让代码更加健壮。
十二、总结
今天的学习内容全面覆盖了 XPathResult 接口的方方面面。我们从 resultType 属性入手,了解了十种结果类型的含义和用途。随后逐一学习了 numberValue、stringValue、booleanValue、singleNodeValue、snapshotLength 等只读属性,以及 snapshotItem() 和 iterateNext() 两个实例方法。最后还探讨了 invalidIteratorState 属性以及快照与迭代器的选择策略。
XPathResult 是 XPath 查询流程的终点,也是我们获取查询结果的关键接口。掌握它的各种属性和方法,能够让我们在处理 XPath 查询结果时更加得心应手,写出更高效、更健壮的代码。
结合前面学习的 XPathEvaluator 和 XPathExpression,现在我们已经完整掌握了浏览器环境中 XPath 查询的整个流程:从创建求值器、编译表达式,到执行查询、处理结果。这套完整的知识体系将为后续的 DOM 高级操作打下坚实的基础。
想要解锁更多HTML 核心标签实战、前端零基础入门干货、开发避坑全指南吗?
持续关注,后续将更新CSS 布局实战、JavaScript 交互基础、全站导航开发等硬核内容,带你从新手快速进阶,轻松搞定前端开发!
