Главная · Карта сайта · Поиск · Статьи · Компьютерные курсы · Обучающие программы · Открытые проекты · Веб-программирование · Создание интернет-сайта · Полезные ссылки · Глоссарий · Контакты · Декабрь 06 2016 22:53:54
Последнее опубликованное

Что такое Model-View-Controller
Pattern Model-View-Controller

Как создать свой веб-сайт
Как создать свой сайт в интернете

Разное
Статистика

Язык запросов XPath


Что такое язык запросов XPath

Стандарт XPath является не чем иным, как языком структурированных запросов к разделам XML документа. Стандарт этот разработан все той же организацией W3C, которая является автором спецификаций на сам расширяемый язык разметки, а также на XSD, XSL и многие другие, связанные с XML рекомендации. По отношению к XML документу XPath выступает в той же роли, что и SQL по отношению к реляционной базе данных. С другой стороны XPath довольно сильно напоминает синтаксис описания путей к ресурсам файловой структуры, поскольку сам XML документ, как и структура вложенных папок, является структурой иерархической. Отсюда и слово Path (путь) в названии стандарта. Строка XPath – это путь к некоторому узлу или узлам XML документа относительно заданного контекста. Контекстом запроса может быть сам документ, а также корневой или любой другой элемент документа. Следующий пример показывает, как можно средствами XML описать фрагмент файловой структуры обычного компьютера под управлением Microsoft Windows, а средствами XPath, к примеру, путь к “файлам” Microsoft Office.

<MyComputer>
 <C>
  <Program_Files>
   <Common_Files/>
   <Microsoft.NET/>
   <Microsoft_Office/>
  </Program_Files>
  <Windows/>
 </C>
 <D>
  <Documents/>
 </D>  
</MyComputer>

Запросы XPath в зависимости от контекста:
Если контекст запроса = Документ, то XPath = MyComputer/C/Program_Files/Microsoft_Office/*
Если контекст запроса = Корневой элемент (MyComputer), то XPath = C/Program_Files/Microsoft_Office/*
Если контекст запроса = Элемент “C”, то XPath = Program_Files/Microsoft_Office/*

Документ XML, в отличие от файловой структуры, позволяет на одном уровне иметь множество элементов с одним и тем же именем. В этом случае простого перечисления имен элементов для описания пути к конкретному узлу будет недостаточно, и потребуется накладывать дополнительные условия поиска, например, добавлять критерии поиска по значениям атрибутов. Следующий пример демонстрирует альтернативный вариант описания файловой структуры на XML и соответствующий ему XPath запрос.

<Folder name="MyComputer">
 <Folder name="C:">
  <Folder name="Program Files">
   <Folder name="Common Files"/>
   <Folder name="Microsoft.NET"/>
   <Folder name="Microsoft Office"/>
  </Folder>
  <Folder name="Windows"/>
 </Folder>
 <Folder name="D:">
  <Folder name="Documents"/>
 </Folder>  
</Folder>

Запрос XPath в контексте документа:
Folder[@name="MyComputer"]/Folder[@name="C:"]/Folder[@name="Program Files"]/Folder[@name="Microsoft Office"]/*

Этот вариант более предпочтителен хотя бы потому, что позволяет в именах каталогов использовать пробелы и двоеточия. Надеюсь, общее представление об XPath появилось, и можно переходить к более детальному рассмотрению его синтаксиса.

Синтаксис XPath

Весь запрос или путь XPath состоит из шагов, разделенных косыми чертами. Путь начинается относительно некоторого контекста, примеры которого были приведены ранее. Теперь более подробно рассмотрим, из каких частей состоит шаг XPath запроса:

Во-первых, на каждом шаге указывается критерий отбора узлов. В качестве критерия отбора используют или имена узлов (элементов, атрибутов) или специальные обозначения множеств узлов, например text(), которое символизирует все текстовые узлы. Обозначение node() или * - любой узел из подмножества узлов текущего шага, а используют их тогда, когда не требуются никакие ограничения. Критерий отбора узлов является обязательной частью каждого шага.

Во-вторых, на каждом шаге есть возможность определить дополнительные критерии отбора или предикат шага. Выражение предиката описывается в квадратных скобках и может содержать ограничения на значения атрибутов (как в примере выше), ограничения, связанные с вложенными узлами или просто индекс элемента, например Folder[5]. Ограничения на значения атрибутов и вложенных элементов могут представлять собой сложные условия, объединенные логическими операциями (and, or) и содержащие математические выражения (+, -, *, div, mod). Более подробно предикаты будут рассмотрены в следующих разделах на конкретных примерах. Эта часть шага не является обязательной.

В третьих. Есть еще одна, в самых простых случаях неявная, но обязательная составная часть определения шага – это ось шага. Под осью шага понимается подмножество узлов документа, определяемое контекстом, на котором будет осуществлен поиск. В примерах, рассмотренных выше, на каждом шаге поиск переходил к узлам следующего уровня – дочерним по отношению к текущему контексту. Если вернуться к самому первому примеру, то шаги соответствующего запроса можно описать следующим образом:

  • Шаг 1: {контекст = документ, ось = дочерние узлы (элемент документа), критерий отбора = “MyComputer”};
  • Шаг 2: {контекст = элемент “MyComputer”, ось = дочерние узлы, критерий отбора = “C”}.

И так далее. Значением оси по умолчанию на каждом шаге поиска является переход к дочерним для текущего контекста узлам и обозначается ключевым словом child с двумя двоеточиями: child::.

Вот так выглядит полный вариант XPath запроса для первого примера:

child::MyComputer/child::C/child::Program_Files/child::Microsoft_Office

Из всего вышесказанного следует, что существуют и другие оси:

  • ancestor:: - все предки текущего контекста;
  • ancestor-or-self:: - все предки плюс узлы контекста;
  • descendant:: - все потомки. Сокращенное обозначение - “.//”;
  • descendant-or-self:: - все потомки плюс узлы контекста;
  • child:: - все потомки на один уровень ниже (дочерние узлы) контекста. Является значением по умолчанию.
  • parent:: - предок на один уровень выше (родительский узел) контекста. Сокращенное обозначение - “..”;
  • following:: - множество узлов, которые в порядке обработки (в порядке прямого обхода документа) следуют после узлов контекста, исключая его потомков (descendant);
  • following-sibling:: - множество узлов одного с контекстом уровня, которые в порядке обработки следуют после узлов контекста;
  • preceding:: - множество узлов, которые в порядке обработки (в порядке прямого обхода документа) следуют перед узлами контекста, исключая его предков (ancestor);
  • preceding-sibling:: - множество узлов одного с контекстом уровня, которые в порядке обработки следуют перед узлами контекста;
  • self:: - сам контекст. Сокращенное обозначение - “.”;
  • attribute:: - переход к множеству атрибутов текущего элемента. Сокращенное обозначение - “@”.

Далее, примеры…

Примеры XPath запросов

Для того чтобы протестировать приведенные ниже примеры представляю вашему вниманию небольшую утилиту “Отладчик XPath запросов”. Используя это приложение, можно загрузить XML документ и отладить в его контексте XPath запрос. Содержимое XML документа представлено в виде дерева. Результат запроса также представлен в виде дерева и дополнительно в виде списка. Выбор элемента в дереве результатов синхронизируется с выборов соответствующего элемента в списке и наоборот. Контекстом всех запросов всегда является уровень документа.

Скачать демонстрационную программу.
Скачать Microsoft .NET Framework 3.5 SP1.

Вернемся к фрагменту XML, который использовался в качестве примера при рассмотрении XSD.

<client>
 <name>name</name>
 <phone>+7(495)555-34-77</phone>
 <phone>+7(495)555-35-77</phone>
 <email>user@host.ru</email>
</client>

Выполним несколько простых запросов к этим данным. Первый запрос покажет все текстовые узлы:

.//text()

Пример XPath запроса 1
Пример XPath запроса 1.

.// – сокращенное обозначение оси descendant::, поэтому поиск осуществляется среди всех потомков контекста. Можно немного усложнить задачу и вывести все родительские элементы с текстом. Для этого необходимо добавить один шаг пути, на котором, посредством оси parent:: будет осуществлен переход “наверх”.

.//text()//..

или

.//text()//parent::*

Также, можно вывести только конкретные родительские элементы, например phone:

.//text()//parent::phone

Результат в отладчике XPath запросов выглядит следующим образом:

Пример XPath запроса 2
Пример XPath запроса 2.

Аналогичных результатов можно добиться с использованием следующих запросов:

.//node()[text()]

и

.//phone[text()]

Эти конструкции выглядят более компактно и содержат меньше шагов, поскольку условие на наличие текста помещено в предикат. Аналогичным образом можно определить дополнительные критерии отбора узлов, задав ограничения на их значения. Например, вот так будет выглядеть запрос на поиск всех элементов (node() – любой узел), текстовое содержимое которых должно быть равно ‘name’:

.//node()[text()='name']

В предикатах можно использовать также имена самих элементов, например [name='name']. Под значением name здесь опять скрывается содержимое соответствующего элементу name текстового узла, но поиск осуществляется уже в контексте более высокого уровня, т.е. запрос .//node()[name='name'] вернет единственный элемент client, для которого элемент name является дочерним. На мой взгляд, использование имен элементов в предикатах может вызвать некоторую неопределенность в интерпретации запроса. Безусловно, неопределенность не у вычислительной машины, а у человека, его анализирующего. Такие выражения уместны для элементов простых типов – тех, что не имеют ни атрибутов, ни дочерних элементов, а могут содержать только данные элементарных типов.

Если с этим примером все ясно, то можно перейти к более сложным запросам. Будем осуществлять выборку элементов из XML отчета, сформированного по базе данных компьютерного курса изучения SQL. Отчет представлен файлом report.xml и содержит данные о сотрудниках некоторой компании.

Пример отчета
Пример отчета.

Для работы со следующими примерами этот файл желательно скачать, познакомиться с его структурой в любом текстовом редакторе и загрузить в отладчик XPath запросов. Следующий запрос выводит “Ф.И.О.” всех сотрудников:

.//Record/Column[@Name='S_NAME']//attribute::Value

, а следующий уже решает более сложную задачу – выводит всех сотрудников со стажем работы более 5 лет:

.//Record/Column[@Name='S_EXPERIENCE' and @Value>5]/preceding-sibling::Column[@Name='S_NAME']//attribute::Value

Пример XPath запроса 3
Пример XPath запроса 3.

Теперь комментарии к последнему запросу. Ось .// (descendant::) означает, что поиск на первом шаге выполняется не только на следующем по отношению к контексту уровне, а на всех уровнях документа. На первом шаге мы ищем все элементы Record. На втором шаге среди дочерних по отношению к Record отбираем элементы Column с ограничениями на значения атрибутов: колонка должна содержать данные о стаже сотрудников, а само значение стажа должно быть больше 5 (@Name='S_EXPERIENCE' and @Value>5). Переход к элементам Record необходим, поскольку элементы Column содержатся также в заголовке отчета - в элементах Columns, и их необходимо исключить. На третьем шаге мы ищем колонку с “Ф.И.О.” (@Name='S_NAME') среди предшествующих (preceding-sibling::) “стажу” колонок (порядок колонок в отчете известен заранее). Ну и на последнем шаге мы переходим к атрибутам этой колонки, чтобы вывести только значение атрибута Value.

Большинство сервисов XPath также поддерживают набор функций, в том числе и для работы с текстом. С использованием одной из этих функций усложним последний запрос дополнительным условием на “Ф.И.О.” сотрудников: пусть их фамилии начинаются на “С”:

.//Record/Column[@Name='S_EXPERIENCE' and @Value>5]/preceding-sibling::Column[@Name='S_NAME' and starts-with(@Value,'С')]//attribute::Value

Для этого в предикат второго шага добавлено условие, чтобы значение атрибута Value начиналось на ‘С’ (starts-with(@Value,'С')).

В случае рассматриваемого отчета известен порядок колонок и их количество, что можно использовать для упрощения XPath запросов с использованием индексации узлов в текущем наборе. Последний запрос можно упростить следующим образом:

.//Record/Column[3][@Value>5]/../Column[1][starts-with(@Value,'С')]//@Value

Пример XPath запроса 4
Пример XPath запроса 4.

Фрагмент Column[3][@Value>5] интерпретируется, как 3-й по порядку элемент Column со значением атрибута Value больше 5. Фрагмент /../Column[1][starts-with(@Value,'С')] определяет возврат на уровень назад и выбор 1-й колонки со значением Value, начинающимся на ‘С’. Выражение @Value – сокращенный вариант attribute::Value. Для индексации элементов можно использовать встроенные системные функции, например функцию last(), возвращающую номер последнего узла текущего уровня.

.//Record/Column[last()-2][@Value>5]/../Column[1][starts-with(@Value,'С')]//@Value

Более подробно про функции XPath рекомендую узнать прямо из первоисточника: http://www.w3.org/TR/xpath/#corelib Надеюсь, что для общего знакомства со стандартом XPath изложенного здесь материала более чем достаточно. Детали ищите на сайте его авторов – организации W3C.


Пример обработки результата XPath запроса на C# можно посмотреть здесь.



Компьютерные курсы и курсы программирования
Основы программирования

Курс для начинающих программистов на C# и VB.NET.

SQL 25™

Построение SQL запросов и работа с базой данных.

C# Quick Guide™

Программирование на C#. Краткое руководство.

RegEx

Применение регулярных выражений.

Plug-in архитектура

Примеры программной Plug-in архитектуры.

XML и его расширения

Язык разметки XML и его расширения с примерами.

HTML и разметка гипертекста

Языки HTML, XHTML и CSS с примерами разметки.

Основы веб-дизайна

Основы веб-дизайна: решения типовых задач верстки.

Программирование на PHP

Руководство по программированию на PHP для начинающих.

Справочные материалы

Шаблоны проектирования
Каталог шаблонов проектирования программных компонентов.

Рефакторинг кода
Каталог приемов рефакторинга программного кода.

Гость
Имя

Пароль



Забыли пароль?
Запросите новый здесь
.
Coding Craft. Все права защищены © 2011. Проект Инициативного Народного Фронта Образования - ИНФО-проект.