(Продолжение, начало см. МК № 48, 51—52 (167, 170—171))

Триединое целое

Искушенный читатель знает, что любая классификация и любое разграничение понятий условны. Можно с известной долей уверенности сказать, что книги по информационным технологиям делятся на две категории: «боекомплекты» для профессионалов и «заварочные пакеты» для «чайников». Я мог бы предложить и другую классификацию: книги хорошие, плохие и очень плохие (говорить об очень хороших книгах не приходится, так как сам жанр еще не сформировался окончательно, а классики столь редки). В категорию «боекомплектов» могут попасть как хорошие, так и очень плохие книги, в то время как произведения, от которых получаешь настоящее эстетическое наслаждение, могут быть заполнены целиком «заваркой». Ничего не поделаешь — классификация основательно влияет на восприятие того, что классифицируется. Что касается расширяемого языка стилей (eXtensible Style Language), то здесь процесс разделения на составляющие существенно упрощен самими создателями языка (см. http://www.w3.org/Style/XSL) — они предложили отдельные стандарты для следующих составных частей XSL:

язык выражений (expression language), используемый для обеспечения доступа к частям документа XML. Этот язык называется XML Path Language или, короче, Xpath;

язык для преобразования (трансформации) XML-документов—XSL Transformations (XSLT);

словарь XML для спецификации форматирования —XSL Formatting Objects (FO);

У тех энтузиастов, кто немного поработал с XSL (а среди интересующихся этим языком все в некотором роде новички, так как сам язык был частично стандартизирован всего два года назад), должны были заметить, что XPath и XSLT тесно переплетаются, и порой трудно понять, где заканчивается одно и начинается другое. Действительно, основатели языка предполагали, что XSLT будет использовать XPath для обращения к частям документа XML и их последующего преобразования и форматирования (в будущем — с помощью Formatting Objects). Поэтому конструкции XPath и XSLT очень часто встречаются вместе. Стандартизация и внедрение поддержки Formatting Objects в браузерах все еще находятся в стадии разработки, поэтому сейчас мы сосредоточимся на рассмотрении XPath и XSLT.

Не свернем с пути истинного

XPath («path» означает «путь») был задуман прежде всего для нахождения информации в XML-документе. При этом в процессе поиска активно используется логическая структура исходного документа. Используя XPath, в XML-документе можно отыскать структуры данных, удовлетворяющие определенным условиям, и применить к ним средства XSLT для преобразования или форматирования. Основные концепции XPath естественно вытекают из самого принципа иерархической организации данных в XML. Новое — это хорошо забытое старое, и в этом можно лишний раз убедиться, познакомившись с синтаксисом XPath, который очень напоминает иерархические структуры файловых систем UNIX и DOS. Думаю, что теперь пришло время пройтись по «путям» XPath.

Путь в XPath (location path) представляет собой последовательность из одного или нескольких шагов (location steps), разделенных значком «/». Как и в популярных операционных системах, пути бывают абсолютными (absolute location paths) и относительными (relative location paths). В последнем случае мы начинаем отсчитывать шаги от узла, называемого контекстным (context или context node), то есть от того, который сейчас, в данный момент рассматривается (понятие контекста напоминает понятие текущего каталога в операционных системах). На каждом шаге выбирается множество узлов, связанных с контекстным узлом с той или иной «степенью родства». Каждый шаг использует узлы, выбранные на предыдущем шаге, как контекст для дальнейшего поиска. Абсолютный путь начинается с символа «/» — это говорит о том, что шаги отсчитываются с корневого узла (root node).

Шаг в XPath, являющийся основной структурной единицей пути, обычно состоит из трех частей:

ось (axis), которая определяет тип отношения между контекстным узлом и теми узлами, которые выбираются на данном шаге;

тестовый узел (node test), который определяет тип и имя узлов, выбираемых на данном шаге;

предикаты (predicates), использующие разнообразные выражения, в том числе логические, для определения подмножества множества узлов, отобранных с помощью тестового узла

Шаг (location step) начинается с имени оси, далее дважды ставится двоеточие, после чего указывается имя тестового узла. Далее следуют выражения в квадратных скобках (наличие таких выражений необязательно). Пример:

child::product[position()=1]

В данном случае child — это имя оси, product — имя тестового узла, и [position()=1]Табл. 1 — предикат.

Подытожим сказанное о шагах в XPath. На каждом шаге в соответствии с осью и тестовым узлом отбирается некоторое множество узлов, которое потом фильтруется с помощью предикатов. Каждый узел этого множества является контекстным для последующих шагов. А сейчас, чтобы теоретические рассуждения на тему XPath не остались праздными разговорами, рассмотрим несколько конкретных выражений, приведенных в табл. 1.

Укоротим ось

Сразу видно, что предложенный синтаксис XPath обрекает нас на необходимость работы с довольно громоздкими выражениями, проигрывающими своим аналогам в UNIX и DOS в краткости и прозрачности. Создатели XPath Табл. 2предусмотрительно изобрели сокращенную запись выражений языка, во многом напоминающую синтаксис путей в популярных операционных системах. В этой упрощенной записи ось child можно опустить, что очень удобно, так как эта ось встречается в выражениях XPath на каждом шагу. Например, вместо child::people/child::person можно просто писать people/person. Рассмотрим также некоторые другие примеры, приведенные в табл. 2.

Ближе к делу

Пришло время «пощупать» XPath своими руками, а если выражаться научным языком, то сейчас мы попробуем использовать некоторые типичные выражения XPath с целью визуализации структур XML. Напомню, что для наших целей необходимо установить parser 3.0 (файл msxml3.exe), если он у вас еще не инсталлирован. Несложная процедура установки кратко описана в статье «XSL — зеркало для XML».

Создайте файл с именем myXPathTest.xml и занесите в него следующий текст:

<?xml version="1.0" encoding="Windows-1251" ?><?xml:stylesheet type="text/xsl" href="myXPathTest.xsl" ?><doc><para><emphasis>Это нужно выделить курсивом, а <emphasis> это нужно, кроме того, написать жирным шрифтом. </emphasis> Это снова — просто курсив. </emphasis></para><para1><level1>Это <note>первый</note> уровень. <level2>Это <note>второй</note> уровень. <level3>Это <note>третий</note> уровень.</level3></level2></level1></para1><para2><level1>Это <note>первый</note> уровень. <level2>Это <note>второй</note> уровень. <level3>Это <note>третий</note> уровень.</level3></level2></level1></para2><para><grandFather>Это — дедушка. <father>Это — папа. <child>Это — первый ребенок <name>John</name>, </child><child>а это — второй ребенок <name>Ivan</name>. </child></father></grandFather></para></doc>

Создайте файл myXPathTest.xsl и наберите в нем следующее:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="para|para1|para2"><p><xsl:apply-templates /></p></xsl:template><xsl:template match="emphasis"><i><xsl:apply-templates /></i></xsl:template><xsl:template match="emphasis/emphasis"><b><xsl:apply-templates /></b></xsl:template><xsl:template match="para1/level1/note"><b><xsl:apply-templates /></b></xsl:template><xsl:template match="para2/level1//note"><b><xsl:apply-templates /></b></xsl:template><xsl:template match="grandFather//child[2]"><b><xsl:apply-templates /></b></xsl:template><xsl:template match="father/child[name='John']"><i><xsl:apply-templates /></i></xsl:template></xsl:stylesheet>

Что касается исходного документа XML, то здесь, думаю, все ясно. Давайте разберемся со стилевой таблицей XSL. Конструкция

<xsl:template match="para|para1|para2"><p><xsl:apply-templates /></p></xsl:template>

позволяет применить форматирование в виде отдельных параграфов элементов para, para1 и para2. Символ «|» в данном случае обозначает операцию объединения множеств узлов. Конструкции

<xsl:template match="emphasis"><i><xsl:apply-templates /></i></xsl:template>

и

<xsl:template match="emphasis/emphasis"><b><xsl:apply-templates /></b></xsl:template>

иллюстрируют форматирование вложенных элементов (в данном случае элементов emphasis) с использованием выражений XPath. Из данного примера видно, что жирным шрифтом оформляются только те элементы emphasis, которые вложены в элементы того же типа. «Внешний» элемент emphasis оформляется только курсивом, так как он не содержится в других элементах emphasis.

Следующие две конструкции

<xsl:template match="para1/level1/note">…</xsl:template>

и

<xsl:template match="para2/level1//note">…</xsl:template>

показывают различие в использовании выражений «/» и «//» в XPath. В первом случае находятся и форматируются только дочерние узлы note узла level1. Во втором случае аналогичное форматирование применяется ко всем потомкам note того же самого элемента level1.

Шаблон

<xsl:template match="grandFather//child[2]">…</xsl:template>

служит для форматирования вторых дочерних узлов (с именем child) для всех потомков узла grandFather. В исходном документе XML имеется только один потомок элемента grandFather, который имеет дочерние узлы child, — следовательно, в данном случае будет отформатирован только один элемент.

Конструкция

<xsl:template match="father/child[name='John']">…</xsl:template>

используется для форматирования только тех узлов child, текстовое содержание которых представляет собой строку символов «John». Заметьте, что в данной конструкции эта строка символов заключена в одинарные кавычки, так как само значение атрибута match нужно указывать в кавычках.

А сейчас откройте файл myXPathTest.xml в окне Internet Explorer, и вы увидите результат «слияния» исходного файла XML со стилевой таблицей:

(Продолжение следует)