Язык преобразований XSLT
Что такое XSLT?
XSLT (eXtensible Stylesheet Language Transformations) - расширяемый язык преобразования листов стилей.
Язык XSLT служит транслятором, с помощью которого можно свободно модифицировать исходный текст. XLST играет решающую роль в утверждении XML в качестве универсального языка хранения и передачи данных. Область применения XSLT широка - от электронной коммерции до беспроводного Web.
Фактическая сборка результирующего документа происходит, когда исходный документ и лист стилей XSLT передаются в синтаксический анализатор XSLT (XSLT-процессор).
При использовании XSLT в среде Web синтаксический анализ может происходить либо на стороне пользователя (т.е. в пользовательском браузере), либо на стороне сервера.
Анализ XSLT на стороне клиента похож на процедуру применения каскадных листов стилей. В исходный документ нужно добавить тег
<?xml-stylesheet type="text/xsl" href="transform.xsl" ?>
Здесь transform.xsl - имя файла листа стилей XSLT.
Шаблоны
Каждый элемент XSLT начинается префиксом xsl:. Элемент xsl:stylesheet служит контейнером для листа стилей XSLT. Атрибут version="1.0" этого элемента определяет версию спецификации XSL.
Преобразования XSLT основаны на шаблонах. Шаблон определяется инструкцией xsl:template.
XSLT-процессор анализируют исходный документ и пытается найти подходящий XSL-шаблон. Если такой шаблон найден, то выполняются инструкции внутри него.
Обработка всегда начинается с шаблона, где match="/". Это значение пути адресации соответствует корневому узлу (в примере 1 это книга).
Пример 1
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t01.xsl" ?>
<книга>
<название>Мастер и Маргарита</название>
<автор>Михаил Булгаков</автор>
</книга>
Преобразование XSLT ( файл t01.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<h1 align="center">
<xsl:value-of select="//название"/>
</h1>
<h2 align="right">
<xsl:value-of select="//автор"/>
</h2>
</xsl:template>
</xsl:stylesheet>
Содержание элементов может быть извлечено из исходного документа двумя основными способами:
- инструкцией xsl:value-of. В этом случае содержание элемента используется без какой-либо дальнейшей обработки (см. пример 2);
- инструкцией xsl:apply-templates. В этом случае XSLT-процессор продолжает обрабатывать выбранные элементы, для которых определен шаблон (см. пример 3).
Пример 2
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t02.xsl" ?>
<книга>
<название>Мастер и Маргарита.</название>
<автор>Михаил Булгаков</автор>
</книга>
Преобразование XSLT ( файл t02.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<h2>
<xsl:value-of select="."/>
</h2>
</xsl:template>
<xsl:template match="автор">
<i>
<xsl:value-of select="."/>
</i>
</xsl:template>
</xsl:stylesheet>
Пример 3
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t03.xsl" ?>
<книга>
<название>Мастер и Маргарита.</название>
<автор>Михаил Булгаков</автор>
</книга>
Преобразование XSLT ( файл t03.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<h2>
<xsl:apply-templates/>
</h2>
</xsl:template>
<xsl:template match="автор">
<i>
 <xsl:value-of select="."/>
</i>
</xsl:template>
</xsl:stylesheet>
В качестве значений атрибутов match и select используются выражения, синтаксис которых похож на маршрут файловой системы:
| Выражение | Описание |
| / | Корневой узел |
| . | Текущий узел |
| .. | Родительский узел текущего узла |
| fruit | Узел fruit |
| fruit/lime | Подузел lime узла fruit |
| fruit/* | Все потомки узла fruit |
| /fruit | Узел fruit, являющийся прямым потомком корневого узла |
| @taste | Атрибут taste текущего узла |
| @* | Все атрибуты текущего узла |
| fruit@taste | Атрибут taste узла fruit |
| fruit/lime@taste | Атрибут taste узла lime, являющегося подузлом узла fruit |
| ..@taste | Атрибут taste родительского узла |
| // | Любое количество промежуточных узлов |
| fruit//lime | Все узлы lime, имеющие предка fruit |
| | | Знак разделения конкретных узлов |
| lime|grape | Узел lime и узел grape |
| [] | Предикатное выражение |
| fruit[lime] | Узел fruit, имеющий потомка lime |
| fruit[lime="fine"] | Узел fruit, имеющий потомка lime, значение которого равно fine |
| fruit[@taste] | Узел fruit, имеющий атрибут taste |
| fruit[@taste="5"] | Узел fruit, имеющий атрибут taste, значение которого равно 5 |
| count(fruit/*) | Количество потомков узла fruit |
| name() | Имя текущего узла |
Сравните результаты примера 4 (перечисление узлов) и примера 5 (все узлы).
Пример 4
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t04.xsl" ?>
<книга>
<название>Мастер и Маргарита</название>
<автор>Михаил Булгаков</автор>
</книга>
Преобразование XSLT ( файл t04.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="название|автор">
<div>
[шаблон
"<xsl:value-of select="name()"/>"
содержит
"<xsl:apply-templates/>"
]
</div>
</xsl:template>
</xsl:stylesheet>
Пример 5
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t05.xsl" ?>
<книга>
<название>Мастер и Маргарита</название>
<автор>Михаил Булгаков</автор>
</книга>
Преобразование XSLT ( файл t05.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<div>
[шаблон
"<xsl:value-of select="name()"/>"
содержит
"<xsl:apply-templates/>"
]
</div>
</xsl:template>
</xsl:stylesheet>
В путях адресации очень часто встречается "//". В начале пути адресации он обозначает: выбрать все узлы определенного типа в документе (пример 6). Внутри пути адресации он обозначает: выбрать все узлы, являющиеся потомками узла, указанного в первой части пути адресации (пример 7).
Пример 6
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t06.xsl" ?>
<source>
<AAA id="a1">
<BBB id="b1"/>
<BBB id="b2"/>
</AAA>
<AAA id="a2">
<BBB id="b3"/>
<BBB id="b4"/>
<CCC id="c1">
<DDD id="d1"/>
</CCC>
<BBB id="b5">
<CCC id="c2"/>
</BBB>
</AAA>
</source>
Преобразование XSLT ( файл t06.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//BBB"/>
<xsl:apply-templates select="//CCC"/>
<xsl:apply-templates select="//DDD"/>
<xsl:apply-templates select="//AAA"/>
</xsl:template>
<xsl:template match="AAA">
<div style="color:navy">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
<xsl:template match="BBB">
<div style="color:purple">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
<xsl:template match="CCC">
<div style="color:red">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
<xsl:template match="DDD">
<div style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
</xsl:stylesheet>
Пример 7
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t07.xsl" ?>
<source>
<AAA id="a1">
<BBB id="b1"/>
<BBB id="b2"/>
</AAA>
<AAA id="a2">
<BBB id="b3"/>
<BBB id="b4"/>
<CCC id="c1">
<DDD id="d1"/>
</CCC>
<BBB id="b5">
<CCC id="c2"/>
</BBB>
</AAA>
</source>
Преобразование XSLT ( файл t07.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="/source/AAA//CCC"/>
<xsl:apply-templates select="/source//AAA/BBB//*"/>
</xsl:template>
<xsl:template match="AAA">
<div style="color:navy">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
<xsl:template match="BBB">
<div style="color:purple">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
<xsl:template match="CCC">
<div style="color:red">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
<xsl:template match="DDD">
<div style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
</xsl:stylesheet>
С помощью режимов mode элемент может быть обработан многократно, причем каждый раз с различным результатом.
Пример 8
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t08.xsl" ?>
<source>
<AAA id="a1">
<BBB id="b1"/>
<BBB id="b2"/>
</AAA>
<AAA id="a2">
<BBB id="b3"/>
<BBB id="b4"/>
<CCC id="c1">
<CCC id="c2"/>
</CCC>
<BBB id="b5">
<CCC id="c3"/>
</BBB>
</AAA>
</source>
Преобразование XSLT ( файл t08.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//CCC" mode="red"/>
<xsl:apply-templates select="//CCC" mode="blue"/>
<xsl:apply-templates select="//CCC"/>
</xsl:template>
<xsl:template match="CCC" mode="red">
<div style="color:red">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
<xsl:template match="CCC" mode="blue">
<div style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
<xsl:template match="CCC">
<div style="color:purple">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:template>
</xsl:stylesheet>
Достаточно часто несколько шаблонов соответствует одному и тому же элементу в исходном XML. Поэтому надо решить, какой из них следует использовать. Для этого можно определить приоритеты с помощью атрибута priority. Если этот атрибут не определен, его приоритет вычисляется в соответствии с несколькими правилами. Вычисленные приоритеты располагаются в диапозоне от -0.5 до 0.5. Более подробная информация содержится в Спецификации XSLT.
Для примеров 9-14 исходным является XML из примера 8.
Пример 9 и пример 10 различаются приоритетами их шаблонов.
Пример 9
Преобразование XSLT
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//CCC"/>
</xsl:template>
<xsl:template match="CCC" priority="3">
<h3 style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h3>
</xsl:template>
<xsl:template match="CCC/CCC" priority="4">
<h2 style="color:red">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h2>
</xsl:template>
</xsl:stylesheet>
Пример 10
Преобразование XSLT
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//CCC"/>
</xsl:template>
<xsl:template match="CCC" priority="4">
<h3 style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h3>
</xsl:template>
<xsl:template match="CCC/CCC" priority="3">
<h2 style="color:red">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h2>
</xsl:template>
</xsl:stylesheet>
Пример 11 показывает действие по умолчанию в отсутствие атрибутов priority. Шаблон CCC имеет меньший приоритет по сравнению с CCC/CCC, поскольку он менее специфичный.
Пример 11
Преобразование XSLT
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//CCC"/>
</xsl:template>
<xsl:template match="CCC">
<h3 style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h3>
</xsl:template>
<xsl:template match="CCC/CCC">
<h2 style="color:red">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h2>
</xsl:template>
</xsl:stylesheet>
Сравните пример 12 и пример 13. Шаблоны CCC/CCC и AAA/CCC/CCC имеют одинаковый приоритет, и он выше, чем приоритет CCC. XSLT-процессор выбирает среди шаблонов с равным приоритетом тот, который будет последним в преобразовании, или сообщает об ошибке.
Пример 12
Преобразование XSLT
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//CCC"/>
</xsl:template>
<xsl:template match="CCC">
<h3 style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h3>
</xsl:template>
<xsl:template match="CCC/CCC">
<h2 style="color:red">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h2>
</xsl:template>
<xsl:template match="AAA/CCC/CCC">
<h2 style="color:green">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h2>
</xsl:template>
</xsl:stylesheet>
Пример 13
Преобразование XSLT
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//CCC"/>
</xsl:template>
<xsl:template match="CCC">
<h3 style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h3>
</xsl:template>
<xsl:template match="AAA/CCC/CCC">
<h2 style="color:green">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h2>
</xsl:template>
<xsl:template match="CCC/CCC">
<h2 style="color:red">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h2>
</xsl:template>
</xsl:stylesheet>
В примере 14 менее специфичный "*" имеет меньший приоритет по сравнению с CCC.
Пример 14
Преобразование XSLT
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//CCC"/>
<xsl:apply-templates select="//AAA"/>
</xsl:template>
<xsl:template match="CCC">
<h3 style="color:blue">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h3>
</xsl:template>
<xsl:template match="*">
<h3 style="color:green">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</h3>
</xsl:template>
</xsl:stylesheet>
Атрибуты
К атрибутам можно обращаться также, как и к элементам. Надо только поставить "@" перед именем атрибута.
Пример 15
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t15.xsl" ?>
<полка1>
<книга isbn="5-7890-0248X">
<данные название="Web-технологии"
автор="Колесников Д.Г."/>
</книга>
</полка1>
Преобразование XSLT ( файл t15.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="книга">
<p>
<b>
<xsl:text>ISBN: </xsl:text>
</b>
<xsl:value-of select="@isbn"/>
</p>
<p>
<b>
<xsl:text>Автор: </xsl:text>
</b>
<xsl:value-of select="данные/@автор"/>
</p>
<p>
<b>
<xsl:text>Название: </xsl:text>
</b>
<xsl:value-of select="данные/@название"/>
</p>
</xsl:template>
</xsl:stylesheet>
Атрибуты можно обрабатывать аналогично элементам.
Пример 16
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?> <?xml-stylesheet type="text/xsl" href="t16.xsl" ?> <полка1> <книга isbn="5-7890-0248X">"Web-технологии" </книга> </полка1>
Преобразование XSLT ( файл t16.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="книга">
<xsl:value-of select="."/>
<xsl:text> [</xsl:text>
<xsl:apply-templates select="@isbn"/>
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="@isbn">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
</xsl:stylesheet>
Также можно выбирать элементы, которые содержат или не содержат данный атрибут. Преобразование XSLT из примера 17 включает элементы, если определенный атрибут присутствует.
Пример 17
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t17.xsl" ?>
<source>
<BBB id="b1" checked="yes"/>
<BBB id="b2" checked="yes"/>
<BBB id="b3"/>
</source>
Преобразование XSLT ( файл t17.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="BBB[@checked]">
<p>
<xsl:text>BBB: </xsl:text>
<xsl:value-of select="@id"/>
</p>
</xsl:template>
</xsl:stylesheet>
Преобразование из примера 18 исключает элементы, содержащие указанный атрибут.
Пример 18
Преобразование XSLT
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="BBB[not(@checked)]">
<p>
<xsl:text>BBB: </xsl:text>
<xsl:value-of select="@id"/>
</p>
</xsl:template>
</xsl:stylesheet>
Повторение и сортировка
Инструкция xsl:for-each определяет шаблон, который применяется для каждого узла, выбранного с помощью атрибута select. Таким образом, инструкцию xsl:for-each можно использовать для организации простых циклов.
Пример 19
Исходный XML
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<?xml-stylesheet type="text/xsl" href="t19.xsl" ?>
<source>
<AAA id="a1">
<BBB id="b1"/>
<BBB id="b2"/>
</AAA>
<AAA id="a2">
<BBB id="b3"/>
<BBB id="b4"/>
<CCC id="c1">
<DDD id="d1"/>
</CCC>
<BBB id="b5">
<CCC id="c2"/>
</BBB>
</AAA>
</source>
Преобразование XSLT ( файл t19.xsl )
<?xml version="1.0" encoding="WINDOWS-1251" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="//BBB">
<div style="color:purple">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:for-each>
<xsl:for-each select="/AAA/CCC">
<div style="color:navy">
<xsl:value-of select="name()"/>
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id"/>
</div>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>