Не прошло и трёх лет с тех пор, как у меня зародилась мысль о том, что пора изучать XSLT -))). Мысль зародилась, а везде ещё стоял PHP 4 и зверствовал Salbotron
, который, мягко говоря, не отличался высокой производительностью. Да и редко какой браузер мог похвастаться поддержкой этого самого XSLT. По этим соображениям изучение столь перспективного направления я отложил до лучших времён. На данный момент можно смело заявить, что эти времена настали, поскольку вышел PHP 5 с поддержкой XSLT и сносной объектной моделью, а все топовые браузеры уже сами уверенно держат преобразования, только подавай XML. :)
Важные ссылки по теме, первоисточники:
Переводы на русский язык:
Для лучшего понимания всего происходящего я рекомендую читать спецификации в следующем порядке:
Особо пытливые могут также уделить внимание расширенному языку стилей XSL.
Что такое валидный XHTML? В первую очередь, это XML-документ, который должен соответствовать спецификации XML. Во-вторую, почти обычная HTML-страница, к которой все привыкли.
Почему нужен именно XHTML? Исключительно из соображений совместимости и кросс-браузерности. Страница в XHTML будет с большей вероятностью отображаться корректно в популярных браузерах, чем обычный HTML.
Для рядового клепателя страниц словосочетание XML-документ должно означать следующее:
<?xml ... ?>
<br />
, <p>...</p>
).<input type="radio" disabled="disabled" />
.&
, <
и >
всегда должны маскироваться. Например, <a href="?a=1&b=2">&</a>
. Исключение составляет только <![CDATA[...]]>
, внутри которого спецсимволы можно не маскировать. Также сам XHTML обязывает выполнять следующие условия:
Пример простого документа 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.
Что такое 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 |
<?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"
/> |
Основные атрибуты:
<?xml ... ?>
). Может иметь значение "yes" или "no" (актуально только для html). Если метод вывода объявлен html, то значения атрибутов encoding и media-type будут подставлены в заголовок страницы (<head>...</head>
) посредством метатега.
Объявление основного шаблона:
<xsl:template match="/"> |
Именно этот 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 |
---|---|---|
Файл с данными test.xml доступен по адресу //anton-pribora.ru/articles/xml/xslt-first-step/test.xml.
Файл со стилем test.xsl доступен по адресу //anton-pribora.ru/articles/xml/xslt-first-step/test.xsl.
Исходный код примера на PHP5 //anton-pribora.ru/articles/xml/xslt-first-step/test.phps.
Постоянный адрес статьи //anton-pribora.ru/articles/xml/xslt-first-step/. /Автор: Прибора Антон Николаевич, 2009 год/
Для получения результирующего документа при помощи 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.
«Товарищи, мы стоим на краю огромной пропасти! И я предлагаю сделать большой, решительный шаг вперёд!»