 | Уровень сложности: простой Бенуа Маршаль, консультант, Pineapplesoft
09.02.2009 XPath 2.0 лежит в основе двух стандартов первостепенной важности, которые на данный момент находятся в последней стадии разработки в W3C: XSLT 2.0 и XQuery. Сам XPath был существенно переработан с целью повышения гибкости и эффективности языка. В этой статье Бенуа Маршаль (Benoît Marchal) расскажет о том, как новая модель данных XPath позволяет разработчикам легко создавать сложные запросы.
Серьезная переработка знакомого стандарта
Несмотря на то, что на данный момент спецификация XPath 2.0 является лишь кандидатом в рекомендации (Candidate Recommendation), она постепенно приближается к официальному утверждению. Это будет первым с 1999 года изменением рекомендации XPath , которого активно ждут на рынке. Более того, уже началась работа над реализациями последних версий спецификации. При этом изменения настолько глубоки, что я не удивлюсь, если к моменту выхода стандарта XPath 1.0 будет выглядеть как черновой вариант XPath 2.0.
Рекомендация XPath 2.0 лежит в основе XSLT 2.0 и XQuery 1.0. Оба этих языка используют XPath в качестве ядра для выполнения запросов. В остальном они лишь добавляют операторы для форматирования результатов выполнения (ссылки приведены в разделе Ресурсы).
Существует множество различий между XPath 1.0 и XPath 2.0, в том числе следующих:
- Новая модель данных, в основе которой лежит понятие последовательности (sequence), а не набора узлов (node set).
- Возможность присваивать значения переменным. Ранее это делалось исключительно средствами внешнего языка, например, XSLT.
- Полная поддержка типов данных XML Schema.
- Множество новых функций, в том числе для работы с регулярными выражениями, датой и временем, а также для манипулирования строками.
- Поддержка комментариев. Разумеется, это не критически важная функция, однако они полезны при отладке запросов, так как позволяют комментировать фрагменты кода в процессе тестирования.
В этой статье основное внимание будет уделено новой модели данных, в особенности использованию последовательностей. В том, что касается гибкости, последовательности – это наиболее важное отличие от предыдущей версии языка.
Последовательности в XPath 2.0
Все элементы данных в процессе обработки в XPath 2.0 представляются в виде последовательностей. Последовательность – это упорядоченный, разнородный набор объектов. Объектами могут быть узлы XML-документа или атомарные значения. Значения могут быть любого, в том числе сложного, типа, который определен в рекомендации XML Schema. Для объявления последовательности в XPath необходимо заключить набор объектов в круглые скобки, разделив их запятыми (см. пример ниже).
(2, 'declencheur', 5.10)
В реальности практически любой правильно сформированный запрос на языке XPath 1.0 является корректным с точки зрения XPath 2.0. Другими словами, в XPath 2.0 поддерживается знакомый вам синтаксис, в частности, "путь" - это по-прежнему набор переходов, разделенных прямыми слэш-символами (/). Пример показан ниже.
/po:PurchaseOrder/po:ProductList/po:Name.
Однако в отличие от своего предшественника, в XPath 2.0 переходы обозначают элементы последовательности, а не просто узлы в дереве. При этом узлы могут выступать в качестве элементов.
Все ключевые понятия в XPath 2.0 были изменены с учетом появления последовательностей. Например, функции, которые в XPath 1.0 принимали наборы узлов в качестве аргументов, теперь работают с последовательностями.
Древовидная модель данных, характерная для XPath 1.0, имела определенные преимущества, учитывая, что XML-документы обладают иерархической структурой. Однако она также имела существенные ограничения, в частности, нельзя было генерировать деревья, а следовательно, невозможно передавать результат от одного запроса к другому для дальнейшей обработки. Было также невозможно писать сложные запросы, например в стиле SQL.
Работа с последовательностями
Как упоминалось ранее, в XPath 2.0 поддерживается синтаксис XPath 1.0, но при этом добавляется несколько новых операторов для работы с последовательностями. Первым из них я рассмотрю выражение for, которое (как следует из названия) служит для организации цикла по элементам последовательности.
Типичный пример выражения for показан в листинге 1.
Листинг 1. Пример использования for в XPath 2.0
for $line in /po:PurchaseOrder/po:OrderLines/po:Line
return $line/po:Price * $line/po:Quantity |
Показанное выше выражение XPath должно вычисляться над данными заказа, например, над документом, показанным в листинге 2. При вычислении выражения подсчитывается общая сумма для каждой строки заказа. Результат возвращается в виде следующей последовательности:
(29.99, 89.98, 80, 3.1)
Листинг 2. XML-документ для описания заказа
<?xml version="1.0" encoding="ISO-8859-1"?>
<po:PurchaseOrder xmlns:po="http://www.marchal.com/2006/po">
<po:Buyer>Pineapplesoft<po:Buyer>
<po:Seller>Bookstore<po:Seller>
<po:OrderLines>
<po:Line>
<po:Code type="ISBN">0-7897-2504-5<po:Code>
<po:Quantity>1<po:Quantity>
<po:Description>XML by Example<po:Description>
<po:Price>29.99<po:Price>
</po:Line>
<po:Line>
<po:Code type="ISBN">0-672-32054-1</po:Code>
<po:Quantity>2<po:Quantity>
<po:Description>Applied XML Solutions<po:Description>
<po:Price>44.99</po:Price>
</po:Line>
<po:Line>
<po:Code type="ISBN">2-10-005763-4<po:Code>
<po:Quantity>2<po:Quantity>
<po:Description>Huit Solutions Concrètes avec XML et Java</po:Description>
<po:Price>40.00<po:Price>
<po:Line>
<po:Line>
<po:Quantity>1<po:Quantity>
<po:Description>Internet Magazine<po:Description>
<po:Price>3.10<po:Price>
<po:Line>
</po:OrderLines>
<po:PurchaseOrder>< |
В листинге 1 for является ключевым словом, обозначающим, что необходимо перебрать всю последовательность строк и присвоить каждую из них переменной $product. Как и в XPath 1.0 для выбора последовательности используется путь: po:PurchaseOrder/po:OrderLines/po:Line.
Далее следует ключевое слово return, которое динамически создает последовательность. Затем на каждой итерации цикла к ней добавляется ноль, один или более элементов, после чего последовательность возвращается в качестве результата.
Использование последовательностей в качестве результатов имеет первостепенное значение, потому что это позволяет организовать их дальнейшую обработку при помощи XPath. Например, можно тривиальным образом подсчитать общую сумму заказа, передав показанную выше последовательность в функцию sum(). Эта функция также мигрировала из XPath 1.0 и теперь обрабатывает последовательности. Пример показан в листинге 3.
Листинг 3. Обработка результатов запроса в XPath 2.0
fn:sum(for $line in /po:PurchaseOrder/po:OrderLines/po:Line
return $line/po:Price * $line/po:Quantity) |
Как этот пример выглядел бы раньше
В листинге 4 показан аналог того же алгоритма, что и в листинге 3, но реализованный средствами XPath 1.0 и XSLT 1.0.
Листинг 4. Вычисление общей суммы заказа в XPath 1.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:po="http://www.marchal.com/2006/po"
xmlns:exslt="http://exslt.org/common"
version="1.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:variable name="lines">
<xsl:for-each select="/po:PurchaseOrder/po:OrderLines/po:Line">
<line-total><xsl:value-of select="po:Price * po:Quantity"/><line-total>
<xsl:for-each>
</xsl:variable>
<xsl:value-of select="sum(exslt:node-set($lines)/line-total)"/>
<xsl:template>
</xsl:stylesheet>
|
В листинге 4 также вычисляются суммы для каждой строки заказа, которые затем передаются в функцию sum(). Однако в XPath 1.0 переменные должны объявляться во внешнем языке (в данном случае XSLT), в частности, в этом примере промежуточные результаты сохраняются в переменной lines, которая затем передается во второе выражение XPath, вычисляющее общую сумму заказа.
Преимущества XPath 2.0 в том, что касается выразительности языка, становятся очевидны при сравнении листингов 3 и 4. В последнем случае требуется два выражения XPath вместо одного, при этом для передачи промежуточных результатов требуется дополнительный язык – XSLT. Кроме того, листинг 4 сложнее для понимания и труднее поддается оптимизации из-за разделения обработки запроса на два выражения XPath.
Условные выражения
В XPath 2.0 также появились выражения для условного перехода (if), приведенные в листинге 5. Синтаксис говорит сам за себя: в зависимости от истинности выражения в скобках, вычисляется либо секция then, либо секция else.
Листинг 5. Пример условного выражения
if(/po:PurchaseOrder/po:Seller = 'Bookstore') then 'ok' else 'ko' |
Кванторы
Обсуждение последовательностей было бы неполным, если не упомянуть о кванторах. Вкратце, кванторы (или квантифицированные выражения – quantified expressions) представляют собой проверки, выполняющиеся над последовательностью в целом. Существуют два квантора, обозначающиеся ключевыми словами every и some.
В листинге 6 показан пример квантора every. Он состоит из двух частей: сначала значение последовательности присваивается переменной (аналогично циклу), а затем указывается условие, которому должны удовлетворять элементы последовательности. Различие между квантором и циклом заключается в том, что результатом вычисления квантора является булево значение, а цикла – последовательность.
Если быть более точным, то значением квантора every является true, если все элементы последовательности удовлетворяют условию. Квантор some является истинным, если условие выполняется хотя бы для одного элемента.
Листинг 6. Пример использования кванторов
every $line in /po:PurchaseOrder/po:OrderLines/po:Line satisfies $line/po:Code |
Результатом вычисления выражения в листинге 6 над данными, показанными в листинге 2, будет false, потому что четвертая строка не содержит элемент po:Code. Если же заменить квантор every на some, то результатом будет true, ввиду того, что элемент po:Code содержится как минимум в одной строке.
Бесконечное множество комбинаций
Мощь XPath 2.0 обуславливается возможностью комбинировать выражения, создавая тем самым сложные запросы. Например, в листинге 7 показано выражения для подсчета общей суммы заказа в соответствии с другой формулой: в подсчете участвуют только строки, включающие код продукта, другие же попросту игнорируются (допустим, что данные продукты не могут быть доставлены заказчику). Код выглядит очень просто, так как все, что пришлось добавить в выражение цикла – это условное выражение if, возвращающее пустую (empty) последовательность в случае отсутствия кода продукта.
Листинг 7. Комбинирование выражений
fn:sum(for $line in /po:PurchaseOrder/po:OrderLines/po:Line
return if($line/po:Code) then $line/po:Price * $line/po:Quantity else ()) |
Таким образом, благодаря новой, основанной на последовательностях модели данных, XPath 2.0 значительно упрощает написание сложных запросов. Те из них, для описания которых ранее требовался значительный объем кода на XSLT, теперь могут создаваться исключительно средствами XPath.
Ресурсы Научиться
- Оригинал статьи: Working XML: Get started with XPath 2.0 (Бенуа Маршаль, developerWorks, май 2006 г.). (EN)
- Прочитайте статью "Языком какого типа является XSLT?" (developerWorks, февраль 2001 г., последняя редакция от апреля 2005 г.), в которой Майкл Кей (Michael Kay) рассказывает об истории создания, преимуществах и причинах по которым следует использовать XSLT. (EN)
- В статье "Факторы, оказавшие влияние на дизайн XQuery" (developerWorks, сентябрь 2003 г.) первопроходец XQuery Дон Чэмберлин (Don Chamberlin) высказывает свою точку зрения на тему появления языка XQuery, требованиях к языку запросов XML, а также его базовых принципов, лежащих в его основе. (EN)
- Ознакомьтесь со статьей "Первый взгляд на XQuery" (Кевин Уильямс, Kevin Williams, developerWorks, февраль 2002 г.), описывающей использование конструкций FLWR (“flower”), находящихся в центре языка XQuery. (EN)
- Прочитайте статью "Сравнение XSLT 2.0 и XQuery" (developerWorks, апрель 2006 г.), в которой Бенуа Маршаль сравнивает два языка, использующих XPath 2.0. (EN)
- Обратитесь к статье "Введение в XQuery" (developerWorks, июнь 2001 г., последняя редакция от января 2006 г.), автор которой Говард Кац (Howard Katz) описывает XQuery, в том числе историю создания, структуру документации и текущий вариант спецификации. (EN)
- Расширяйте свои знания XML, читая статьи и руководства в разделе XML на сайте developerWorks.
-
Сертификация по XML корпорации IBM: Узнайте, как стать сертифицированным разработчиком IBM в области XML и связанных с ним технологий. (EN)
Получить продукты и технологии
- Загрузите Saxon – интегрированный процессор XSLT и XQuery. (EN)
Обсудить
Об авторе  | 
|  | Бенуа Маршаль (Benoît Marchal) – бельгийский консультант. Он автор многих книг, посвященных XML, в том числе «XML на примерах, второе издание» XML
by Example, Second EditionБёнуа Маршаль специализируется в области XML, технологий Java и электронной коммерции. Более подробную информацию о нем можно получить на его сайте www.marchal.com. С ним можно связаться по адресу bmarchal@pineapplesoft.com. |
Выскажите мнение об этой странице
|  |