Полное руководство по XPath для тестирования XML, SOAP и веб-приложений
| Символ |
Описание |
Пример |
Результат |
/ |
Выбор прямых потомков |
/library/book |
Все <book> внутри <library> |
// |
Выбор на любом уровне |
//book |
Все <book> в документе |
. |
Текущий узел |
./title |
<title> относительно текущего |
.. |
Родительский узел |
../author |
<author> родителя |
@ |
Атрибут |
//@id |
Все атрибуты id |
* |
Любой элемент |
/library/* |
Все дочерние элементы <library> |
\| |
Объединение |
//book \| //magazine |
Все <book> и <magazine> |
[] |
Предикат (условие) |
//book[@id='1'] |
<book> с атрибутом id="1" |
| Ось |
Описание |
Пример |
child:: |
Дочерние элементы |
child::book |
parent:: |
Родительский элемент |
parent::library |
ancestor:: |
Все предки |
ancestor::* |
descendant:: |
Все потомки |
descendant::title |
following:: |
Элементы после текущего |
following::chapter |
preceding:: |
Элементы до текущего |
preceding::chapter |
following-sibling:: |
Следующие соседи |
following-sibling::book |
preceding-sibling:: |
Предыдущие соседи |
preceding-sibling::book |
attribute:: |
Атрибуты |
attribute::id |
self:: |
Сам элемент |
self::book |
// Дочерние элементы
//book/child::title
→ Все <title> которые являются прямыми детьми <book>
// Родитель
//title/parent::book
→ Все <book> которые содержат <title>
// Предки
//title/ancestor::library
→ Все <library> предки элементов <title>
// Все потомки
//library/descendant::title
→ Все <title> на любом уровне внутри <library>
// Следующие соседи
//book[1]/following-sibling::book
→ Все <book> после первого <book>
// Предыдущие соседи
//book[last()]/preceding-sibling::book
→ Все <book> до последнего <book>
element[condition]
| Предикат |
Описание |
Пример |
[n] |
n-й элемент |
//book[1] - первая книга |
[last()] |
Последний элемент |
//book[last()] - последняя книга |
[position() < 3] |
Позиция меньше 3 |
//book[position() < 3] - первые 2 книги |
[@attr] |
Наличие атрибута |
//book[@id] - книги с атрибутом id |
[@attr='value'] |
Значение атрибута |
//book[@id='1'] - книга с id="1" |
[text()='value'] |
Текст элемента |
//title[text()='1984'] |
[contains(@attr, 'value')] |
Содержит подстроку |
//book[contains(@id, 'book')] |
[starts-with(@attr, 'value')] |
Начинается с |
//book[starts-with(@id, 'bk')] |
// AND (и)
//book[@id='1' and @lang='en']
→ Книга с id="1" И lang="en"
// OR (или)
//book[@id='1' or @id='2']
→ Книга с id="1" ИЛИ id="2"
// Сравнение чисел
//book[price > 20]
→ Книги дороже 20
//book[price >= 20 and price <= 50]
→ Книги от 20 до 50
// Множественные условия
//book[@id='1'][author='Orwell']
→ Книга с id="1" и автором "Orwell"
// Условия на вложенных элементах
//book[author='Orwell']/title
→ Названия книг Оруэлла
//book[price > 30]/author
→ Авторы книг дороже 30
| Функция |
Описание |
Пример |
string() |
Преобразует в строку |
string(//book[1]/title) |
concat() |
Объединяет строки |
concat('ID: ', @id) |
substring() |
Извлекает подстроку |
substring('hello', 2, 3) → "ell" |
substring-before() |
До подстроки |
substring-before('hello-world', '-') → "hello" |
substring-after() |
После подстроки |
substring-after('hello-world', '-') → "world" |
string-length() |
Длина строки |
string-length('hello') → 5 |
normalize-space() |
Убирает лишние пробелы |
normalize-space(' hello ') → "hello" |
translate() |
Заменяет символы |
translate('abc', 'a', 'A') → "Abc" |
contains() |
Проверяет наличие |
contains('hello', 'ell') → true |
starts-with() |
Начинается с |
starts-with('hello', 'he') → true |
| Функция |
Описание |
Пример |
number() |
Преобразует в число |
number('123') → 123 |
sum() |
Сумма значений |
sum(//book/price) |
ceiling() |
Округление вверх |
ceiling(4.3) → 5 |
floor() |
Округление вниз |
floor(4.9) → 4 |
round() |
Округление |
round(4.5) → 5 |
| Функция |
Описание |
Пример |
boolean() |
Преобразует в boolean |
boolean(//book) |
not() |
Инверсия |
not(@id='1') |
true() |
Возвращает true |
true() |
false() |
Возвращает false |
false() |
| Функция |
Описание |
Пример |
count() |
Количество узлов |
count(//book) |
last() |
Последняя позиция |
//book[last()] |
position() |
Текущая позиция |
//book[position()=2] |
name() |
Имя элемента |
name(//book[1]) → "book" |
local-name() |
Локальное имя (без namespace) |
local-name(//soap:Body) → "Body" |
// Длина строки
//book[string-length(title) > 10]
→ Книги с названием длиннее 10 символов
// Содержит подстроку
//book[contains(title, 'Python')]
→ Книги со словом "Python" в названии
// Начинается с
//book[starts-with(@id, 'bk')]
→ Книги с id начинающимся на "bk"
// Объединение строк
//book[concat(author, ' - ', title)]
→ "George Orwell - 1984"
// Сумма значений
sum(//book/price)
→ Общая стоимость всех книг
// Количество элементов
count(//book[@lang='en'])
→ Количество книг на английском
// Нормализация пробелов
//book[normalize-space(title)='1984']
→ Книга с названием "1984" (игнорируя лишние пробелы)
<?xml version="1.0" encoding="UTF-8"?>
<library>
<book id="1" lang="en">
<title>1984</title>
<author>George Orwell</author>
<year>1949</year>
<price currency="USD">15.99</price>
</book>
<book id="2" lang="en">
<title>Animal Farm</title>
<author>George Orwell</author>
<year>1945</year>
<price currency="USD">12.99</price>
</book>
<book id="3" lang="ru">
<title>Война и мир</title>
<author>Лев Толстой</author>
<year>1869</year>
<price currency="RUB">500</price>
</book>
</library>
// Все книги
//book
→ Возвращает все элементы <book>
// Конкретная книга по ID
//book[@id='1']
→ Книга с id="1"
// Название первой книги
//book[1]/title/text()
→ "1984"
// Все авторы
//book/author/text()
→ ["George Orwell", "George Orwell", "Лев Толстой"]
// Книги на английском
//book[@lang='en']
→ Книги с атрибутом lang="en"
// Книги дороже $13
//book[price > 13]
→ Книги со стоимостью > 13
// Книги Оруэлла
//book[author='George Orwell']
→ Все книги автора George Orwell
// Название книги с id="2"
//book[@id='2']/title/text()
→ "Animal Farm"
// Валюта книги с id="3"
//book[@id='3']/price/@currency
→ "RUB"
// Проверить наличие элемента
boolean(//book[@id='1'])
→ true
// Проверить отсутствие
not(//book[@id='999'])
→ true
// Количество книг
count(//book)
→ 3
// Количество книг на английском
count(//book[@lang='en'])
→ 2
// Проверить значение
//book[@id='1']/title/text() = '1984'
→ true
// Проверить диапазон
//book[@id='1']/price > 10 and //book[@id='1']/price < 20
→ true
// Сумма всех цен (осторожно, разные валюты!)
sum(//book[@lang='en']/price)
→ 28.98
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Authentication xmlns="http://example.com/orders">
<token>abc123xyz</token>
</Authentication>
</soap:Header>
<soap:Body>
<CreateOrderRequest xmlns="http://example.com/orders">
<orderId>ORD-123</orderId>
<customer>John Doe</customer>
<total>100.00</total>
</CreateOrderRequest>
</soap:Body>
</soap:Envelope>
// Проверить наличие токена
boolean(//*[local-name()='token'])
→ true
// Получить orderId
//*[local-name()='orderId']/text()
→ "ORD-123"
// Проверить total
number(//*[local-name()='total']) = 100.00
→ true
// Получить customer
//*[local-name()='customer']/text()
→ "John Doe"
<div class="user-profile">
<h2 id="username">john_doe</h2>
<p class="email">john@example.com</p>
<button data-testid="edit-profile">Edit Profile</button>
<div class="stats">
<span class="followers">1250</span>
<span class="following">340</span>
</div>
</div>
// По ID
//*[@id='username']
//h2[@id='username']
// По классу
//*[@class='email']
//p[@class='email']
// По data-атрибуту
//*[@data-testid='edit-profile']
//button[@data-testid='edit-profile']
// По тексту
//button[text()='Edit Profile']
//button[contains(text(), 'Edit')]
// По частичному совпадению класса
//*[contains(@class, 'btn-primary')]
// Вложенные элементы
//div[@class='user-profile']//span[@class='followers']
// По порядку
//div[@class='stats']/span[1] // первый span (followers)
//div[@class='stats']/span[2] // второй span (following)
// Получить email Alice
//tr[td[1]='Alice']/td[2]
//tr[td='Alice']/td[2]
// Кнопка Delete для Bob
//tr[td='Bob']//button[@class='btn-delete']
// Все активные пользователи
//tr[td[contains(@class, 'status-active')]]/td[1]
// Количество строк в таблице
count(//table[@id='users-table']//tbody/tr)
// Строка с конкретным email
//tr[td='alice@example.com']
| Задача |
XPath |
| Все элементы |
//element |
| По атрибуту |
//element[@attr='value'] |
| По тексту |
//element[text()='text'] |
| Содержит текст |
//element[contains(text(), 'text')] |
| Первый элемент |
//element[1] |
| Последний элемент |
//element[last()] |
| Родитель |
//element/parent::* или //element/.. |
| Потомки |
//element//descendant |
| Соседи |
//element/following-sibling::* |
| С namespace |
//*[local-name()='element'] |
| Количество |
count(//element) |
| Сумма |
sum(//element) |
| Проверка существования |
boolean(//element) |
| Несколько условий |
//element[@a='1' and @b='2'] |
| Или |
//element[@a='1' or @a='2'] |
| Начинается с |
//element[starts-with(@attr, 'value')] |
| Содержит |
//element[contains(@attr, 'value')] |
| Не равно |
//element[@attr!='value'] или //element[not(@attr='value')] |
| Оператор |
Описание |
Пример |
= |
Равно |
@id='1' |
!= |
Не равно |
@id!='1' |
< |
Меньше |
price < 20 |
> |
Больше |
price > 20 |
<= |
Меньше или равно |
price <= 20 |
>= |
Больше или равно |
price >= 20 |
and |
Логическое И |
@id='1' and @lang='en' |
or |
Логическое ИЛИ |
@id='1' or @id='2' |
not() |
Логическое НЕ |
not(@id='1') |
\| |
Объединение результатов |
//book \| //magazine |
+ |
Сложение |
price + tax |
- |
Вычитание |
price - discount |
* |
Умножение |
price * quantity |
div |
Деление |
total div count |
mod |
Остаток от деления |
position() mod 2 |