1 added
1 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Язык разметки XML с самого первого стандарта окружает пользователей компьютеров. Таблицы в Excel, выгрузки из интернет-магазинов, RSS-ленты с новостями - все это основано на XML. Хоть визуальное отображение отличается на устройствах и в программах, но в основе всегда лежит единый формат.</p>
1
<p>Язык разметки XML с самого первого стандарта окружает пользователей компьютеров. Таблицы в Excel, выгрузки из интернет-магазинов, RSS-ленты с новостями - все это основано на XML. Хоть визуальное отображение отличается на устройствах и в программах, но в основе всегда лежит единый формат.</p>
2
<p>Внутри XML-файла может находиться огромное количество информации, поэтому и встает вопрос о перемещении и выборке внутри документа. Как это сделать быстро? Какие средства применять, чтобы в интернет-магазине найти нужный товар из десятков тысяч других? Для навигации и поиска внутри XML используется<strong>язык запросов XPath</strong>.</p>
2
<p>Внутри XML-файла может находиться огромное количество информации, поэтому и встает вопрос о перемещении и выборке внутри документа. Как это сделать быстро? Какие средства применять, чтобы в интернет-магазине найти нужный товар из десятков тысяч других? Для навигации и поиска внутри XML используется<strong>язык запросов XPath</strong>.</p>
3
<p>В этой статье разберем:</p>
3
<p>В этой статье разберем:</p>
4
<ul><li>для кого может быть полезен<em>XPath</em></li>
4
<ul><li>для кого может быть полезен<em>XPath</em></li>
5
<li>базовые конструкции языка для поиска информации в XML</li>
5
<li>базовые конструкции языка для поиска информации в XML</li>
6
<li>чем XPath отличается от CSS-селекторов при поиске в HTML</li>
6
<li>чем XPath отличается от CSS-селекторов при поиске в HTML</li>
7
</ul><h2>Содержание</h2>
7
</ul><h2>Содержание</h2>
8
<ul><li><a>Синтаксис XPath</a></li>
8
<ul><li><a>Синтаксис XPath</a></li>
9
<li><a>Отличия от CSS-селекторов</a></li>
9
<li><a>Отличия от CSS-селекторов</a></li>
10
<li><a>Кому нужен Xpath</a></li>
10
<li><a>Кому нужен Xpath</a></li>
11
<li><a>Заключение</a></li>
11
<li><a>Заключение</a></li>
12
</ul><h2>Синтаксис XPath</h2>
12
</ul><h2>Синтаксис XPath</h2>
13
<p>Для начала создадим базовый пример XML, с которым и будем работать весь урок. Например, список курсов по верстке на Хекслете в XML будет выглядеть так:</p>
13
<p>Для начала создадим базовый пример XML, с которым и будем работать весь урок. Например, список курсов по верстке на Хекслете в XML будет выглядеть так:</p>
14
<p>Это учебный пример, но для отработки навыков<em>XPath</em>подойдет и любой другой XML. Принципы<em>XPath</em>сохранятся при любой структуре файла, потому что по стандарту XML можно использовать элементы с произвольными тегами.</p>
14
<p>Это учебный пример, но для отработки навыков<em>XPath</em>подойдет и любой другой XML. Принципы<em>XPath</em>сохранятся при любой структуре файла, потому что по стандарту XML можно использовать элементы с произвольными тегами.</p>
15
<p>Для тестирования результата подойдут такие онлайн-сервисы, как:</p>
15
<p>Для тестирования результата подойдут такие онлайн-сервисы, как:</p>
16
<ul><li><a>Code Beautify</a></li>
16
<ul><li><a>Code Beautify</a></li>
17
<li><a>XPather</a></li>
17
<li><a>XPather</a></li>
18
</ul><h3>Абсолютные пути</h3>
18
</ul><h3>Абсолютные пути</h3>
19
<p>Самый простой запрос состоит из обращения к корневому элементу. Для этого достаточно выполнить запрос /courses. Нам вернется XML в почти таком же виде, что и в примере выше. Обратите внимание на строку <?xml version="1.0" encoding="UTF-8"?>. Она отличается, потому что элемент не внутри <courses>:</p>
19
<p>Самый простой запрос состоит из обращения к корневому элементу. Для этого достаточно выполнить запрос /courses. Нам вернется XML в почти таком же виде, что и в примере выше. Обратите внимание на строку <?xml version="1.0" encoding="UTF-8"?>. Она отличается, потому что элемент не внутри <courses>:</p>
20
<p>В качестве результата<em>XPath</em>возвращает узлы XML-документа.</p>
20
<p>В качестве результата<em>XPath</em>возвращает узлы XML-документа.</p>
21
<p>Продолжим цепочку и обратимся к описанию из элемента <description>. Для этого добавим в запрос путь к description: /courses/description. Результатом выполнения станет:</p>
21
<p>Продолжим цепочку и обратимся к описанию из элемента <description>. Для этого добавим в запрос путь к description: /courses/description. Результатом выполнения станет:</p>
22
<p>Путь, который строится от корневого элемента, называется<strong>абсолютным</strong>. Используем схему из прошлого запроса и обратимся к любому элементу внутри XML.</p>
22
<p>Путь, который строится от корневого элемента, называется<strong>абсолютным</strong>. Используем схему из прошлого запроса и обратимся к любому элементу внутри XML.</p>
23
<p>Попробуем обратиться к имени курса. В этом случае вернется поле <name> из всех курсов. Запрос /courses/course/name вернет:</p>
23
<p>Попробуем обратиться к имени курса. В этом случае вернется поле <name> из всех курсов. Запрос /courses/course/name вернет:</p>
24
<p>Вот список некоторых базовых запросов и их результат:</p>
24
<p>Вот список некоторых базовых запросов и их результат:</p>
25
<h3>Относительные пути</h3>
25
<h3>Относительные пути</h3>
26
<p>Прошлые запросы строились с помощью абсолютных путей - то есть мы указывали полный путь до информации. Бывают ситуации, когда полный путь не подходит: например, мы хотим обраться к какому-то уникальному полю или не знаем полный путь. В этом случае можно использовать<strong>относительный путь</strong>- он произведет поиск по всему XML и вернет узлы, подходящие под запрос.</p>
26
<p>Прошлые запросы строились с помощью абсолютных путей - то есть мы указывали полный путь до информации. Бывают ситуации, когда полный путь не подходит: например, мы хотим обраться к какому-то уникальному полю или не знаем полный путь. В этом случае можно использовать<strong>относительный путь</strong>- он произведет поиск по всему XML и вернет узлы, подходящие под запрос.</p>
27
<p>Чтобы записать относительный путь, нужно использовать конструкцию //. После нее можно написать любое поле и получить результат. Например, //name вернет поля <name> из всего XML:</p>
27
<p>Чтобы записать относительный путь, нужно использовать конструкцию //. После нее можно написать любое поле и получить результат. Например, //name вернет поля <name> из всего XML:</p>
28
<p>Проблема такого подхода - уникальность полей. В документах одни и те же имена полей могут обозначать разные данные в зависимости от расположения. Поэтому используйте относительные пути только там, где уверены в возвращаемых данных. Например, в нашем примере название курса может быть заключено в <title>:</p>
28
<p>Проблема такого подхода - уникальность полей. В документах одни и те же имена полей могут обозначать разные данные в зависимости от расположения. Поэтому используйте относительные пути только там, где уверены в возвращаемых данных. Например, в нашем примере название курса может быть заключено в <title>:</p>
29
<p>Запрос //title вернет не только имена курсов, но и узел, который находится в <courses>:</p>
29
<p>Запрос //title вернет не только имена курсов, но и узел, который находится в <courses>:</p>
30
<p>Чтобы сэкономить пару секунд, разработчики опускают корневой элемент и пользуются относительными путями. Например, вместо /courses/course/name они пишут //course/name. Для практики попробуйте прошлые примеры перевести на относительные пути с помощью такого механизма.</p>
30
<p>Чтобы сэкономить пару секунд, разработчики опускают корневой элемент и пользуются относительными путями. Например, вместо /courses/course/name они пишут //course/name. Для практики попробуйте прошлые примеры перевести на относительные пути с помощью такого механизма.</p>
31
<p>Несколько примеров запросов с идентичными ответами, как и в прошлой таблице:</p>
31
<p>Несколько примеров запросов с идентичными ответами, как и в прошлой таблице:</p>
32
<h3>Предикаты</h3>
32
<h3>Предикаты</h3>
33
<p>В примерах запросов к именам возвращались имена всех найденных курсов. В некоторых ситуациях это может быть избыточно. Что делать, если хочется получить данные только по первому курсу в <courses>? На помощь приходят<strong>предикаты</strong>- конструкции, с помощью которых можно отфильтровать элементы по заданным условиям. </p>
33
<p>В примерах запросов к именам возвращались имена всех найденных курсов. В некоторых ситуациях это может быть избыточно. Что делать, если хочется получить данные только по первому курсу в <courses>? На помощь приходят<strong>предикаты</strong>- конструкции, с помощью которых можно отфильтровать элементы по заданным условиям. </p>
34
<p>Выберем ключевые слова первого курса по верстке. Для этого достаточно использовать запрос //course[1]/tags:</p>
34
<p>Выберем ключевые слова первого курса по верстке. Для этого достаточно использовать запрос //course[1]/tags:</p>
35
<p>Обратите внимание на[1]. Это предикат с таким условием: "Взять элемент по индексу 1". Попробуйте сделать запрос ко второму или третьему элементу. Достаточно поменять всего одну цифру! </p>
35
<p>Обратите внимание на[1]. Это предикат с таким условием: "Взять элемент по индексу 1". Попробуйте сделать запрос ко второму или третьему элементу. Достаточно поменять всего одну цифру! </p>
36
<p>В<em>XPath</em>индексы элементов начинаются с единицы, а не с нуля, как в принятых стандартах программирования. Если вы уже программируете, это может немного запутать.</p>
36
<p>В<em>XPath</em>индексы элементов начинаются с единицы, а не с нуля, как в принятых стандартах программирования. Если вы уже программируете, это может немного запутать.</p>
37
<p>Предикаты помогают делать точные выборки. Например, получить ссылки на русскоязычные страницы курсов. Для этого нужно получить элементы <url>, у которых атрибут lang равен ru. Делается это указанием атрибута и значения. Чтобы<em>XPath</em>отличил атрибут от элемента перед атрибутом указывается символ @. </p>
37
<p>Предикаты помогают делать точные выборки. Например, получить ссылки на русскоязычные страницы курсов. Для этого нужно получить элементы <url>, у которых атрибут lang равен ru. Делается это указанием атрибута и значения. Чтобы<em>XPath</em>отличил атрибут от элемента перед атрибутом указывается символ @. </p>
38
<p>Теперь запрос будет выглядеть так: //course/url[@lang="ru"]</p>
38
<p>Теперь запрос будет выглядеть так: //course/url[@lang="ru"]</p>
39
<p>Иногда полезно выбрать элементы, которые имеют хоть какой-то атрибут. Для этого можно использовать конструкцию //*[@*]:</p>
39
<p>Иногда полезно выбрать элементы, которые имеют хоть какой-то атрибут. Для этого можно использовать конструкцию //*[@*]:</p>
40
<p>По примеру выше видно, знак * обозначает "все/любой".</p>
40
<p>По примеру выше видно, знак * обозначает "все/любой".</p>
41
<p>Когда выбраны элементы по атрибутам, можно произвести дополнительную фильтрацию по этим значениям. Например, найдем элементы <duration> со значением атрибута value больше 9. Внутри предикатов используются<strong>операторы сравнения</strong>, знакомые по языкам программирования:</p>
41
<p>Когда выбраны элементы по атрибутам, можно произвести дополнительную фильтрацию по этим значениям. Например, найдем элементы <duration> со значением атрибута value больше 9. Внутри предикатов используются<strong>операторы сравнения</strong>, знакомые по языкам программирования:</p>
42
<ul><li>> - больше</li>
42
<ul><li>> - больше</li>
43
<li>< - меньше</li>
43
<li>< - меньше</li>
44
<li>>= - больше или равно</li>
44
<li>>= - больше или равно</li>
45
<li><= - меньше или равно</li>
45
<li><= - меньше или равно</li>
46
<li>= - равно</li>
46
<li>= - равно</li>
47
<li>!= - не равно</li>
47
<li>!= - не равно</li>
48
</ul><p>Запрос будет выглядеть так: //course/duration[@value > 9]:</p>
48
</ul><p>Запрос будет выглядеть так: //course/duration[@value > 9]:</p>
49
<p>Мы разобрались, как выбирать одно поле - это интересная, но редкая задача. Чаще разработчики обрабатывают данные по всему файлу или нескольким полям. Попробуем одновременно использовать предикат и обратиться к другим полям. Обратите внимание на два момента:</p>
49
<p>Мы разобрались, как выбирать одно поле - это интересная, но редкая задача. Чаще разработчики обрабатывают данные по всему файлу или нескольким полям. Попробуем одновременно использовать предикат и обратиться к другим полям. Обратите внимание на два момента:</p>
50
<ul><li>Предикат необязательно должен идти в конце запроса</li>
50
<ul><li>Предикат необязательно должен идти в конце запроса</li>
51
<li>Внутри предиката могут находиться новые пути, которые нужно проверить</li>
51
<li>Внутри предиката могут находиться новые пути, которые нужно проверить</li>
52
</ul><p>Мы уже знаем, как с помощью предиката отфильтровать данные по полю <duration>. Эту задачу мы выполняли с помощью конструкции duration[@value > 9]. А теперь попробуем сделать эту конструкцию предикатом для <course>. Так мы получим данные о курсах с длительностью больше 9 часов: //course[duration[@value > 9]]:</p>
52
</ul><p>Мы уже знаем, как с помощью предиката отфильтровать данные по полю <duration>. Эту задачу мы выполняли с помощью конструкции duration[@value > 9]. А теперь попробуем сделать эту конструкцию предикатом для <course>. Так мы получим данные о курсах с длительностью больше 9 часов: //course[duration[@value > 9]]:</p>
53
-
<p>Можн�� продолжить этот запрос и получить только имена курсов. Тогда предикат будет в середине запроса, а не в его конце: //course[duration[@value > 9]]/name</p>
53
+
<p>Можно продолжить этот запрос и получить только имена курсов. Тогда предикат будет в середине запроса, а не в его конце: //course[duration[@value > 9]]/name</p>
54
<h3>Функции</h3>
54
<h3>Функции</h3>
55
<p>В прошлых примерах запросы затрагивали теги и атрибуты. Сами данные мы не затрагивали, хотя это огромный пласт информации, по которой можно делать выборки. Для решения этой задачи используются встроенные в<em>XPath</em>функции. Они являются частью предикатов - например, @. Попробуем найти курс с названием "Основы верстки контента".</p>
55
<p>В прошлых примерах запросы затрагивали теги и атрибуты. Сами данные мы не затрагивали, хотя это огромный пласт информации, по которой можно делать выборки. Для решения этой задачи используются встроенные в<em>XPath</em>функции. Они являются частью предикатов - например, @. Попробуем найти курс с названием "Основы верстки контента".</p>
56
<p>Для поиска по тексту внутри элемента используется функция text(). Ее задача - получить текстовое значение элемента и сравнить его с условием по необходимости. Вот как будет выглядеть запрос для поиска курса с нужным именем: //course[name[text()="Основы верстки контента"]]</p>
56
<p>Для поиска по тексту внутри элемента используется функция text(). Ее задача - получить текстовое значение элемента и сравнить его с условием по необходимости. Вот как будет выглядеть запрос для поиска курса с нужным именем: //course[name[text()="Основы верстки контента"]]</p>
57
<p>Но что, если нам известно только часть названия? Для этого существует функция contains(), которая принимает два аргумента:</p>
57
<p>Но что, если нам известно только часть названия? Для этого существует функция contains(), которая принимает два аргумента:</p>
58
<ol><li>Строка, где будет производиться поиск</li>
58
<ol><li>Строка, где будет производиться поиск</li>
59
<li>Подстрока, которая будет искаться</li>
59
<li>Подстрока, которая будет искаться</li>
60
</ol><p>Для примера найдем курс, у которого в ключевых словах есть слово "Bootstrap". Функция примет текстовое значение элемента tags и найдет там слово "Bootstrap": //course[tags[contains(text(), "Bootstrap")]]</p>
60
</ol><p>Для примера найдем курс, у которого в ключевых словах есть слово "Bootstrap". Функция примет текстовое значение элемента tags и найдет там слово "Bootstrap": //course[tags[contains(text(), "Bootstrap")]]</p>
61
<p>В стандарте<em>XPath</em>существует еще несколько функций, но цель статьи - показать принципы работы тех или иных механизмов, а не дать исчерпывающую документацию по всему языку.</p>
61
<p>В стандарте<em>XPath</em>существует еще несколько функций, но цель статьи - показать принципы работы тех или иных механизмов, а не дать исчерпывающую документацию по всему языку.</p>
62
<h2>Отличия от CSS-селекторов</h2>
62
<h2>Отличия от CSS-селекторов</h2>
63
<p>Если вы писали на JavaScript, то знаете, что элементы можно искать с помощью CSS-селекторов, используя методы querySelector() или querySelectorAll(). Почему же разработчики иногда ищут элементы внутри HTML именно с помощью<em>XPath</em>?</p>
63
<p>Если вы писали на JavaScript, то знаете, что элементы можно искать с помощью CSS-селекторов, используя методы querySelector() или querySelectorAll(). Почему же разработчики иногда ищут элементы внутри HTML именно с помощью<em>XPath</em>?</p>
64
<p>Дело в концепции поиска элементов. Используя CSS, можно идти только в глубину без возможности обратиться к родительским элементам. В отличие от CSS,<em>XPath</em>позволяет в любой момент обращаться и к дочерним, и к родительским элементам.</p>
64
<p>Дело в концепции поиска элементов. Используя CSS, можно идти только в глубину без возможности обратиться к родительским элементам. В отличие от CSS,<em>XPath</em>позволяет в любой момент обращаться и к дочерним, и к родительским элементам.</p>
65
<p>Если вы хотите подробнее изучить поиск по HTML с помощью<em>XPath</em>, рекомендуем обратиться к статье<a>Introduction to using XPath in JavaScript</a>.</p>
65
<p>Если вы хотите подробнее изучить поиск по HTML с помощью<em>XPath</em>, рекомендуем обратиться к статье<a>Introduction to using XPath in JavaScript</a>.</p>
66
<p>С помощью CSS нельзя найти все элементы div, внутри которых есть ссылки - можно найти сами ссылки, но не их родителей.<em>XPath</em>позволяет это сделать простым сочетанием div[a]. Постепенно ситуация меняется: в CSS появился селектор :has(), но он поддерживается еще не всеми новыми версиями браузеров. Со временем это изменится, но пока реальность именно такая.</p>
66
<p>С помощью CSS нельзя найти все элементы div, внутри которых есть ссылки - можно найти сами ссылки, но не их родителей.<em>XPath</em>позволяет это сделать простым сочетанием div[a]. Постепенно ситуация меняется: в CSS появился селектор :has(), но он поддерживается еще не всеми новыми версиями браузеров. Со временем это изменится, но пока реальность именно такая.</p>
67
<p>Другой пример - поиск элементов по тексту внутри них. С этой задачей CSS никогда не справится, так как такой цели у него нет.<em>XPath</em>, как мы изучили, умеет это делать с помощью функции text().</p>
67
<p>Другой пример - поиск элементов по тексту внутри них. С этой задачей CSS никогда не справится, так как такой цели у него нет.<em>XPath</em>, как мы изучили, умеет это делать с помощью функции text().</p>
68
<h2>Кому нужен Xpath</h2>
68
<h2>Кому нужен Xpath</h2>
69
<p>Если коротко, Xpath нужен всем, кто работает с XML.</p>
69
<p>Если коротко, Xpath нужен всем, кто работает с XML.</p>
70
<p>Чтобы разобраться подробнее, изучим несколько примеров:</p>
70
<p>Чтобы разобраться подробнее, изучим несколько примеров:</p>
71
<p><strong>SEO-специалисты</strong>. Специалисты по продвижению часто обрабатывают большие массивы данных и вытаскивают информацию со страниц сайта.</p>
71
<p><strong>SEO-специалисты</strong>. Специалисты по продвижению часто обрабатывают большие массивы данных и вытаскивают информацию со страниц сайта.</p>
72
<p>Например, для них критичны<strong>мета-теги</strong>- дополнительная информация, в которой содержатся иконки сайтов, название страницы, описание и так далее. Эту информацию SEO-специалист может автоматически парсить с помощью запросов в<em>XPath</em>.</p>
72
<p>Например, для них критичны<strong>мета-теги</strong>- дополнительная информация, в которой содержатся иконки сайтов, название страницы, описание и так далее. Эту информацию SEO-специалист может автоматически парсить с помощью запросов в<em>XPath</em>.</p>
73
<p><strong>Тестировщики</strong>. При работе с Front-end тестировщики часто проверяют тот или иной вывод информации на странице - для этого они выбирают отдельные элементы с нужной страницы. Это можно делать через<em>XPath</em>и DevTools, встроенный в браузеры на основе<em>Chromium</em>.</p>
73
<p><strong>Тестировщики</strong>. При работе с Front-end тестировщики часто проверяют тот или иной вывод информации на странице - для этого они выбирают отдельные элементы с нужной страницы. Это можно делать через<em>XPath</em>и DevTools, встроенный в браузеры на основе<em>Chromium</em>.</p>
74
<p><strong>Разработчики</strong>. Они часто используют<strong>парсеры</strong>- это скрипты, которые ищут нужную информацию на страницах одного или нескольких сайтов. Например, мы хотим сравнить стоимость одного и того же товара в разных магазинах. Для такой задачи можно написать скрипт, который пройдется по всем нужным сайтам, сравнит цены и вернет данные. В этом случае для поиска информацию на странице можно использовать<em>XPath</em>.</p>
74
<p><strong>Разработчики</strong>. Они часто используют<strong>парсеры</strong>- это скрипты, которые ищут нужную информацию на страницах одного или нескольких сайтов. Например, мы хотим сравнить стоимость одного и того же товара в разных магазинах. Для такой задачи можно написать скрипт, который пройдется по всем нужным сайтам, сравнит цены и вернет данные. В этом случае для поиска информацию на странице можно использовать<em>XPath</em>.</p>
75
<p>Это лишь часть сценариев, в которых пригождается язык<em>XPath</em>- на самом деле, их десятки.</p>
75
<p>Это лишь часть сценариев, в которых пригождается язык<em>XPath</em>- на самом деле, их десятки.</p>
76
<h2>Заключение</h2>
76
<h2>Заключение</h2>
77
<p>В этой статье мы рассмотрели, где встречается XML и кому он может пригодиться. Мы научились составлять базовые запросы и изучили часто используемые конструкции<em>XPath</em>:</p>
77
<p>В этой статье мы рассмотрели, где встречается XML и кому он может пригодиться. Мы научились составлять базовые запросы и изучили часто используемые конструкции<em>XPath</em>:</p>
78
<ul><li>Абсолютные и относительные пути</li>
78
<ul><li>Абсолютные и относительные пути</li>
79
<li>Предикаты</li>
79
<li>Предикаты</li>
80
<li>Поиск по атрибутам</li>
80
<li>Поиск по атрибутам</li>
81
<li>Операторы сравнения</li>
81
<li>Операторы сравнения</li>
82
<li>Функции</li>
82
<li>Функции</li>
83
</ul><p>Также теперь вы знаете, что поиск по HTML с помощью<em>XPath</em>может быть эффективнее поиска с помощью CSS-селекторов.</p>
83
</ul><p>Также теперь вы знаете, что поиск по HTML с помощью<em>XPath</em>может быть эффективнее поиска с помощью CSS-селекторов.</p>
84
<p>В этой статье мы постарались дать знания, которые помогут справиться с большинством задач. Но это далеко не все возможности<em>XPath</em>- это более глубокий язык, чем представлено в статье. Как и с другими технологиями, тут важно набить руку. Чем больше вы практикуетесь, тем более точные и полезные запросы пишете.</p>
84
<p>В этой статье мы постарались дать знания, которые помогут справиться с большинством задач. Но это далеко не все возможности<em>XPath</em>- это более глубокий язык, чем представлено в статье. Как и с другими технологиями, тут важно набить руку. Чем больше вы практикуетесь, тем более точные и полезные запросы пишете.</p>