XPath — Полное руководство

Навигация по DOM-дереву, оси, функции и примеры для QA

1. Основы XPath

XPath (XML Path Language) — это язык для навигации по элементам XML/HTML документа. В тестировании XPath используется для поиска элементов в Selenium, Playwright и других инструментах.

Выражение Описание
/htmlКорневой элемент
//divВсе элементы div в документе
.Текущий узел
..Родительский узел
@attrАтрибут элемента
text()Текстовый узел

Пример HTML-структуры

<!-- DOM Tree Example --> <html> <body> <div id="container"> <form class="login-form"> <input type="text" id="username"> <input type="password" id="password"> <button type="submit">Войти</button> </form> </div> </body> </html>
2. Типы узлов
Тип Обозначение Пример
Elementtagnamediv, button
Attribute@name//div[@id='foo']
Texttext()//button/text()
Commentcomment()//comment()
Nodenode()Любой узел
Processing Instructionprocessing-instruction()XML инструкции

Примеры поиска по типу узла

// Текст кнопки
//button/text()
→ "Войти"

// Элемент по тексту
//button[text()="Войти"]
→ <button>Войти</button>

// Вход по текстовому содержимому
//*[contains(text(), "Войти")]
3. Оси XPath

Оси определяют направление движения по DOM-дереву относительно текущего узла.

self::

Текущий узел

parent::

Родительский узел

child::

Дочерние элементы

ancestor::

Все предки (вверх)

descendant::

Все потомки (вниз)

following-sibling::

Следующие соседи

preceding-sibling::

Предыдущие соседи

following::

Все после (в документе)

preceding::

Все до (в документе)

ancestor-or-self::

Предки + текущий

descendant-or-self::

Потомки + текущий

namespace::

Пространство имён

Сокращённый синтаксис

Полная форма Сокращение
child::**
descendant::*//
self::node().
parent::node()..
attribute::*@*

Примеры с осями

DOM-структура для примеров

<form id="login"> <input type="text" id="username" placeholder="Имя пользователя"/> <input type="password" id="password" placeholder="Пароль"/> <button type="submit">Войти</button> </form>

XPath-запросы и результаты

// 1. Следующий сосед (following-sibling)
//input[@id='username']/following-sibling::button
// Результат: <button type="submit">Войти</button>

// 2. Родитель (parent)
//input[@id='username']/parent::form
// Результат: <form id="login">...</form>

// 3. Первый следующий сосед
//input[@id='username']/following-sibling::input[1]
// Результат: <input id="password">

// 4. Все предки (ancestor)
//button[@type='submit']/ancestor::html
// Результат: <html>...</html>

// 5. Дочерние элементы (child)
//form[@id='login']/child::*
// Результат: [input#username, input#password, button]
4. Предикаты (фильтры)

Предикаты — это условия в квадратных скобках [], которые фильтруют узлы.

Фильтрация по индексу

DOM-структура

<ul> <li>Первый</li> <li>Второй</li> <li>Третий</li> <li>Последний</li> </ul>

XPath-запросы

// Первый элемент списка
//li[1]
// Результат: <li>Первый</li>

// Последний элемент
//li[last()]
// Результат: <li>Последний</li>

// Предпоследний
//li[last()-1]
// Результат: <li>Третий</li>

// Первые 2 элемента
//li[position()<=2]
// Результат: [<li>Первый</li>, <li>Второй</li>]

Фильтрация по атрибутам

DOM-структура

<div id="header">Шапка</div> <div class="login-form active"> <input type="text" name="username"/> <input type="password" name="password"/> <button type="submit" disabled>Войти</button> </div> <div class="hidden">Скрытый</div>

XPath-запросы

// По id (уникальный)
//div[@id='header']
// Результат: <div id="header">Шапка</div>

// По class (точное совпадение)
//div[@class='login-form active']
// Результат: <div class="login-form active">...</div>

// class содержит 'login'
//div[contains(@class, 'login')]
// Результат: <div class="login-form active">...</div>

// Несколько атрибутов (AND)
//input[@type='text' and @name='username']
// Результат: <input type="text" name="username">

// Элемент с атрибутом disabled
//button[@disabled]
// Результат: <button type="submit" disabled>Войти</button>

// class НЕ содержит 'hidden'
//div[not(contains(@class, 'hidden'))]
// Результат: [<div id="header">, <div class="login-form active">]

Фильтрация по тексту

DOM-структура

<nav> <a href="/">Главная</a> <a href="/about">О компании</a> <a href="/services">Подробнее о услугах</a> <button>Отправить</button> </nav>

XPath-запросы

// Точное совпадение текста
//a[text()='Главная']
// Результат: <a href="/">Главная</a>

// Текст содержит подстроку
//a[contains(text(), 'услуг')]
// Результат: <a>Подробнее о услугах</a>

// Текст начинается с
//a[starts-with(text(), 'О')]
// Результат: <a href="/about">О компании</a>

// Любой элемент с текстом 'Отправить'
//*[text()='Отправить']
// Результат: <button>Отправить</button>

// Ссылка с текстом содержащим 'Подробнее'
//a[contains(text(), 'Подробнее')]
// Результат: <a>Подробнее о услугах</a>
5. Функции XPath

Строковые функции

contains(str, substr)

Содержит подстроку

starts-with(str, prefix)

Начинается с

ends-with(str, suffix)

Заканчивается на

substring(str, pos, len)

Подстрока

normalize-space(str)

Убирает лишние пробелы

string-length(str)

Длина строки

concat(str1, str2, ...)

Конкатенация

translate(str, from, to)

Замена символов

Числовые функции

count(node-set)

Количество узлов

sum(node-set)

Сумма значений

position()

Позиция в наборе

last()

Последняя позиция

Логические функции

boolean(value)

Приведение к bool

not(expr)

Отрицание

true()

Истина

false()

Ложь

Функции узлов

name(node?)

Имя тега

local-name(node?)

Локальное имя

namespace-uri(node?)

URI пространства имён

6. Навигация по DOM

Спуск вниз (child axis)

<form id="login"> <div> <input id="user"/> </div> </form>
// Прямой дочерний элемент
//form[@id='login']/div

// Любой дочерний input
//form[@id='login']/input

// Все потомки input
//form[@id='login']//input

// Первый дочерний div
//form[@id='login']/div[1]

Подъём вверх (parent axis)

// Родитель по оси
//input[@id='user']/parent::div

// То же через ..
//input[@id='user']/../div

// Два уровня вверх
//input[@id='user']/../../

// Корневой элемент
//input[@id='user']/ancestor::form

Боковое движение (sibling axes)

<div> <input id="firstName"/> <input id="lastName"/> <input id="email"/> </div>
// Следующий сосед (после lastName идёт email)
//input[@id='lastName']/following-sibling::input

// Предыдущий сосед (перед lastName идёт firstName)
//input[@id='lastName']/preceding-sibling::input

// Первый следующий input
//input[@id='firstName']/following-sibling::input[1]

// Все следующие соседи
//input[@id='firstName']/following-sibling::*
7. Практические примеры

Поиск кнопки по тексту

// Точное совпадение
//button[text()='Отправить']

// Текст содержит
//button[contains(text(), 'Отправ')]

// Ссылка с текстом
//a[text()='Читать далее']

Работа с формами

// Все поля ввода в форме
//form[@id='registration']//input

// Input по name
//input[@name='email']

// Обязательные поля
//input[@required]

// Поле по placeholder
//input[@placeholder='Введите email']

// Кнопка submit в форме
//form[@id='login']//button[@type='submit']

Таблицы

// Заголовки таблицы
//table[@id='data']/thead//th

// Строки таблицы
//table[@id='data']/tbody/tr

// Ячейка по координатам [row, col]
//table//tr[2]/td[3]

// Строка по содержимому
//table//tr[td[contains(text(), 'Иванов')]]

Динамические элементы

// Элемент с динамическим id
//div[starts-with(@id, 'dropdown-')]

// Меню с вложенными пунктами
//ul[@class='menu']//li[contains(@class, 'active')]

// Скрытый элемент
//div[@style='display: none;' and @class='tooltip']

//disabled кнопка
//button[@disabled and contains(text(), 'Загрузка')]

Комбинированные условия

// AND - оба условия
//input[@type='text' and @required]

// OR - хотя бы одно
//input[@name='phone' or @name='mobile']

// NOT - отрицание
//button[not(@disabled)]

// Сложное условие
//div[@class='card' and contains(@id, 'product') and position() <= 5]
8. XPath 2.0+ улучшения

Примечание: XPath 2.0+ поддерживается не всеми браузерами и инструментами. Selenium WebDriver использует XPath 1.0. Для Playwright доступны некоторые функции XPath 2.0+.

Функция Описание XPath
lower-case()Нижний регистр2.0+
upper-case()Верхний регистр2.0+
matches()Регулярное выражение2.0+
replace()Замена по regex2.0+
tokenize()Разбиение строки2.0+
avg()Среднее значение2.0+
min(), max()Мин/макс2.0+
9. Лучшие практики

Рекомендации

  • Используйте уникальные атрибутыid, data-testid, data-qa
  • Избегайте абсолютных путей — начинайте с // для гибкости
  • Короче = надёжнее//[@data-qa='submit-btn'] лучше длинного DOM-пути
  • Текстовые селекторы хрупкие — используйте при необходимости
  • Проверяйте на динамический контент — идентификаторы могут меняться
  • Используйте contains() осторожно — может найти лишние элементы
  • Комбинируйте стратегии — XPath + CSS часто надёжнее

Порядок поиска локаторов (по приоритету):

1. data-testid / data-qa → 2. id → 3. name → 4. CSS selector → 5. XPath