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;
}

資源

另請參閱