Где при тестировании может понадобиться XPath, а также обзор инструментальных средств для отладки XPath-запросов можно найти в предыдущей статье.
Что же представляет из себя xpath-запрос?
XPath (XML Path Language) — язык запросов к элементам XML или XHTML документа. XML имеет древовидную структуру. В документе всегда имеется корневой элемент. У элемента дерева всегда существуют предки (исключение — корневой элемент, у которого предков нет) и могут существовать потомки. Каждый элемент дерева находится на определенном уровне вложенности. У элементов на одном уровне бывают предыдущие и следующие за ним элементы. Строка XPath — это фактически путь к элементу в дереве, где каждый уровень разделяется косой чертой «/». В результате обработки выражения XPath получается объект, который может быть:
- набор узлов (node-set) — неупорядоченный набор узлов без дубликатов
- булево значение (boolean) — true или false
- число (number) — число с плавающей точкой
- строка (string) — последовательность UCS символов
Небольшой примерчик для старта:
Результатом выполнения следующего XPath запроса будет узел <span>
:
/html/body/*/span
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
Следующий запрос вернет несколько элементов (div#first и div#second):
/html/body/div
<html> <body> <div id="first"> <span>span внутри div</span> </div> <div id="second"></div> <span>некоторый текст</span> </body> </html>
- * — обозначает любое имя или набор символов
- / — определяет уровень дерева
Если в запросе первым символом стоит «/» , то путь адресации считается абсолютным (то есть от корня документа). Корень документа всегда является контекстом по умолчанию. Контекст — это текущий полученный узел или набор узлов, относительно которых рассчитывается следующий шаг.
Оси
Оси это основа запросов XPath и их обязательная часть.
- ancestor:: — возвращает множество предков.
- ancestor-or-self:: — возвращает множество предков и текущий элемент.
- attribute:: — возвращает множество атрибутов текущего элемента.
- child:: — возвращает множество потомков на один уровень ниже.
- descendant:: — возвращает полное множество потомков.
- descendant-or-self:: — возвращает полное множество потомков и текущий элемент.
- following:: — возвращает необработанное множество, ниже текущего элемента.
- following-sibling:: — возвращает множество элементов на том же уровне, следующих за текущим.
- namespace:: — возвращает множество имеющее пространство имён (то есть присутствует атрибут xmlns).
- parent:: — возвращает предка на один уровень назад.
- preceding:: — возвращает множество обработанных элементов исключая множество предков.
- preceding-sibling:: — возвращает множество элементов на том же уровне, предшествующих текущему.
- self:: — возвращает текущий элемент.
Для наиболее часто используемых осей существуют сокращения:
- attribute:: — можно заменить на «@»
- child:: — часто просто опускают
- descendant:: — можно заменить на «.//»
- parent:: — можно заменить на «..»
- self:: — можно заменить на «.»
Для приведенного выше примера
/html/body/*/span
полный синтаксис будет иметь вид
/child::html/child::body/child::*/child::span
Чаще xpath-запрос начинают с «.//» или «//», это делает путь к элементу относительным. Символы ".//"
в начале запроса возвращают полное множество потомков, которые являются дочерними для корня документа, т.е. все элементы на текущей странице. В данном случае точку в начале запроса можно опустить, потому что корневой элемент уже является контекстом.
Первый пример можно переписать так:
.//div/span
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
В то время как следующий xpath-запрос вернет оба элемента span:
.//span
<html> <body> <div id="first"> <span>span внутри div</span> </div> <div id="second"></div> <span>некоторый текст</span> </body> </html>
Важную роль в построение запросов играют предикаты — это необязательная часть, заключаемая в квадратные скобки, в которой могут содержаться оси, условия проверки, функции и операторы. В ходе обработки предиката из полученного на шаге набора узлов исключаются узлы, не прошедшие условие проверки. Например, найдем элемент span, находящийся внутри любого элемента с id = «first»
.//*[@id="first"]/span
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
Примеры использования осей при построении запросов:
1. following-sibling::
.//*[@id="first"]/following-sibling::span или .//*[@id="second"]/following-sibling::*[1]
<html>
<body>
<div id="first">
<span>span внутри div</span>
</div>
<div id="second"></div>
<span>некоторый текст</span>
</body>
</html>
2. parent::
.//span[1]/..
<html> <body> <div id="first"> <span>span внутри div</span> </div> <div id="second"></div> <span>некоторый текст</span> </body> </html>