XPath 片段
本文件提供了一些 XPath 程式碼片段——有關如何實現幾個實用函式的示例。這些函式基於公開 XPath 功能供 JavaScript 程式碼使用的標準介面。這些片段是您可以在實際程式碼中使用的函式。
特定於節點的求值函式
以下自定義實用函式可用於對給定的 XML 節點評估 XPath 表示式。第一個引數是 DOM 節點或 Document 物件,第二個引數是定義 XPath 表示式的字串。
示例:定義自定義的特定於節點的 evaluateXPath() 實用函式
js
// Evaluate an XPath expression `expr` against a given DOM node
// or Document object `node`, returning the results as an array
// thanks wanderingstan at morethanwarm dot mail dot com for the
// initial work.
function evaluateXPath(node, expr) {
const xpe = new XPathEvaluator();
const nsResolver =
node.ownerDocument === null
? node.documentElement
: node.ownerDocument.documentElement;
const result = xpe.evaluate(expr, node, 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,
context,
doc = context ? context.ownerDocument : document,
resolver = null,
) {
let i;
const a = [];
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;
}