Spec-Zone.ru › XSLT & XPath

Фрагменты XPath

В этой статье представлены фрагменты кода XPath — простые примеры, демонстрирующие работу нескольких простых утилитарных функций, основанных на стандартных интерфейсах спецификации XPath DOM уровня 3 DOM Level 3 XPath specification, которые предоставляют функциональность XPath для JavaScript-кода. Эти фрагменты являются функциями, которые вы можете использовать в своём коде.

Функция оценки для узлов

Следующая пользовательская утилитарная функция может быть использована для оценки выражений XPath для заданных XML-узлов. Первый аргумент — узел DOM или объект Document, а второй — строка, определяющая выражение XPath.

Пример: Определение пользовательской утилитарной функции оценки XPath для узлов

// 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 = xpe.createNSResolver(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;
}

Эта функция использует конструктор new XPathEvaluator(), поддерживаемый в Firefox, Chrome, Opera и Safari, но не в Edge или Internet Explorer. Скрипты в веб-документе, которые могут быть доступны пользователям Edge или Internet Explorer, должны заменить вызов new XPathEvaluator() следующим фрагментом:

  // XPathEvaluator is implemented on objects that implement Document
  const xpe = aNode.ownerDocument || aNode;

В этом случае создание XPathNSResolver может быть упрощено:

  const nsResolver = xpe.createNSResolver(xpe.documentElement);

Однако обратите внимание, что createNSResolver следует использовать только в том случае, если вы уверены, что префиксы пространств имён в выражении XPath соответствуют префиксам в документе, который вы хотите запросить (и что не используется пространство имён по умолчанию (хотя см. document.createNSResolver для обходного пути)). В противном случае, вам нужно предоставить собственную реализацию XPathNSResolver.

Если вы используете XMLHttpRequest для чтения локального или удалённого XML-файла в дерево DOM (как описано в Разбор и сериализация XML), первый аргумент для evaluateXPath() должен быть req.responseXML.

Пример использования

Предположим, у нас есть следующий XML-документ (см. также Как создать дерево DOM и Разбор и сериализация XML):

Пример: XML-документ для использования с пользовательской утилитарной функцией evaluateXPath()
<?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. Вот несколько примеров.

Пример: JavaScript-код с пользовательской утилитарной функцией evaluateXPath()
// 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()

// 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()

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

Ресурсы

  • XPath
  • Обсуждение на форуме по этой теме

См. также

  • Введение в использование XPath в JavaScript

© 2005–2022 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/XPath/Snippets

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API