XPath 代码片段
本文提供了一些 XPath 代码片段,这些片段是关于如何基于来自DOM Level 3 XPath 规范的标准接口构建一些简单的**实用程序函数**的简单示例,这些接口将 XPath 功能公开给 JavaScript 代码。这些代码片段是可以用于您自己代码中的真实世界函数。
特定于节点的评估器函数
以下自定义实用程序函数可用于评估给定 XML 节点上的 XPath 表达式。第一个参数是 DOM 节点或 Document 对象,第二个参数是定义 XPath 表达式的字符串。
示例:定义自定义特定于节点的 evaluateXPath()
实用程序函数
js
// Evaluate an XPath expression aExpression against a given DOM node
// or Document object (aNode), returning the results as an array
// thanks wanderingstan at morethanwarm dot mail dot com for the
// initial work.
function evaluateXPath(aNode, aExpr) {
const xpe = new XPathEvaluator();
const nsResolver =
aNode.ownerDocument === null
? aNode.documentElement
: aNode.ownerDocument.documentElement;
const result = xpe.evaluate(aExpr, aNode, nsResolver, 0, null);
const found = [];
let res;
while ((res = result.iterateNext())) found.push(res);
return found;
}
请注意,只有在您确定 XPath 表达式中的命名空间前缀与您要查询的文档中的命名空间前缀匹配(并且没有使用默认命名空间)时,才应使用 documentElement
。否则,您必须提供您自己的 XPathNSResolver 实现。
示例用法
假设我们有以下 XML 文档(另请参阅解析和序列化 XML)
示例:要与自定义 evaluateXPath()
实用程序函数一起使用的 XML 文档
xml
<?xml version="1.0"?>
<people>
<person first-name="eric" middle-initial="H" last-name="jung">
<address street="321 south st" city="denver" state="co" country="usa"/>
<address street="123 main st" city="arlington" state="ma" country="usa"/>
</person>
<person first-name="jed" last-name="brown">
<address street="321 north st" city="atlanta" state="ga" country="usa"/>
<address street="123 west st" city="seattle" state="wa" country="usa"/>
<address street="321 south avenue" city="denver" state="co" country="usa"/>
</person>
</people>
现在,您可以使用 XPath 表达式“查询”文档。尽管遍历 DOM 树可以实现类似的结果,但使用 XPath 表达式更快且功能更强大。如果您能够依赖 id
属性,document.getElementById()
仍然功能强大,但它远不如 XPath 强大。以下是一些示例。
示例:使用自定义 evaluateXPath()
实用程序函数的 JavaScript 代码
js
// display the last names of all people in the doc
let results = evaluateXPath(people, "//person/@last-name");
for (const i in results)
console.log(`Person #${i} has the last name ${results[i].value}`);
// get the 2nd person node
results = evaluateXPath(people, "/people/person[2]");
// get all the person nodes that have addresses in denver
results = evaluateXPath(people, "//person[address/@city='denver']");
// get all the addresses that have "south" in the street name
results = evaluateXPath(people, "//address[contains(@street, 'south')]");
console.log(results.length);
docEvaluateArray
以下是一个简单的实用程序函数,用于将(有序)XPath 结果放入数组中,无论是否需要特殊的命名空间解析器等。它避免了在不需要时使用document.evaluate()
的更复杂的语法,以及在XPathResult
上使用特殊迭代器(通过返回数组而不是迭代器)。
示例:定义简单的 docEvaluateArray()
实用程序函数
js
// Example usage:
// const els = docEvaluateArray('//a');
// console.log(els[0].nodeName); // gives 'A' in HTML document with at least one link
function docEvaluateArray(expr, doc, context, resolver) {
let i;
const a = [];
doc = doc || (context ? context.ownerDocument : document);
resolver = resolver || null;
context = context || doc;
const result = doc.evaluate(
expr,
context,
resolver,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null,
);
for (let i = 0; i < result.snapshotLength; i++) {
a.push(result.snapshotItem(i));
}
return a;
}
getXPathForElement
以下函数允许传递一个元素和一个 XML 文档,以查找一个唯一的字符串 XPath 表达式,该表达式指向回该元素。
示例:定义 getXPathForElement()
实用程序函数
js
function getXPathForElement(el, xml) {
let xpath = "";
let pos, tempitem2;
while (el !== xml.documentElement) {
pos = 0;
tempitem2 = el;
while (tempitem2) {
if (tempitem2.nodeType === 1 && tempitem2.nodeName === el.nodeName) {
// If it is ELEMENT_NODE of the same name
pos += 1;
}
tempitem2 = tempitem2.previousSibling;
}
xpath = `*[name()='${el.nodeName}' and namespace-uri()='${
el.namespaceURI ?? ""
}'][${pos}]/${xpath}`;
el = el.parentNode;
}
xpath = `/*[name()='${xml.documentElement.nodeName}' and namespace-uri()='${
el.namespaceURI ?? ""
}']/${xpath}`;
xpath = xpath.replace(/\/$/, "");
return xpath;
}