XSLT первый шаг
- Введение
- Валидный XHTML
- XSLT-преобразования
- Приложение
1. Введение
Не прошло и трёх лет с тех пор, как у меня зародилась мысль о том, что пора изучать XSLT -))). Мысль зародилась, а везде ещё стоял PHP 4 и зверствовал Salbotron, который, мягко говоря, не отличался высокой производительностью. Да и редко какой браузер мог похвастаться поддержкой этого самого XSLT. По этим соображениям изучение столь перспективного направления я отложил до лучших времён. На данный момент можно смело заявить, что эти времена настали, поскольку вышел PHP 5 с поддержкой XSLT и сносной объектной моделью, а все топовые браузеры уже сами уверенно держат преобразования, только подавай XML. :)
Важные ссылки по теме, первоисточники:
Переводы на русский язык:
Для лучшего понимания всего происходящего я рекомендую читать спецификации в следующем порядке:
- XML (это основа!)
- пространства имён (механизм разнородного XML-кода в одном файле)
- XPath (язык выборки элементов из дерева структуры)
- XSLT (преобразования)
- XHTML (то, к чему нужно стремиться)
Особо пытливые могут также уделить внимание расширенному языку стилей XSL.
2. Валидный XHTML
Что такое валидный XHTML? В первую очередь, это XML-документ, который должен соответствовать спецификации XML. Во-вторую, почти обычная HTML-страница, к которой все привыкли.
Почему нужен именно XHTML? Исключительно из соображений совместимости и кросс-браузерности. Страница в XHTML будет с большей вероятностью отображаться корректно в популярных браузерах, чем обычный HTML.
Для рядового клепателя страниц словосочетание XML-документ должно означать следующее:
- Документ содержит объявление XML-документа в самом начале страницы:
<?xml ... ?>
- Документ содержит один корневой элемент, в котором находятся все остальные.
- Все элементы (тэги) должны иметь закрывающую часть (
<br />, <p>...</p>).
- Атрибуты всегда имеют значение, которое обязательно указывается в кавычках (одинарных или двойных). Например,
<input type="radio" disabled="disabled" />.
- Управляющие символы
&, < и > всегда должны маскироваться. Например, <a href="?a=1&b=2">&</a>. Исключение составляет только <![CDATA[...]]>, внутри которого спецсимволы можно не маскировать.
Также сам XHTML обязывает выполнять следующие условия:
- Документ должен объявлять пространство имён, в рамках которого будут использоваться элементы HTML.
- Документ должен объявлять DOCTYPE перед корневым элементом и указывать в нём один из типов XHTML и соответствующий DTD.
Пример простого документа XHTML1.0:
Код - валидный xhtml |
<?xml version="1.0" encoding="windows-1251"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
<head>
<title>Это валидный XHTML!</title>
</head>
<body>
<p>Привет, мир!</p>
</body>
</html> |
И так обо всём по порядку.
-
Объявление XML-документа, в котором указывается его версия и кодировка.
<?xml version="1.0" encoding="windows-1251"?> |
Для большей безопасности кодировку нужно всегда выставлять, иначе могут возникнуть проблемы с невалидными (по отношению к дефолтной кодировке) символами.
-
Объявление типа документа и его схемы.
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
Для XHTML 1.0 есть три типа - Strict (строгое соответствие рекомендациям W3C), Transitional (переходный тип) и Frameset (использование фреймов). Для каждого из них предусмотрен отдельный DTD.
-
Объявление пространства имён и используемого языка.
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru"> |
Очень важно указывать ссылку именно в таком регистре и никак иначе. Это связано с тем, что в XML имена элементов и содержимое их атрибутов регистрозависимы.
Три версии XHTML1.0 предназначены для лучшей обратной совместимости:
Strict - обеспечивает наибольшее соответствие рекомендациям W3C со стороны браузеров. Однако и сам HTML-код должен следовать этим рекомендациям.
Transitional - менее строгое соответствие, которое заставляет браузер вести себя так, как если бы это был обычный HTML-документ.
Frameset - позволяет использовать фреймы.
Помимо XHTML1.0 на данный момент доступен XHTML1.1:
<?xml version="1.0" encoding="windows-1251"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>XHTML1.1</title>
</head>
<body>
<p>Это валидный XHTML1.1!</p>
</body>
</html> |
XHTML1.1 по сути является тем же XHTML1.0 Strict и призван вытеснить другие версии XHTML1.0. Однако, по сравнению с XHTML1.0 Strict, у него есть ряд отличий:
- Удалён атрибут
lang, его роль выполняет xml:lang. (Модуль [XHTMLMOD])
- Для элементов
a и map вместо атрибута name нужно использовать атрибут id. (Модуль [XHTMLMOD])
- Доступен набор элементов
ruby. (Модуль [RUBY])
Итак, если вам нужна наибольшая кросс-браузерность и совместимость с рекомендациями W3C, то XHTML1.1 самое оно!
Из этих соображений результатом моих преобразований будет именно XHTML1.1.
3. XSLT-преобразования
Что такое XSLT? Это язык преобразований XML-документа, который был разработан как часть расширенного языка стилей (XSL).
Зачем нужен XSLT? Он позволяет реализовать схему, при которой данные хранятся отдельно, а их представление отдельно. То есть, один XML-документ преобразуется с помощью другого XML-документа (XSL, в котором находятся XSLT-шаблоны) в конечный документ. Результатом может быть XML, HTML или текстовый документ любого формата.
Для того, чтобы воспользоваться XSLT-преобразованиями, в первую очередь нужно сформировать правильный стиль XSL и подключить его к XML-файлу.
Валидным XSL-документом является XML-документ, у которого задано пространство имён xsl и присутствует корневой элемент stylesheet. В самом простом случае стиль может выглядеть, например, так:
Файл - test.xsl |
<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet> |
Этот стиль не содержит каких-либо явных определений шаблонов или других элементов XSL. Однако, его уже можно использовать. Чтобы посмотреть результат, достаточно сформировать произвольный XML-документ и подключить к нему этот стиль:
Файл - test.xml |
<?xml version="1.0" encoding="windows-1251"?>
<?xml-stylesheet type='text/xsl' href='test.xsl'?>
<elements attr1="Главный атрибут">
<element attr1="мой атрибут1" attr2="мой атрибут2">Один</element>
<element>Два</element>
<element attr5="Халявный атрибут">Три</element>
</elements> |
За подключение стиля отвечает строка:
<?xml-stylesheet type='text/xsl' href='test.xsl'?> |
Если файлы text.xml и test.xsl созданы и находятся в одной папке, то с помощью любого XSLT-парсера можно преобразовать исходный test.xml в результирующий документ. В качестве парсера могут выступать все популярные браузеры (IE5+, FF2+, Opera9+ и другие), а также модули в языках программирования, например, в PHP. Если вы используете браузер, то достаточно открыть test.xml, и он сразу отобразит примерно такой результат:
При этом кодировка результата будет UTF-8, несмотря на то, что исходный документ был сформирован в windows-1251. К сожалению, браузеры обычно не позволяют просмотреть код результирующего документа, но модуль XSLT в PHP5 даёт возможность передать результирующий код в переменную, которую можно сохранить в файл. Поэтому, используя PHP, я приведу исходный код результирующего документа:
Результат - исходный код |
1 2 3 4 5 6 7
|
<?xml version="1.0"?>
Один
Два
Три
|
Этот код не является валидным XML-документом и тем более XHTML1.1. Для того, чтобы сформировать нужный код, я усложню исходный XSL-стиль и добавлю туда необходимые шаблоны и преобразования. При этом исходный XML-документ останется без изменений.
В качестве примера я приведу XSL-стиль, который при помощи XSLT будет выводить список атрибутов исходного XML-документа с их значениями, при этом будет формироваться валидный XHTML1.1. Итак, стиль:
Файл - test.xsl |
<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"
encoding="windows-1251"
omit-xml-declaration="no"
indent="yes"
media-type="text/xml"
doctype-public="-//W3C//DTD XHTML 1.1//EN"
doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Мой первый XSLT</title>
</head>
<body>
<div><xsl:text>Мой список:</xsl:text></div>
<ol>
<xsl:for-each select="/descendant-or-self::*/@*">
<li>
<xsl:if test="position() mod 2 = 0">
<xsl:attribute name="style">background-color: #eee;</xsl:attribute>
</xsl:if>
<xsl:value-of select="concat(name(), ' = ', .)" />
</li>
</xsl:for-each>
</ol>
<div>
<xsl:text>Разработчик парсера: </xsl:text>
<a>
<xsl:attribute name="href">
<xsl:value-of select="system-property('xsl:vendor-url')" />
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="system-property('xsl:vendor-url')" />
</xsl:attribute>
<xsl:value-of select="system-property('xsl:vendor')" />
</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet> |
Чтобы понять, как он работает, я распишу каждое действие отдельно:
-
Объявление XML-документа:
<?xml version="1.0" encoding="windows-1251"?> |
Документ сформирован в кодировке windows-1251, о чём сообщается в атрибуте encoding. Версию XML-документа желательно всегда указывать, это рекомендация W3C.
-
Затем идёт объявление корневого элемента, стиля:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
Обязательным атрибутом является определение пространства имён xsl через атрибут xmlns:xsl="http://www.w3.org/1999/XSL/Transform".
-
Следующим шагом в корневом элементе stylesheet объявляется, каким образом нужно формировать результирующий документ:
<xsl:output
method="xml"
encoding="windows-1251"
omit-xml-declaration="no"
indent="yes"
media-type="text/xml"
doctype-public="-//W3C//DTD XHTML 1.1//EN"
doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
/> |
Основные атрибуты:
- method="xml" - метод вывода документа. Результирующий документ будет в формате XML.
- encoding="windows-1251" - кодировка результирующего документа.
- omit-xml-declaration="no" - пропускать или нет начальное объявление XML-документа (
<?xml ... ?>). Может иметь значение "yes" или "no" (актуально только для html).
- indent="yes" - формировать отступы согласно уровню вложенности. Может иметь значение "yes" или "no".
- media-type="text/xml" - MIME-тип результирующего документа (используется только для метода вывода html).
- doctype-public="-//W3C//DTD XHTML 1.1//EN" - тип результируюшего документа (DOCTYPE)
- doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" - ссылка на DTD
Если метод вывода объявлен html, то значения атрибутов encoding и media-type будут подставлены в заголовок страницы (<head>...</head>) посредством метатега.
Объявление основного шаблона:
Именно этот XSLT-шаблон соответствует корню исходного дерева и будет вызван первым для преобразования. Атрибут match принимает значения, которые должны соответствовать языку поиска элементов XPath.
Остальные шаблоны, если таковые имеются, должны подключаться из этого шаблона при помощи средств XSLT.
-
Формирование XHTML-страницы. Оно начинается с элемента <html>, у которого указано пространство имён xhtml:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru"> |
Атрибут xmlns="http://www.w3.org/1999/xhtml" указывает на пространство имён xhtml, которое будет применено по умолчанию к этому элементу и всем дочерним элементам, у которых оно не задано явно.
Атрибут xml:lang="ru" указывает на язык, в котором сформирована страница (будущая).
Эта часть стиля была нужна для формирования атрибутики валидного XHTML1.1 кода.
Теперь что касается XSLT-преобразований:
Вставка простого текста:
<div><xsl:text>Мой список:</xsl:text></div> |
Текст "Мой список:" будет подставлен в тег <div> с маскированием управляющих символов. В принципе, этот код ничего особенно не делает, а стоит просто, как пример.
Организация цикла по выборке:
<xsl:for-each select="/descendant-or-self::*/@*"> |
Атрибут select принимает выражение XPath, на основе которого делает выборку. Если выборка вернула список узлов, то начинает работать цикл по каждому элементу.
В данном случае выборка вернёт список атрибутов для этого (корневого) и всех дочерних элементов.
-
Проверка условия:
<xsl:if test="position() mod 2 = 0"> |
В данном случае проверяется на чётность позиция элемента в списке выборки. Если тест возвращает true (порядковый номер элемента чётный), то срабатывает содержимое этого элемента.
-
Управление атрибутами вышестоящего элемента:
<xsl:attribute name="style">background-color: #eee;</xsl:attribute> |
В данном случае, если позиция элемента чётная (определяется вышестоящим if), то в стиль элемента <li> будет прописан серый цвет фона.
Вывод значений элемента:
<xsl:value-of select="concat(name(), ' = ', .)" /> |
Этот код подставит в вышестоящий элемент строку, собранную из имени текущего элемента и его значения. Содержимое атрибута select соответствует XPath.
-
Вывод ссылки на разработчика парсера XSLT:
<xsl:text>Разработчик парсера: </xsl:text>
<a>
<xsl:attribute name="href">
<xsl:value-of select="system-property('xsl:vendor-url')" />
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="system-property('xsl:vendor-url')" />
</xsl:attribute>
<xsl:value-of select="system-property('xsl:vendor')" />
</a> |
Этот небольшой код XSLT формирует ссылку на разработчика парсера XSLT. Во многих случаях она будет разная и содержать разные значения.
Результатом обработки этого стиля (test.xsl) станет такой код:
Результат - исходный код |
<?xml version="1.0" encoding="windows-1251"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Мой первый XSLT</title>
</head>
<body>
<div>Мой список:</div>
<ol>
<li>attr1 = Главный атрибут</li>
<li style="background-color: #eee;">attr1 = мой атрибут1</li>
<li>attr2 = мой атрибут2</li>
<li style="background-color: #eee;">attr5 = Халявный атрибут</li>
</ol>
<div>Разработчик парсера: <a href="http://xmlsoft.org/XSLT/" title="http://xmlsoft.org/XSLT/">libxslt</a></div>
</body>
</html> |
Этот код соответствует стандарту XHTML1.1 и был сформирован на основе исходного XML-документа. Для проверки можно воспользоваться валидатором от W3C, который расположен по адресу http://validator.w3.org/.
В браузере этот код выглядит примерно так:
| IE 6 |
FireFox 3 |
Opera 9.02 |
 |
 |
 |
4. Приложение
Ссылки на исходный код
Файл с данными test.xml доступен по адресу http://anton-pribora.ru/articles/xml/xslt-first-step/test.xml.
Файл со стилем test.xsl доступен по адресу http://anton-pribora.ru/articles/xml/xslt-first-step/test.xsl.
Исходный код примера на PHP5 http://anton-pribora.ru/articles/xml/xslt-first-step/test.phps.
Постоянный адрес статьи http://anton-pribora.ru/articles/xml/xslt-first-step/. /Автор: Прибора Антон Николаевич, 2009 год/
Использование PHP5 для обработки XSLT
Для получения результирующего документа при помощи PHP5 я использовал такой код:
Пример - использование XSLT в PHP5 |
<?php
// Вывод кода HTML в виде текста
header('Content-Type: text/plain;');
// Объект исходного XML-документа
$xml = new DOMDocument(null, 'windows-1251');
$xml->load('test.xml');
// Объект стиля
$xsl = new DOMDocument(null, 'windows-1251');
$xsl->load('test.xsl');
// Создание парсера
$proc = new XSLTProcessor();
// Подключение стиля к парсеру
$proc->importStylesheet($xsl);
// Обработка парсером исходного XML-документа
$parsed = $proc->transformToXml($xml);
// Вывод результирующего кода
echo $parsed;
// Запись файла с результирующим кодом
file_put_contents('parsed.html', $parsed);
?> |
Дополнительную информацию по использованию XSLT в PHP5 можно найти по адресу http://ru2.php.net/manual/ru/book.xslt.php.
Мысли вслух
«Товарищи, мы стоим на краю огромной пропасти! И я предлагаю сделать большой, решительный шаг вперёд!»