Фрагменты 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; }
Ресурсы
См. также
© 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