Лекция 06-07 (XSLT) new

advertisement
Кафедра «ОСУ»
Весенний семестр 2010/2011 уч. года
Языки описания информации
Лекция 4.
XSLT
Описание преобразования XMLдокументов
• Достаточно часто требуется составленные XMLдокументы преобразовывать в другие форматы.
• Это связано с тем, что они могут передаваться
между различными приложениями, которые
требуют на входе XML-документы, имеющие
другой синтаксис (схему описания).
• Кроме того, может потребоваться динамически
преобразовать структуру документа в
интерактивный документ, например для того,
чтобы привести ее в соответствие запросам
пользователя.
Виды преобразования
XML-документов
• структурные преобразования – преобразование XMLдокумента из одного синтаксиса (схемы) в другой
синтаксис конкретного языка разметки (аналогично
выполнению перевода между естественными языками);
• создание динамических документов – на основе
предпочтений пользователя появляется возможность
изменения порядка, сортировки и фильтрации частей
XML-документов (например при выполнении «щелчка»
на заголовке столбца таблицы можно изменить порядок
ее строк);
• преобразование в язык формирования изображения –
подготовка документа для визуального представления в
какой-либо форме пользователя, например в HTML,
Wireless Application Protocol (WAP), VOXML или в
формате масштабируемой векторной графики.
• Преобразование XML-документов можно
описать с помощью двух языков:
– XSLT и
– XQuery.
• Они позволяют выполнять поиск требуемых
частей XML-документа, выполнять их
преобразование и добавлять узлы в
результирующее дерево.
• Для выполнения поиска в XML-документах,
языки XSLT и XQuery используют пути доступа
языка XPath.
Использование языка XSLT
• в большинстве случаев, используется для
преобразования XML-документов в документы на
языке HTML (или XHTML) для их показа
пользователям.
• для создания других, основанных на XML,
форматов преставления, как например, в
документы на языке Scalable Vector Graphics
(SVG).
• для преобразования XML-документов из одной
структуры в другую при выполнении транзакций
между организациями.
Использование языка XQuery
• наиболее часто используется при выполнении
запросов к хранилищам XML-документов или
базам данных, содержащих XML-данные.
– Такая задача может быть решена и с помощью
XSLT, но XQuery лучше подходит для ее решения.
• На практике язык XQuery наиболее вероятно
используется в СУБД или при разработке
программ, работающих с БД.
• В языке XQuery не используется XMLсинтаксис, что облегчает его применение при
разработке программ.
Язык XSLT
(расширяемый язык преобразований,
XSL таблицы стилей)
(eXtensible Stylesheet Language Transformations)
• Язык преобразований XML-документов – XSL
Transformations (XSLT) является частью более
общего стандарта – расширяемого языка таблиц
стилей – eXtensible Stylesheet Language (XSL).
• XSL это набор стандартизированных языков для
выполнения преобразования и визуализации
XML-документов. XSL включает
– язык преобразований XML-документов – XSL
Transformations (XSLT)
– язык разметки типографских макетов – XSL Formatting
Objects (XSL-FO).
Пример XSL-FO документа
<?xml version="1.0" encoding="iso-8859-1"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="my-page">
<fo:region-body margin="1in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<fo:block>Hello, world!</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
Язык XSL-FO
• XSL Formatting Objects (XSL-FO) - язык разметки типографских макетов и
иных предпечатных материалов.
• Документ на языке XSL-FO (XSL Formatting Objects) представляет собой XML
файл, в котором хранятся данные для печати или вывода на экран
(например, просто текст).
– Эти данные находятся внутри специальных тэгов fo:block, fo:table, fo:simplepage-master и д.р., с помощью которых задаются отступы, переводы строк и
т.д.
• Общая идея использования XSL состоит в следующем
– вначале пользователь создаёт документ в виде обычного XML документа (а не
в виде форматированного объекта XSL-FO).
– затем применяется XSLT-преобразование, которое формирует XML документ
на языке XSL-FO.
– Полученный XSL-FO документ передаётся приложению (FO-процессор),
который конвертирует XSL-FO-документ в какой-либо читаемый и/или
печатаемый формат.
• Наиболее часто используется преобразование в PDF или RTF-файлы, либо
просто выполняется отображение документа в окне программы.
• Однако, язык XSLТ имеет более широкое
применение, чем для формирования XSL-FO
документов.
• Он активно используется в области webпрограммирования и генерации отчётов.
• Одной из задач, решаемых языком XSLT, является
отделение данных от их представления, как часть
общего шаблона MVC (Model-View-Controller).
• Другой стандартной задачей является
преобразование XML-документов с одного
конкретного языка разметки (XML-схемы) в
другой конкретный язык разметки.
Язык XSLT
• С помощью языка XSLT можно преобразовать XMLдокумент в любой другой XML документ, например,
HTML, WML или RTF.
• Для обработки XML документа c помощью XSLT,
необходимо в него включить следующую инструкцию:
<?xml-stylesheet type="text/xsl" href="my-style.xsl"?>
• Самым доступным XSLT-процессором на данный
момент для Microsoft Windows является MSXML
(поставляется с Internet Explorer начиная с версии 4.5 и
выше);
– для систем на основе GNU — xsltproc.
Преобразование XML документа
Использование XSLT преобразования
Использование XSLT на промежуточном
уровне ПО
Как XSLT работает
Общее описание языка XSLT
• Язык XSLT является декларативным языком, т.е. с
его помощью описывается не
последовательности действий, а объявляется
(декларируются) набор правил преобразования.
• Каждое из таких правил может:
– обрабатывать определенный фрагмент входного
документа с тем, чтобы сгенерировать фрагмент
выходного документа;
– вызывать другие правила, таким образом
обеспечивая обработку документов сколь угодно
сложной структуры.
• В результате применения XSLT-преобразования,
состоящего из набора правил, к XML-документу
(исходное дерево) образуется результирующее
дерево, которое может быть сериализовано
(представлено в линейной последовательности
символов) в виде другого XML-документа, HTMLдокумента или простого текстового файла.
• Применение правил (а иногда и преобразование)
к различным частям обрабатываемого XMLдокумента описывается с помощью языка
запросов XPath.
• В общем случае, в преобразовании исходного XMLдокумента участвуют три документа:
– исходный XML-документ, который подвергается
преобразованию;
– документ с описанием преобразования (XSLT-документ);
– результирующий XML-документ, который является
результатом преобразования.
• Следует отметить, что XSLT-обработчики
работают не с документами, а со структурами.
• Чтобы XSLT-процессор мог работать c XMLдокументом, он вначале должен быть
преобразован в иерархическую структуру,
состоящую из узлов (аналогичной структуре,
которая используется в языке XPath).
• Процесс выполнения преобразования делится
на три этапа:
– вначале XSLT-процессор выполняет
грамматический анализ исходного документа и
документа преобразования и создает для них
иерархические структуры данных (деревья);
– к дереву исходного документа применяются
правила, описанные в преобразовании и
создается дерево результирующего документа;
– созданное дерево описывается в виде
результирующего файла.
• Два основных шага для выполнения
преобразования с использованием XSLTдокумента:
– Создание файла с XSLТ-преобразованием.
– Связывание XML-документа с созданным XSLTпреобразованием.
Элементы языка XSLT
• Язык XSLT является конкретным языком разметки.
• Корневым элементом языка XSLT является элемент
xsl:stylesheet.
• Кроме корневого элемента в XSLT определено около
полусотни других элементов. Из них:
– 17 элементов верхнего уровня, которые могут быть
непосредственно вложены в корневой элемент
xsl:stylesheet – называемые декларациями.
– более тридцати элементов, которые можно записывать в
содержании элементов верхнего уровня (в том числе
инструкции XSLT).
• Все элементы необязательны и могут располагаться в
любом порядке, за одним исключением: декларации
xsl:import, если такие элементы используется, то они
должны быть записаны первыми.
Декларации
• Элементы верхнего уровня, которые являются
дочерними для корневого элемента:
–
–
–
–
–
–
–
–
xsl:import,
xsl:include,
xsl:attribute-set,
xsl:function,
xsl:output,
xsl:param,
xsl:template,
xsl:variable.
• Все декларации, кроме xsl:param и xsl:variable, можно
записывать только на верхнем уровне вложенности,
непосредственно в корневом элементе xsl:stylesheet.
Инструкции
• Инструкции XSLT это элементы, которые можно
включать в конструкторы узлов результирующего
дерева.
• К инструкциям, в частности, относятся:
– элементы, создающие узлы всех семи видов и
последовательности узлов (xsl:element, xsl:attribute,
xsl:text, xsl:comment, xsl:processing-instruction,
xsl:namespace, xsl:result-document, xsl:sequence);
– элементы xsl:apply-templates, xsl:value-of, xsl:variable и
др. (всего более двадцати элементов);
– элементы, управляющие выбором правил
преобразовании xsl:if, xsl:for-each, xsl:choose;
– элементы, копирующие узлы xsl:copy, xsl:copy-of.
Описание XSLT–преобразования
• XSLT-преобразование описывается в виде XMLдокумента, в котором:
– задается пространство префикс xsl для пространства имен
http://www.w3.org/1999/XSL/Transform;
– используется корневой элемент xsl:stylesheet (или его
синоним xsl:transform), имеющий один обязательный
атрибут version, в котором указывается версия языка,
использованная при создании этого преобразования.
• Например, XSLT-документ может иметь следующий
вид:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- один или несколько правил …-->
</xsl:stylesheet>
• Корневой элемент xsl:stylesheet должен
включать одно или несколько – правил,
описываемых элементом xsl:template.
• В каждом правиле
– с помощью атрибута match задается шаблон
узлов, к которым оно может быть применено
(условия срабатывания) и
– действия, которые должны быть выполнены для
узлов, которые соответствуют условию
(содержание элемента xsl:template).
• XSLT-процессор использует такие правила для
проверки, может ли оно быть применено для
текущих элементов в обрабатываемом XMLдокументе.
• Атрибуту match правила задается путь доступа
на языке XPath (образец, pattern), который
используется
– не для выбора узлов из исходного XML-документа,
– а для проверки соответствия текущего
обрабатываемого узла данному правилу.
• Каждое XSLT-преобразование может
содержать одно и только одно правило с
атрибутом match, который имеет значение "/",
следующего вида:
<xsl:template match="/">
<!-- дочерние элементы … -->
</xsl:template>
• Данное правило выполняется для корневого
элемента всего XML-документа. Таким
образом, оно содержит инструкции для
отображения всего XML-документа.
• Кроме правила с шаблоном, соответствующим
корневому элементу, XSLT-преобразование
может включить одно или несколько
дополнительных правил с инструкциями для
отображения определенных частей структуры
XML-документа;
• каждая из них должна иметь образец
(шаблон, заданный с помощью пути доступа
на языке XPath), описывающий данную часть
структуры.
Задание формат создаваемого
документа
• Описывается с помощью элемента xsl:output:
<xsl:output method="xml|html|text|name" version="string"
encoding="string" omit-xml-declaration="yes|no" indent="yes|no" />
• Все эти атрибуты являются не обязательными и имеют следующий
смысл:
– method – задает формат результирующего документа (по умолчанию
method="xml");
– version – номер версии выходного формата;
– encoding – код используемой кодировки;
– omit-xml-declaration –
• "yes" указывает, что XML-объявление (<?xml...?>) не нужно записывать в
результирующий документ;
• "no" – XML-объявление должно записываться (по умолчанию omit-xmldeclaration="no");
– indent –
• "yes" указывает, что текст результирующего документа должен записываться с
отступами в соответствии с его иерархической структурой.
• "no" – текст записывается без отступов.
• Например, элемент xsl:output может быть
записан следующим образом:
<xsl:output method="html" indent="yes"/>
Связывание XSLT-преобразования с
XML-документом
• Если для обработки XML-документа используется одно и то же XSLTпреобразование, то данный документ можно связать с этим
преобразованием с помощью инструкции обработки xml-stylesheet,
имеющей следующий вид:
<?xml-stylesheet href ="URI" type=”тип” title="название" media="тип”
носителя" charset=" кодировка" alternate="yes" | "no" ?>
• Инструкция xml-stylesheet содержит следующие шесть атрибутов два из
которых, href и type, являются обязательными:
– href – указывает местоположение XSLT-преобразования, закрепляемого за
документом;
– type – указывает тип преобразования (MIME код), закрепляемый за XSLTдокументом, обычно "text/xsl";
– title – задает название присоединяемого преобразования; особого значения при
обработке не имеет – просто поясняет назначение данного преобразования;
– media – указывает тип носителя или устройства, для которого предназначен
результирующий документ (предопределенные типы: screen, tty, tv, projection,
handheld, print, braille, aural, all);
– charset – определяет кодировку, в которой создано преобразование;
– alternate – указывает, является ли данное преобразование основным ("no") или
альтернативным ("yes"). Значением этого атрибута по умолчанию является "no".
• Инструкция xml-stylesheet должна
предшествовать корневому элементу.
• Стандартным способом использования xmlstylesheet является следующий:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="mytransform.xsl" ?>
<body>
<!-- . . . -->
</body>
• Данная инструкция xml-stylesheet указывает на
то, что этот документ должен быть обработан
XSLT-преобразованием mytransform.xsl.
Контекст преобразования
• При выполнении преобразования каждая
инструкция языка XSLT, каждый из его элементов
обрабатывается в некотором контексте.
• Контекст преобразования включает текущее
множества узлов и текущий узел, который
обрабатывается в данный момент.
• XSLT-процессор поочередно обрабатывает
каждый из узлов текущего множества (при этом
делая этот узел текущим узлом) и полученные
фрагменты объединяет в одно результирующее
дерево.
• Вначале преобразования текущее множество
контекста состоит из единственного узла – узла
документа.
• Он становится текущим и обрабатывается
соответствующим правилом.
• Контекст преобразования может изменяться
только двумя элементами: xsl:apply-templates и
xsl:for-each. Каждый из этих элементов вычисляет
множество узлов, которое становится текущим и
затем обрабатывается. После этого контекст
преобразования восстанавливается до того
состояния, каким он был перед обработкой.
• Вначале преобразования текущее множество
контекста состоит из единственного узла – узла
документа.
• Он становится текущим и обрабатывается
соответствующим правилом.
• Контекст преобразования может изменяться только
двумя элементами: xsl:apply-templates и xsl:for-each.
• Каждый из этих элементов вычисляет множество
узлов, которое становится текущим и затем
обрабатывается.
• После этого контекст преобразования
восстанавливается до того состояния, каким он был
перед обработкой.
Правила языка XSLT
• Преобразование в XSLT состоит не из
последовательности операторов, а из множества
правил, каждое из которых обрабатывает свою
часть XML-документа.
• Как уже отмечалось, язык XSLT является
декларативным, т.е. вместо задания
последовательности действий, в XSLT-документе
описываются правила преобразования.
• Каждое из этих правил может в свою очередь
вызывать другие правила, таким образом
обеспечивая обработку документов сколь угодно
сложной структуры.
Объявление правил
• Правила объявляются с помощью элемента
(декларации) xsl:template, который имеет
следующий синтаксис:
<xsl:template match="пaттepн" name="имя"
priority="число" mode="имя">
<!-- Содержимое: несколько элементов xsl:param,
тело правила -->
</xsl:template>
Атрибут правила match
• match – задает путь доступа (XPath-выражение, паттерн),
определяющего последовательность узлов исходного
дерева, для преобразования которых следует применять
это правило.
• Правила, в которых определен атрибут match, вызываются
при помощи инструкции xsl:apply-templates)
– заданных либо во встроенных правилах, либо в правилах XSLTпреобразования.
• Например, следующее правило будет вызываться для
обработки элементов bold, который должны заменяться на
элементы <b>:
<xsl:template match="bold">
<b><xsl:value-of select="." /></b>
</xsl:template>
Атрибут правила name
• name – имя правила, используемое для задания именованных
правил, которые могут вызываться вне зависимости от текущего
контекста, и даже вести себя как функции, т.е. принимать на вход
параметры и возвращать некоторые значения.
• Вызвать их можно только по имени с помощью элемента xsl:calltemplate.
• Например, следующее правило не обрабатывает какие-либо
определенные узлы, а может вызываться по имени (они будут
включать в результирующее дерево текстовое содержание
текущего узла):
<xsl:template name="bold">
<b><xsl:value-of select="."/></b>
</xsl:template>
• При определении правила нужно обязательно указать хотя
бы один из атрибутов match или name, причем эти
атрибуты могут присутствовать в xsl:template
одновременно.
Атрибутs правила mode и priority
• mode – указывает режим правила; с помощью
режимов можно задавать различные
преобразования для одних и тех же частей
документа (будут рассмотрены далее).
• priority – задает приоритет правила;
используется для разрешения конфликтов,
когда один и тот же узел исходного документа
может быть обработан различными
правилами.
Описание содержания правила
• Элемент xsl:template задает только условия, при
которых данное правила будет вызываться на
выполнения.
• Что конкретно будет делать данное правило
задается в содержании элемента xsl:template.
• Тело правила может содержать
–
–
–
–
любые инструкции по обработке,
текстовые узлы,
комментарии, и
литеральные результирующие элементы
при условии, что не будет нарушен синтаксис
XML-документа.
• Тело правила может содержать следующие
элементы XSLT, называемые инструкциями:
– xsl:apply-imports;
– xsl:apply-templates;
– xsl:attribute;
– xsl:call-template;
– xsl:choose;
– xsl:comment;
– xsl:copy; xsl:copy-of;
– xsl:element;
xsl:fallback;
xsl:for-each;
xsl:if;
xsl:message;
xsl:number;
xsl:param;
xsl:processing-instruction;
xsl:text;
xsl:value-of;
xsl:variable.
Пустые правила
• Тело правила может быть также и пустым.
• В этом случае результат обработки узлов,
соответствующих этому правилу будет пустым
(т.е. ничего в результирующее дерево
переноситься не будет).
• Например, если в преобразовании содержится
правило вида
<xsl:template match="comment()" />
то каждый раз, встретив узел комментария и
обрабатывая его этим правилом, процессор
будет получать пустой результат.
Пример простого правила
• содержит литеральный элемент body, текстовый
узел и элемент xsl:copy-of (выделено жирным
шрифтом):
<xsl:template match="page">
<body>
<xsl:value-of select="."/>
</body>
Комментарии:
<xsl:copy-of select="comment()"/>
</xsl:template>
• При выполнении данного правила в
результирующий документ будет выведен
– элемент body, так как он описан в данном правиле,
при этом его содержимое будет вычислено –
текстовое значение элемента page будет скопировано
в результирующее дерево;
– затем выведен текст «Комментарии:», а
– затем элемент xsl:copy-of будет заменен множеством
дочерних комментариев текущего узла.
• Следует отметить, что текстовый узел в данном
случае состоит не только из строки
"Комментарии:".
– Он включает также все пробельные символы и
символы переноса строки.
Литеральные результирующие
элементы
• В содержимом правила могут быть записаны
элементы, которые не принадлежат к
пространству имен XSLT (т.е. не относятся к языку
XSLT).
• Например, в показанном ниже правиле элемент
<b> не является элементом языка XSLT:
<xsl:template match="b">
<b/>
</xsl:template>
• Такие элементы называются литеральными
результирующими элементами.
• Если при обработке правила XSLT-процессор находит литеральный
результирующий элемент, то он выводит его в результирующий
документ без изменений (со всеми имеющимися атрибутами).
• Если один литеральный элемент включает другой, как например:
<xsl:template match="a">
<a>
<b/>
</a>
</xsl:template>
• то при выполнении такого правила XSLT-процессор создаст элемент
a и включит в него обработанное содержимое – то есть элемент b.
• Результатом выполнения такого правила будет XML-фрагмент:
<a>
<b/>
</b>
• Если теперь включить в содержимое элемента <a>
XSLT-инструкцию xsl:value-of select:
<xsl:template match="a">
<a>
<xsl:value-of select="." />
</a>
</xsl:template>
• то при выполнении этого правила XSLT-процессор
создаст результирующий элемент a и включит в него
результат выполнения его содержимого, то есть
элемента xsl:value-of.
• Этот элемент создаст текстовый узел со строковым
значением текущего узла контекста преобразования.
• Например, если это правило применяется к
элементу а вида
<а href="http: //www.mysite.ru">Добро
пожаловать!</a>
• то будет получен следующий результат:
<a> Добро пожаловать!</a>
• При переносе литеральных элементов в результирующий
документе, XSLT-процессор копирует также все атрибуты и узлы
пространств имен, которые ассоциируются с данным элементом.
• Например, в результате выполнения следующего правила:
<xsl:template match="a">
<a href="http://www.mysite.ru"
xmlns:xhtml="http://www.w3. org/1999/xhtml">
<xsl:value-of select="." />
</a>
</xsl:template>
• будет сформирован следующий элемент:
<a href="http:/ /www. xsltdev.ru"
xmlns :xhtml="http: //www.w3.org/1999/xhtml">
Добро пожаловать!
</a>
Шаблоны значений атрибутов
• Во многих элементах XSLT в качестве значений
атрибутов могут быть указаны специальные шаблоны,
называемые шаблонами значений атрибутов.
• Такие шаблоны задают атрибутам вместо простых
строковых значений результаты вычисления
выражений, которые заключаются в фигурные скобки
({ }).
• Например: href="{../@dir}/(@filename}".
• Если XSLT-процессор встречает внутри значения
атрибута выражение в таких скобках, то он вычисляет
это выражение и заменяет его в атрибуте вместе с
фигурными скобками на результат вычисления в
строковом виде.
• В одном атрибуте можно использовать несколько
выражений – каждое из них должно быть заключено в
фигурные скобки.
• Рассмотрим пример: имеется список файлов на
графические изображения описанный в виде XMLдокумента:
<images dir="/images">
<image filename="rose.jpg"/>
<image filename="orchide.gif"/>
<image filename="primul.gif "/>
</images>
• Каталог, в котором хранятся данные файлы указан в
атрибуте dir элемента images, a иконки имеют те же имена
файлов, что и большие изображения, но с префиксом "th_".
• Требуется создать гиперссылки на эти графические изображения в виде
иконок.
• Это можно сделать с помощью следующего преобразования, в котором
использую шаблоны значений атрибутов:
<xsl:template match="images/image">
<а href="{../@dir}/(@filename}">
<img src="{../@dir}/th_{@filename}"/>
</xsl:template>
• Результатом данного преобразования будет следующее:
<а href="/images/rose.jpg">
<img src="/images/th_rose.jpg"/>
</a>
<a href="/images/orchide.gif">
<img src="/images/th_orchide.gif"/>
</a>
<a href="/images/primal, gif”>
<img. src="/ images /th_primul.gif "/>
</a>
Вызов правил на выполнение
• Правила вызываются на выполнение
(срабатывают) в следующих случаях:
– если шаблон правила подходит для обработки
текущего узла исходного документа (т.е. его
шаблон заданный в атрибуте match соответствует
текущему узлу);
– если правила рекурсивно вызываются с помощью
элемента xsl:apply-templates;
– если правило имеет атрибут name и вызываются
по имени с помощью элемента xsl:call-template.
• Элемент xsl:apply-templates указывает выполнять
рекурсивную обработку всех узлов, которые
являются потомками узлов, выбранных
родительским элементом xsl:template.
• Данный элемент чаще всего записывается внутри
элемента xsl:template и имеет следующий
синтаксис:
<xsl:apply-templates select="выражение" mode= "режим" >
<!-- Содержимое: несколько элементов xsl:sort или
xsl:with-param -->
</xsl:apply-templates>
• Атрибут select ограничивает обработку только
указанными в нем узлами.
• Значением атрибута select должен быть XPath
путь доступа, который возвращающий
последовательность узлов.
• Если атрибут select не задан, то xsl:applytemplates применяет правила ко всем дочерним
узлам текущего узла, то есть запись
<xsl:apply-templates />
• равносильна записи:
<xsl:apply-templates select="child::node()"/>
• Атрибут mode выбирает указывает режим
обработки, т.е. значение, которое задается в
атрибуте mode элемента xsl:template.
• Режим – это любое имя типа QName, но два
режима предопределены.
– текущий режим, отмечаемый словом #current, и
– режим по умолчанию, принимаемый при
отсутствии атрибута mode, или отмечаемый явно
словом #default.
• Использование режимов будет рассмотрено
далее.
Порядок обработки элемента
<xsl:apply-templates>
• Вначале процессор вычисляет выражение,
указанное в атрибуте select.
– Полученное в результате его выполнения множество
узлов упорядочивается и становится текущим
списком узлов контекста.
• Из полученного списка выбирается узел, который
делается текущим, и для него ищется наиболее
подходящее правило обработки.
• Найденное подходящее правило выполняется и
полученный с его помощью фрагмент дерева
добавляется в результирующее дерево.
• Содержимым элемента xsl:apply-templates могут
быть элементы xsl:sort и xsl:with-param.
Встроенные правила
• Для того чтобы обеспечить рекурсивную
обработку документа при преобразовании, в
XSLT существуют так называемые встроенные
правила.
• Несмотря на то, что они явно не описываются
в преобразованиях, встроенные правила
применяются процессорами по умолчанию в
случаях, когда более подходящих правил нет.
• Существуют пять основных встроенных
правил, которые применяются процессорами
по умолчанию.
Первое встроенное правило
• Первое правило обеспечивает рекурсивную
обработку дочерних элементов документа,
которые находятся как в корне, так и в других
элементах.
• Это правило эквивалентно следующему
правилу:
<xsl:template match="* | /">
<xsl:apply- templates/>
</xsl:template>
• Второе правило аналогично первому, с той
лишь особенностью, что для каждого режима
преобразования рекурсивная обработка
происходит в том же самом режиме. В XSLT
это правило выглядело бы следующим
образом:
• <xsl:template match="* | /" mode= "режим" >
• <xsl:apply-templates mode="режим" />
• </xsl:template>
• Третье правило задает обработку текстовых
узлов и атрибутов –просто выводит их
текстовые значения. Оно может быть
записано в следующем виде:
• <xsl:template match="text () | @*">
• <xsl:value-of select="."/>
• </xsl:template>
• Четвертое правило задает обработку
инструкций по обработке и комментариев. В
соответствии с этим правилом инструкции и
комментарии просто не записываются в
результирующий документ. Данное правило
преобразования имеет следующий вид
• <xsl:template match="processing-instruction() |
comment () "/>
• Пятое правило описывает обработку узлов
пространств имен.
• Также, как инструкции и комментарии, по
умолчанию они из обработки исключаются.
• Встроенные правила имеют наименьший
приоритет.
• Любое правило, определенное в
преобразовании, будет иметь больший
приоритет, чем у встроенных правил, а значит,
что встроенные правила будут использоваться
лишь тогда, когда в XSLT-преобразовании нет
другого, более подходящего, правила.
Порядок выполнения преобразования
исходного документа
• В начале работы XSLT-процессора, выполняющего
преобразование XML-документа, контекстом обработки
является корневой элемент документа.
• Поэтом он начинает свою работу с того, что вначале ищет
правило для корневого элемента (текущего узла).
• Если правила для корневого элемента нет, то используя
встроенные правила (правила по умолчанию).
• Встроенные правила описывают обход исходного дерева
по принципу «сначала вглуб – потом в ширину».
• При выполнении обхода происходит изменение контекста.
• Для всех узлов входящих в текущий контекст определяются
(выбираются) правила, которые могут быть к ним
применены.
• Порядок просмотра узлов может быть изменен вызовом
правил с помощью элемента xsl:apply-templates.
Описание типового алгоритма
выполнения преобразования
1. к набору заданному набору правил XSLTпреобразования добавляются правила
используемые по умолчанию (встроенные
правила);
2. в начале обработки исходного дерева
задается текущий контекст
(последовательность узлов), состоящий из
единственного узла – корневого узла дерева,
который становится текущим узлом;
3. текущий узел контекста обрабатывается
следующим образом:
– из всех правил, определенных в данном
преобразовании, выбираются те, у которых
шаблон соответствует данному узлу (соответствие
определяется шаблоном заданным в атрибуте
match);
– из этих правил выбирается наиболее
приоритетное (определение приоритетов
рассматривается далее);
– выбранное правило выполняется для текущего
узла;
4. если правило содержит инструкции xsl:applytemplates или xsl:for-each, которые
дополнительно выбирают узлы для
обработки, то
– формируется новый контекст (последовательность
узлов), который становится текущим;
– предыдущий контекст запоминается;
– текущим становится первый узел нового контекста
(последовательности) и выполняется переход к
этапу 3;
5. если правило не содержит инструкции
xsl:apply-templates или xsl:for-each и если не
все узлы контекста обработаны, то текущим
узлом становится следующий узел контекста
и выполняется переход к этапу 3;
6. если в текущем контексте обработаны все
узлов, то текущим контекстом снова
становится предыдущий контекст;
7. если предыдущий контекст не состоит только из
корневого элемента документа, и в этой
последовательности есть узел который не
обрабатывался, то он становится текущим и
обработка переходит на этап 3;
8. если предыдущий контекст является
последовательностью, состоящей только из
корневого элемента документа (который был в
самом начале обработан), то процесс
преобразования завершается.
• Каждое правило будут создавать фрагменты
дерева, которые затем объединяются в дерево
результирующего документа.
• Вначале включим в XSLT-преобразование
правило для элемента bold:
<xsl:template match="bold">
<b><xsl:value-of select="."/></b>
</xsl:template>
• Это правило вначале создает элемент b, в
который включается текстовое значение текущего
узла (то есть, обрабатываемого элемента bold).
• При использовании данного преобразования к
входящему документу, будет получен следующий
результат:
<b>text</b>
• Теперь составим такое же правило для элемента para и
создадим преобразование, включающее оба правила.
• <xsl:stylesheet version="1.0"
• xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
• <xsl:template match="bold">
• <b><xsl:value-of select="."/></b>
• </xsl:template>
• <xsl:template match="para">
• <p><xsl:value-of select="."/></p>
• </xsl:template>
• </xsl:stylesheet>
Пример простого преобразования
• Рассмотрим пример XSLT-преобразования
следующего простого входного документа:
<para>
<bold>text</bold>
</para>
• Таким образом, чтобы имена элементов para и
bold заменялись на элементы р и b
соответственно.
• Теперь составим такое же правило для элемента
para и создадим преобразование, включающее
оба правила.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="bold">
<b><xsl:value-of select="."/></b>
</xsl:template>
<xsl:template match="para">
<p><xsl:value-of select="."/></p>
</xsl:template>
</xsl:stylesheet>
• Однако при использовании данного
преобразования к следующим XML-данным:
<para><bold>text</bold></para>
• будет получен не совсем ожидаемый
результат
<p> text </p>
• Как такое получилось, почему в
результирующий документ не выводится
элемент b?
• Для этого рассмотрим, как выполняется данное
преобразовании:
• XSLT-процессор начинает обработку с корневого узла
дерева.
• Он выбирает правило, соответствующее этому узлу.
• Если в рассматриваемом примере нет такого правила, то
процессор будет применять к корневому элементу
правило, определенное по умолчанию.
– По умолчанию правило корневого узла обрабатывает все
дочерние узлы.
• В рассматриваемом документе единственным дочерним
узлом корня будет элемент para.
• Для элемента para в составленном преобразовании задано
правило, которое и будет применен к этому элементу.
• В соответствии с этим правилом, процессор создаст элемент р и
включит в него текстовое значение выражения "." (Символ "." это
сокращенная форма выражения "self::node()", которое возвращает
текущий узел).
• Таким образом, элемент <xsl:value-of select="."/> вычислит и
возвратит строковое значение текущего узла, то есть узла para.
• Строковым значением элемента является конкатенация всех его
текстовых потомков (т.е. текстовые узлы всех элементов которые
являются наследниками узла para).
• Единственным текстовым потомком элемента para является
текстовый узел со значением "text" (который является содержимым
дочернего элемента <b>). Поэтому данное значение и выводится
между открывающим и закрывающим тегами созданного элемента
р.
• Таким образом, элемент b не выводится в результирующий
документ, потому, что правило для элемента bold просто не
вызывается на выполнение.
• Для того, чтобы элемент <b> все-таки выводился в результирующее
дерево, можно изменить преобразование таким образом, чтобы в
создаваемый элемент р включалось не текстовое значение
элемента para, а результат обработки его дочерних узлов.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="bold">
<b><xsl:value-of select=". "/></b>
</xsl:template>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
</xsl:stylesheet>
• Результатом этого преобразования будет документ:
<p><b>text</b></p>
• Теперь рассмотрим преобразование немного более
сложное документа:
<раrа>
<bold>textl</bold>
<раrа>
<bold>text2</bold>
</раrа>
</раrа>
• Как и ожидалось, результатом ранее составленного
преобразования будет следующий документ:
<p>
<b>textl</b>
<p><b>text2</b></p>
</p>
Процесс выполнения данного преобразования
можно описать следующим образом:
• Обработка начинается с корневого узла дерева.
• Так как для него нет заданного правила, то будет
применено правило по умолчанию – обработать
все дочерние узлы.
• Множество дочерних узлов корня содержит
единственный элемент para, значит, текущий
список узлов контекста будет состоять из одного
узла.
• Для него в преобразовании определено правило,
которое и будет выполнять процессор.
• Правило, соответствующее элементу para, создает
элемент р, содержимым которого будет результат
выполнения инструкции xsl:apply-templates, то есть
результатом применения данного правила к дочерним
узлам текущего узла будет элемента para.
• Единственным дочерним узлом элемента para
является элемент bold. Процессор изменит контекст
так, что текущий список узлов будет содержать только
элемент bold и выполнит соответствующее правило,
которое создаст элемент b и включит в него узел,
вычисленный инструкцией <xsl:value-of select="."/>, то
есть текстовый узел со строковым значением текущего
узла – элемента bold.
Использование атрибута select
• Атрибут select элемента xsl:apply-templates
позволяет выбирать, к каким именно узлам
будет применяться данное правило.
• Атрибуту select задается XPath путь доступа,
который должен возвращать
последовательность узлов.
• В случае, если атрибут select указан, то данное
правила будут поочередно применяться к
каждому из узлов выбранного множества.
• Следует отметить разницу между
использованием Xpathпутей доступа, которые
задаются
– атрибуту select (элемент xsl:apply-templates) и
– атрибуту match (элемента xsl:template).
XPath путь доступа атрибута match
• XPath путь доступа атрибута match элемента
xsl:template используется
• не для выбора последовательности узлов,
• а для проверки, может ли текущий узел
(выбираемый XSLT-процессором) обрабатываться
данным правилом);
XPath путь доступа атрибута select
• XPath путь доступа атрибута select элемента
xsl:apply-templates используется для
получения множества подходящих узлов.
• В нем могут использоваться
– переменные, содержащие множества узлов;
– функции, возвращающие множества узлов
(например, такие, как id() или key()), выражения с
операциями над множествами;
– пути выборки, фильтрующие выражения, в общем,
любые выражения, которые только могут
возвращать множества.
• Например, для того, чтобы обработать
содержимое произвольного внешнего XMLдокумента, в атрибуте select элемента
xsl:apply-template следует использовать
функцию document:
<xsl:apply-templates
select="document('a.xml')//para"/>
Использование режимов правил
• Часто при выполнении преобразования XML-документа
требуется разными способами обрабатывать одни и те же
узлы.
• Примером такого типа задачи является формирование
оглавления документа вместе с преобразованием его
содержимого.
• Такая проблема в языке XSLT решается с помощью атрибута
mode элемента xsl:template, который задает режим этого
правила.
• Точно такой же атрибут есть у элемента xsl:apply-templates:
в этом элементе он устанавливает режим обработки.
• При выполнении xsl:apply-templates процессор будет
применять только те правила преобразования, режим
которых совпадает с заданным режимом обработки.
Именованные правила
• Вместо того чтобы при помощи атрибута match
указывать, какая часть входящего документа
должна преобразовываться данным правилом,
ему можно присвоить имя и вызывать в любой
момент вне зависимости от контекста
преобразования.
• Такие правила очень похожи на функции
обычных языках программирования – они
позволяют описывать часто используемые
преобразования, передавать им параметры и
вызывать их вне зависимости от того, что именно
обрабатывается в данный момент.
• Имя правилу присваивается атрибутом name
элемента xsl:template.
• Если правилу задан атрибут name, то не
обязательно задавать атрибут match, теперь
оно может быть вызвано по имени.
• Правило, которому задан атрибут name
называется именованным правилом.
• Два правила не могут иметь одинаковых
имен.
• Именованному правилу можно передавать
параметры с помощью инструкции xsl:param.
• Например:
<xsl:template name="print">
<xsl:param name="message"/>
<!--содержание правила записывается здесь -->
</xsl:template>
• Вызов на выполнение именованного шаблона
выполняется с помощью инструкции xsl:call-template
(вместо использования инструкции xsl:apply-templates).
• Например:
<xsl:call-template name="print">
<xsl:with-param name="message"
select="'See if it prints this message.'"/>
</xsl:call-template>
• Вызов именованного правила xsl:call-template не
меняет контекста преобразования.
• Фактически, выполнение элемента xsl:call-template
эквивалентно замене в тексте преобразования данного
элемента на тело вызываемого именованного правила.
Идентичное преобразование
• Использование в XSLT правил, выполняемых по
умолчанию, иногда приводит к тому, что результаты
выполнения преобразований оказываются не такими,
какие ожидают разработчики.
• Например, требуется переименовать все элементы с
именами bold в элементы с именами b в следующем
исходном документе.
<а>
text a
<bold>text b<bold/>
<bold></bold>
<c>text с</c>
</a>
• Для этого можно составить следующее,
кажущееся очевидным, простое
преобразование:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http: //www.w3.org/1999/XSL/Transform">
<xsl:template match="bold">
<b><xsl:apply-templates/></b>
</xsl:template>
</xsl:stylesheet>
• Однако в результатом обработки исходного документа
будет получен следующий не ожиданный документ:
text a
<b> text b </b>
text с
• Как можно заметить, что в результирующем документе
нет элементов а и с, но есть их содержимое.
• Причиной получения такого результата является
использование встроенных правилах, которые по
умолчанию рекурсивно обрабатывают содержимое
элементов и копируют текстовые узлы, если иного не
определено.
• Для того, чтобы избежать такого нежелательного
результата, к ранее созданному преобразованию нужно
добавить идентичное преобразование.
• Данное преобразование в случае отсутствия правил для
обработки каких-либо узлов исходного документа
выполняет их копирование в результирующий документ.
• Идентичное преобразование описывается следующим
образом:
<xsl:template match="@* | node () ">
<xsl:copy>
<xsl:apply-templates select="@* | node() "/>
</xsl:copy>
</xsl:template>
• Идентичное преобразование использует единственное
правило, содержащее элемента xsl:copy, которое
рекурсивно создает в результирующем документе
копии узлов и атрибутов.
• Это преобразование выполняет не просто копирование
документа (для этого было бы достаточно элемента
xsl:copy-of).
• Оно переопределяет встроенные правила.
• Теперь, если для обработки какого-либо узла в
преобразовании не определено подходящее правило,
то будут использоваться не встроенные правило, а
идентичное правило, которое будет копировать
данный узел вместе со всеми его потомками в
результирующий документ без изменений.
• Идентичное преобразование очень полезно в
тех случаях, когда требуется изменить только
некоторые части документа, оставив
остальное в без изменения.
• Например, в предыдущем примере
требовалось только переименовать все
элементы bold исходного документа
Переменные
• В XSLT все переменные являются константами,
которым могут быть инициализироваться при их
объявлении, но в дальнейшем не могут быть
изменены.
• В XSLT вообще нет оператора присваивания.
• Для объявления переменных в XSLT служит
элемент xsl:variable, который может
записываться, как в теле правила, так и быть
элементом верхнего уровня:
<xsl:variable name="имя" select="выражение">
<!-- Содержимое: шаблон -->
</xsl:variable>
• Элемент xsl:variable связывает имя, указанное в
обязательном атрибуте name, со значением
выражения, указанного в атрибуте select или с
деревом, которое является результатом
выполнения правила, содержащегося в этом
элементе.
• Таким образом, объявление переменной в XSLT
происходит в два шага:
– сначала вычисляется значение присваиваемого
выражения,
– а затем полученное значение связывается с
указанным именем.
• Значение присваиваемого выражения вычисляется в
зависимости от того, как был определен элемент
xsl:variable:
• если в элементе xsl:variable определен атрибут select, то
значением присваиваемого выражения будет результат
вычисления выражения, указанного в этом атрибуте;
• если атрибут select не определен, но сам элемент
xsl.variable имеет дочерние узлы, значением
определяемой переменной будет результирующий
фрагмент дерева, полученный в результате выполнения
содержимого xsl:variable;
• если атрибут select не определен и при этом сам
элемент xsl:variable пуст, значением параметра по
умолчанию будет пустая строка.
Цели использования переменных
• для хранения значений выражений, которые
много раз используются в преобразовании,
что избавляет процессор от необходимости
пересчитывать выражение многократно;
• для хранения результата преобразований, что
позволяет выполнять преобразования уже
сформированных частей документа;
• для более прозрачного доступа к внешним
документам.
• Для использования значения, присвоенного
переменной при инициализации, нужно
перед именем переменной указать символ
"$", например для использования
переменной sum нужно указать имя $sum.
Параметры
• Параметры в языке XSLT практически полностью идентичны
переменным.
• Они используются для передачи в правила языка XSLT
значений, которые могут применяться при их выполнении.
• Параметры также, как и переменные задают имена для
объектов. С помощью этих имен в дальнейшем к этим
объектам можно обращаться.
• Главным отличием параметров от переменных является то,
что значение, заданное параметру при инициализации,
является значением по умолчанию, которое может быть
переопределено при вызове.
• Работа с параметрами выполняется с помощью двух
элементов:
– xsl:param, который объявляет в правиле новый параметр и
– xsl:with-param, который указывает значение параметра при
вызове именованного правила.
Элемент xsl:with-param
• Элемент xsl:with-param абсолютно идентичен
элементу xsl:param.
• Также аналогичны их действия: элемент xsl:withparam тоже связывает с именем параметра
значение, и при выполнении правила это
значение будет использоваться вместо значения
параметра по умолчанию.
• Элемент xsl:with-param описывается следующим
образом:
<xs1:with-param name="имя" select=" выражение"'>
<!-- Содержимое: шаблон -->
</xsl:with-param>
• Значение параметра, заданного в правиле,
выбирается в соответствии со следующими
положениями:
– если в элементе, который вызывает это правило,
присутствует элемент xsl:with-param, передающий
значение этого параметра, в правиле будет
использоваться переданное значение;
– если в элементе, который вызывает этот правило,
элемента xsl:with-param, с соответствующим
именем нет, в качестве значения параметра будет
использоваться значение по умолчанию.
• Элементs xsl:with-param может
использоваться только в качестве дочернего
элемента xsl:apply-templates и xsl:call-template
для задания параметров правил, выполнение
которых они инициируют.
• Например, рассмотрим правило, которое выводит сокращение
названия для недели по его номеру.
• Номер дня передается в правило с помощью параметра day-number.
<xsl:template name=“day-name”>
<xsl:param name=“day-number” select=“0”"
<xsl:choose>
<xsl:when test="$day-number=1">Понедельник</xsl:when>
<xsl:when test="$day-number=2">Вторник</xsl:when>
<xsl:when test="$day-number=3">Среда</xsl:when>
<xsl:when test="$day-number=4">Четверг</xsl:when>
<xsl:when test="$day-number=5">Пятница</xsl:when>
<xsl:when test="$day-number=6">Суббота</xsl:when>
<xsl:when test="$day-number=7">Воскресенье</xsl:when>
<xsl:otherwise>Ошибочное значение!</xsl:otherwise>
</xsl:choose>
</xsl:template>
• В результате вызова данного правила:
<xsl:call-template name="day-name">
<xsl:with-param name="day-number" select="1" />
</xsl:call-template>
• будет получен текстовый узел "Понедельник".
Конструкторы узлов
• Узлы результирующего дерева могут быть созданы, как с
помощью литеральных результирующих элементов, так и с
помощью специальных элементов – конструкторов, таких,
как:
–
–
–
–
–
–
–
–
–
xsl:element – создание в выходящем дереве узла элемента;
xsl:attribute – создание в выходящем дереве узла атрибута;
xsl:attribute-set – определение именованного набора атрибутов;
xsl:text – создание текстового узла;
xsl:value-of – создание текстового узла по результатам
вычисления выражения;
xsl:comment – создание узла комментария;
xsl:processing-instruction – создание узла инструкции по
обработке;
xsl:copy – копирование текущего узла вместе с его узлами
пространств имен;
xsl:copy-of – копирование результата вычисления выражения.
Создание узлов элементов
• В результирующем документе можно создать узлы
элементов с использованием литеральных
результирующих элементов, которые
записываются в правилах и в неизменном виде
копируются процессором в результирующее
дерево.
• Такой способ является простым и понятным.
• Однако он не может быть использован в тех
случаях, когда требуется создавать элементы с
заранее неизвестными (например, вычисляемыми
во время выполнения) именами.
• Например, пусть требуется преобразовать исходный
документ:
<element name="a">
<element name="b"/>
</element>
• в следующий результирующий документ:
<a> <b/> </a>
• Понятно, что с помощью литеральных элементов такое
преобразование сделать невозможно.
• Это связано с тем, что имена элементов
результирующего документа заранее не известны –
они определяются значениями атрибутов исходного
документа.
• Данная задача может быть решена, за счет
использования конструктора элемента
xsl:element, который записывается следующим
образом:
<xsl:element name- "{имя}" namespace="{пространство
имен}" use-attribute-sets="имена">
<!-- Содержимое: шаблон -->
</xsl:element>
• Содержимым xsl:element является шаблон,
который выполняется процессором и затем
включается в создаваемый элемент.
Атрибуты xsl:element
• В элементе xsl:element могут использоваться
следующие атрибуты:
– name – обязательный атрибут, указывающий имя
создаваемого элемента. Этот атрибут может
содержать шаблон значения, а значит, имя элемента
может быть вычислено во время выполнения.
– namespace – атрибут, указывающий URI пространства
имен создаваемого элемента. Точно так же, как и
name, данныйт атрибут может содержать шаблон
значения, что позволяет вычислять пространство имен
создаваемого элемента при помощи выражений.
– use-attribute-sets – атрибут, перечисляющий имена
наборов атрибутов, которые должны быть включены в
создаваемый элемент.
Пример:
• пусть имеются элементы следующего вид:
<fire on=”babylon”/>
• требуется поменять имена этих элементов на значения их
первого атрибута, а первому атрибуту задать имя элемента.
• Такое преобразование можно выполнить с помощью
следующего правила:
<xsl:template match="*">
<xsl:element name="{@*}">
<xsl:attribute name="{name (@*) }">
<xsl:value-of select="name()"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
• В результате выполнения данного правила
получится следующий результирующий
элемент:
<babylon on="fire"/>
Создание узлов атрибутов
• Для создания атрибутов используется элемент
xsl:attribute задается конструкцией вида:
<xsl:attribute name="{имя}«
namespace="{пространство имен}">
<!-- Содержимое: шаблон -->
</xsl:attribute>
– обязательный атрибут name указывает имя,
– атрибут namespace – URI пространства имен
создаваемого атрибута.
• Использование элементов xsl:attribute и
xsl:element во многом аналогично.
• Причин применения xsl:attribute несколько
больше, чем для xsl:element.
• В частности, xsl:attribute следует использовать,
если:
– требуется создать атрибут с не известным заранее
именем или пространством имен;
– требуется создать атрибут, вычисление значения
которого не может быть реализовано одним или
несколькими XPath-выражениями (например,
условный вывод атрибута).
• Например, рассмотрим преобразование
следующего фрагмента исходного документа:
<element name="record">
<attribute name="fieldcount" value="12"/>
<attribute name="title" value="Aggregation"/>
</element>
• в следующий элемент результирующего
элемента:
<record fieldcount="12" title="Aggregation"/>
• Для выполнения такой задачи можно использовать следующее
преобразование:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="element">
<xsl:element name="{@name}">
<xsl:apply-templates select="attribute"/>
</xsl:element>
</xsl:template>
<xsl:template match="attribute">
<xsl:attribute name="{@name}">
<xsl:value-of select="@value"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
• Узлы атрибутов могут создаваться только как дочерние
узлы для узлов элементов.
• Кроме того, узлы атрибутов должны создаваться до
создания дочерних узлов других типов – текста,
элементов и так далее.
• Таким образом, xsl:attribute может быть использован в
содержимом любого из следующих родителей:
– литерального результирующего элемента;
– элемента xsl:element;
– элемента xsl:copy в случае, если текущий, копируемый
узел является элементом;
– элемента xsl:attribute-set в случае определения
именованного набора атрибутов.
• Текстовое значение атрибута может задаваться
не только символьными данными.
• Оно может генерироваться также элементами
XSLT, такими, как, например, xsl:text и xsl:vaiue-of.
• To есть правильным будет следующее описание:
<xsl:attribute name="href">
<xsl:text>http://</xsl:text>
<xsl:value-of select="concat('www','.','bbb')"/>
<xsl:text>.com</xsl:text>
</xsl:attribute>
• Основными особенностями использования
элемента xsl:attribute являются:
– Атрибуты могут создаваться только в узлах элементов.
Если атрибут создается в узле, который не является
узлом элемента, процессор может либо выдать
ошибку, либо проигнорировать создаваемый атрибут.
– Атрибуты могут содержать только текстовые узлы.
Процессор может либо выдать ошибку, либо
проигнорировать нетекстовые узлы.
– Узлы атрибутов должны быть первыми узлами,
которые создаются в элементах. XSLT не разрешает
создавать атрибуты после того, как в элемент
включены дочерние узлы других типов.
Именованные наборы атрибутов
• Для упрощения создания в элементах наборов
атрибутов, можно заранее определить их с
помощью элемента xsl:attribute-set, который
описывается следующим образом:
<xsl:attribute-set name="имя" use-attribute-sets="имена">
<!-- Содержимое: несколько элементов xsl:attribute -->
</xsl:attribute-set>
• В элементе xsl:attribute-set есть один обязательный
атрибут name, который задает имя набора
атрибутов.
• Содержанием элемент xsl:attribute-set является
последовательность, состоящую нескольких
элементов xsl:attribute.
• Именованные наборы атрибутов можно
использовать, указывая их имена в значении
атрибута use-attribute-sets, который может
присутствовать в элементах xsl:element,
xsl:сору и xsl:attribute-set, а также в
литеральных результирующих элементах.
• В атрибуте use-attribute-sets через пробел
перечисляются имена наборов атрибутов,
которые должны быть использованы в
данном элементе.
• Например, именованный набор атрибутов может быть
описан следующим образом:
<xsl:attribute-set name="elements">
<xsl:attribute name="name">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:attribute name="node-count">
<xsl:value-of select="count(*)"/>
</xsl:attribute>
</xsl:attribute-set>
• Включение набора атрибутов в элемент равносильно
простому копированию элементов xsl:attribute,
определенных в соответствующих элементах xsl:attributeset.
Создание текстовых узлов
• Правило преобразования может содержать
текстовые узлы, которые при выполнении
шаблона после обработки пробельных
символов будут попросту скопированы в
результирующее дерево.
• Таким образом, для того, чтобы вывести в
выходящий документ некоторый текст, можно
просто включить его в правило
преобразования.
• Рассмотрим пример преобразования элемента
<answer>No!</answer>
в текстовую строку.
• Для этого можно использовать следующий
шаблон:
<xsl: template match="answer">
The answer was "<xsl:value-of select="text ()"/>".
</xsl:template>
• В результате получается следующий текст
The answer was "No!"
• Текстовые узлы могут также быть созданы с
помощью следующих элементов:
– элемент xsl:text используется для создания
текстовых узлов, содержащих пробельные и
специальные символы;
– элемент xsl:value-of выводит в выходящее дерево
строковый результат вычисления выражений.
Элемент xsl:text
• Элемент xsl:text используется для создания в
результирующем документе текстовых узлов.
• Он записывается следующим образом:
<xsl:text disable-output-escaping="yes" | "no">
<!-- Содержимое: символьные данные-->
</xsl:text>
Особенности элемента xsl:text
• Преобразования будут сохранять пробельные
символы, находящиеся в элементе xsl:text.
– To есть, для того чтобы вывести в выходящий документ
пробельный символ, например такой, как символ
перевода строки, достаточно написать <xsl:text> 

</xsl:text>.
• Элемент xsl:text имеет атрибут disable-output-escaping,
который позволяет избежать замены в выходящем
документе специальных символов на символьные или
встроенные сущности.
– Например, для того, чтобы вывести символ "<" можно
указать в преобразовании
<xsl:text disable-output-escaping="yes"> < </xsl:text>
• В остальных случаях символьные данные, включенные
в элемент xsl:text, ведут себя так же, как и вне его.
Элемент xsl:value-of
• Данный элемент является одним из наиболее часто
используемых в XSLT-преобразованиях.
• Он выполняет вычисление значений выражений и
записывается следующим образом:
<xsl:value-of select="выражение" disable-outputescaping="yes" | "no"/>
• В обязательном атрибуте select этого элемента
задается выражение, которое вычисляется
процессором, а затем преобразовывается в строку и
выводится в результирующем дереве в виде текстового
узла.
• Процессор не создает текстовый узел, если в
результате вычисления выражения получается пустая
строка.
• Например, результатом выполнения элемента
<xsl:value-of select="concat('Divide ', '&', ' impera')"/>
будет текстовый узел
Divide & impera
• Часто элемент xsl:value-of записывается как
<xsl:value-of select="."/>
• Такой элемент возвращает строковое
значение текущего узла.
• Если текущий элемент имеет потомков, то
его строковым значением является
конкатенацией текстового содержания всех
его потомков.
Копирование узлов
• Преобразование может включать в себя не
только создание новых, но и копирование
существующих узлов.
• Для этого можно использовать элементы
xsl:copy и xsl:copy-of.
Элемент xsl:copy
• Элемент xsl:copy создает копию текущего узла вне
зависимости от его типа и имеет следующий вид:
<xsl:copy use-attribute-sets = "наборы атрибутов">
<!-- Содержимое: шаблон -->
</xsl:copy>
• Элемент xsl:copy вместе с текущим узлом в
результирующее дерево копирует только узлы
пространств имен, связанные с ним.
• Дочерние узлы и узлы атрибутов в результирующий
документ не копируются.
• В содержании элемента xsl:copy определяет, какие
другие атрибуты и элементы будут копироваться
вместе с текущим узлом.
• В содержании элемента xsl:copy определяет, какие другие атрибуты
и элементы будут копироваться вместе с текущим узлом.
• Элемент xsl:copy во многом аналогичен элементу xsl:element,
который создает новый элемент с именем текущего элемента.
• Т.е. запись:
<xsl:template match="*" mode="html">
<xsl:copy>
<xsl:apply-templates select="@* | * | text()" mode="html" />
</xsl:copy>
</xsl:template>
• Аналогична записи:
<xsl:template match="*" mode="html">
<xsl:element name="{name()}">
<xsl:apply-templates select="@* | * | text()" mode="html" />
</xsl:element>
</xsl:template>
Элемент xsl:copy-of
• Элемент xsl:copy-of используется для полного
копирования результата вычисления заданного
выражения в результирующее дерево.
• Данный элемент имеет следующий синтаксис:
<xsl:copy-of select = "выражение" />
• Поведение xsl:copy-of зависит от того, какой тип
данных возвращает выражение.
– Если результат вычисления имеет булевый, числовой или
строковый тип, то xsl:copy-of выводит его в виде текстового
узла. В этом случае поведение xsl:copy-of абсолютно не
отличается от поведения элемента xsl:value-of.
– Если результатом вычисления выражения является
множество узлов (node-set), то xsl:copy-of копирует в
результирующий документ все узлы в порядке просмотра
документа вместе с их потомками.
• Например, слеудющее преобразование скопирует весь
исходный документ в результирующий документ:
<xsl:template match="/">
<xsl:copy-of select="*"/>
</xsl:template>
• Элементы xsl:value-of и xsl:copy-of очень сходны,
только элемент xsl:value-of сначала преобразовывает
вычисленное выражение к строковому виду, а потом
выводит его в выходящий документ.
• Иными словами, выражение:
<xsl:value-of select="выражение"/>
• равносильно выражению:
<xsl:copy-of select="string(выражение)"/>
Условная обработка
• В XSLT имеются две инструкции, которые
поддерживают условную обработку –
– xsl:if позволяет создавать простые условия типа
"если – то“;
– xsl:choose- создает более сложную конструкцию
для выбора одной из нескольких имеющихся
возможностей в зависимости от выполнения тех
или иных условий.
• Элемент xsl:if записывается следующим
образом:
<xsl:if test= " выражение " >
<!-- Содержимое: шаблон -->
</xsl:if>
• Выражение, содержащееся в обязательном
атрибуте test элемента xsl:if, вычисляется и
преобразуется к булевому типу.
• Если выражение имеет значение true, то
выполняется шаблон, содержащийся в xsl:if.
• Вследствие того, что атрибуты в XML не могут
содержать некоторые специальные символы
(такие как "<" и "&"), их необходимо заменять
ссылками на символьные сущности.
• Например, сравнение "a < b" в инструкции xsl:if
следует записывать, как
<xsl:if test="a < b"/>.
• Символ операции "больше" (">") заменять
сущностью необязательно.
• Однако из соображений единообразия принято
заменять и его.
• Например: требуется преобразовать список названий
<list active="Bravo">
<item>Alpha</item>
<item>Bravo</item>
<item>Charlie</item>
</list>
• во фрагмент HTML-кода, в котором каждый элемент
item должен быть преобразован в соответствующий
элемент option, а значение, выбранное во входящем
документе атрибутом active элемента list, должно быть
помечено специальным атрибутом selected.
• Это можно сделать с помощью следующего преобразования,
использующего элемент <xsl:if>:
<xsl: template match="item">
<option>
<xsl:if test=". =../@active">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:if>
<xsl:value-of select="."/>
</option>
</xsl:template>
• В результате будет получен следующий набор элементов:
<option>Alpha</option>
<option selected>Bravo</option>
<option>Charlie</option>
• Элемент xsl:choose позволяет выбрать одно из заданных
элементов xsl:when, либо xsl:otherwise, которые он
включает.
• Данные элементы записываются следующим образом:
<xsl:choose>
<!-- Содержимое: несколько элементов xsl:when, и может
быть xsl:otherwise -->
</xsl:choose>
<xsl:when test="выражение">
<!-- Содержимое: шаблон -->
</xsl:when>
<xsl:otherwise>
<!-- Содержимое: шаблон --->
</xsl:otherwise>
• При обработке xsl:choose процессор
поочередно вычисляет выражения,
содержащиеся в атрибутах test элементов
xsl:when, приводит их к булевому типу и
выполняет содержимое первого (и только
первого) элемента, тестовое выражение
которого будет равно true.
• В случае если ни одно из тестовых выражений
не имеет значение "истина" и если в
xsl:choose имеется элемент xsl:otherwise, то
выполняется содержимое этого элемента.
Циклы языка XSLT
• Для создания в результирующем документе
повторяемых частей структуры используется
элемент xsl:for-each:
<xsl:for-each select="выражение">
<!-- Содержимое: несколько элементов xsl:sort, шаблон -->
</xsl:for-each>
• Обязательный атрибут select указывает
выражение, результатом вычисления которого
должно быть множество узлов.
• Шаблон, содержащийся в xsl:for-each, будет
выполняться для каждого узла этого множества.
• Например: элемент xsl:for-each можно использовать для создания
списка гипертекстовых ссылок в результирующем документе.
• Рассмотрим следующую простую web-страницу (исходный
документ):
<html>
<head> <title>Это простая web-страница...</title> </head>
<body>
Пожалуйста перейдите <a href="http: //www.aaa.com">по данной
ссылке</a>.
или <a href="http: //www.bbb.com">этой ссылке</a>.
или посетите <a href="http: //www.ccc. com">этот web-сайт</a>.
или щелкните <a href="http: //www.ddd.com">здесь</a>.
</body>
</html>
• В этом документе элементы гипертекстовых ссылок
являются потомками элемента body, который входит в
содержимое элемента html.
• Для создания списка всех гиперссылок можно
составить следующее правило использующее элемент
xsl:for-each:
<xsl:template match="/">
<links>
<xsl:for-each select="/html/body//a">
<a href="{@href}"> <xsl:value-of select = "@href"/>
</xsl:for-each>
</links>
</xsl:template>
• В результате использования данного преобразования
будет сформирован следующий список ссылок:
<links>
<a href="http://www.aaa.com">http://www.aaa.com</a>
<a href="http://www.bbb.com">http://www.bbb.com</a>
<a href="http://www.ccc.com">http://www.ccc.com</a>
<a href="http://www.ddd.com">http://www.ddd.com</a>
</links>
• Следует помнить, что элемент xsl:for-each
изменяет контекст преобразования.
• Множество узлов, возвращаемое выражением в
атрибуте select, становится текущим множеством
узлов, а узел, шаблон для которого выполняется в
данный момент, становится текущим узлом.
• Множества узлов в XSLT не имеют внутреннего
порядка.
• Однако, обработка узлов в xsl:for-each будет
происходить в так называемом порядке
просмотра документа, который зависит от того,
какое выражение использовалось для
вычисления обрабатываемого множества.
Сортировка данных
• Порядок обработки последовательности узлов может
быть также изменен с помощью атрибута order-by.
• Данный атрибут используется в элементах applytemplates и for-each, и задает порядком, в котором
XSLT-процессор будет обрабатывать выбираемые
элементы.
• Атрибуту order-by можно задать один или несколько
образцов, разделяя их точкой с запятой. XSLTпроцессор будет сортировать элементы с
использованием образцов в том порядке, в котором
они перечислены.
• Для указания направления сортировки (по
возрастанию или по убыванию) следует предварить
образец префиксом + или –.
• Например, в следующем примере, атрибут
order-by элемента for-each, указывает
– выполнять сортировать элементы book по
фамилиям авторов в порядке возрастания,
– если фамилии одинаковые, то нужно сортировать
по возрастанию имен:
<xsl:for-each select="inventory/book"
order-by="+author/lastname; +author/firstname">
• В другом примере атрибут order-by задает
сортировку элементов book по названиям книг по
убыванию:
<xsl:apply-templates select="inventory/book" order-by="title">
• Оператор пути, который присваивается атрибуту
order-by, действует относительно образца,
назначенного атрибуту select.
• Так, в данном примере установка order-by="-title"
указывает на элемент title внутри элемента book,
вложенного в элемент inventory.
Примеры XSLT преобразований
• Лучше всего изучать XSLT язык на примерах.
Поэтому далее будут рассмотрены два
примера составления XSLT-преобразований
– Пример 1: Преобразование XML-документа в
табличный формат.
– Пример 2: Преобразование XML-документа со
статьей.
– Пример 3: Преобразование XML-документа со
списком музыкальных файлов.
Выходной синтаксис для XSLT
• XSLT может создать результат с
использованием трех выходных
синтаксисов
– XML файлы
– HTML файлы
– Text (не размеченные тэгами файлы)
• ASCII email message
• comma-separated file
• desktop publishing system format (e.g., XTags for
QuarkXPress)
Назначение XSLT
• XSLT was designed to process XML
– Takes full advantage of the tree
– XML constructs are built in ( no special programming)
• Solves problems with
– order of the material
– document model/processing mismatch
– interchange (mine different from yours different from
ours)
– personalization/localization
• Part of the XML family, so applications built to support
• Makes content fluid, as XML and SGML have always
promised
Что может делать XSLT
• Извлечь что-либо из входного документа.
• Изменить последовательность элементов
(rearrange / sort)
• Удалить что-либо из входного документа.
• Использовать один и тот же элемент или
атрибут многократно.
• Добавить сгенерированный текст.
XSLT легко преобразует XML
документ в разные XML форматы
•
•
•
•
Переименовать элемент или атрибут.
Изменить элемент xxx в элемент yyy
Преобразовать элементы в атрибуты.
Преобразовать атрибуты в элементы.
XSLT хорошо работает с
размеченными документами
• XSLT работает лучше всего, когда
– Требуется получить размеченный тэгами
результат!
– Иерархия задается явно .
– Наиболее важными отношениями являются
древовидные отношения
• включение (parent / child)
• siblings
• attributes
XSLT не подходит для любых
преобразований
• Совершенно не подходит
– Для преобразования произвольных документов в XML
формат.
– Для обработки не XML данных (Word, QuarkXPress,
SGML).
• Не так эффективен, как большинство
универсальных языков программирования для:
–
–
–
–
обработки чисел (arithmetic and higher math)
обработки строк (parsing)
обработки очень больших файлов
создания структуры там, где ее не было
(преобразование плоского файла в иерархию).
XSLT имеет слабые возможности
работы с текстом (строками)
• An XSLT processor expects to work on
– a tree of nodes
– not an XML file of tags and text
• If you have untagged files
(comma delimited, space delimited, tab
delimited)
– there is no tree
– strings must be “parsed” into pieces
– XSLT does this awkwardly
• (XSLT 2.0 has better string manipulation than XSLT
1.0, but…)
Язык XSLT
• XSLT это декларативны язык описания преобразований
структуры XML документов.
• XSLT документы называются XSL-таблица стилей или XSLT
трансформациями.
• Каждая XSL-таблица стилей должна иметь корневой элемент,
представленный ниже.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- один или несколько элементов шаблона …-->
</xsl:stylesheet>
– Первым атрибут элемента stylesheet задает версию XSLT,
– Второй атрибут xmlns:xsl задает пространство имен для элементов языка
XSLT.
• В соответствии с этим тэгом все XSL-элементы принадлежат
пространству имен, заданным префиксом «xsl» (т. е. перед XSL
элементами пишется префикс «xsl:».
Как процессор XSL трансформирует
исходный документ
• Язык XSLT работает не с синтаксисом документа, а с его моделью:
– Исходный формат и создаваемый формат являются приложениями
XML и подлежащая структура в обоих случаях представляет собой
дерево.
– Таблица стилей XSL — это документ XML, и потому она также может
быть представлена в виде дерева.
– Процессоры XSLT работают с тремя деревьями.
• Язык XSLT является декларативным, т.е. в таблице стилей
описывается:
– как должен выглядеть результат,
– а не то, как он должен быть трансформирован;
– именно для выполнения этой работы нужен процессор XSL.
• Таблица стилей XSL состоит из шаблонов (templates), описывающих,
как некоторый узел исходного дерева должен быть представлен в
дереве результата.
• Процессор проходит по дереву источника, начиная с корня, и ищет
соответствующие шаблоны в дереве таблицы стилей.
• Обнаружив шаблон, он с помощью содержащихся в нем правил
записывает абстрактное представление результата в дерево
результата.
• Так он перемещается по документу узел за узлом (это определяется
инструкцией XSLT <xsl:apply-template>) и ищет соответствия в
таблице стилей.
• Если соответствующего шаблона не обнаруживается, он
переходит к следующему.
• Можно сказать, что в таком случае он выполняет шаблон по
умолчанию, который не приводит к результату на выходе.
• По завершении работы процессора дерево результата можно
представить в виде
– XML документ,
– HTML документа,
– текста, или в другой желаемой форме.
• Теоретически события должны происходить в описанной
последовательности. Однако в методах создания обработчиков
XSLT используются различные вариации.
Элементы языка XSLT
• В языке XSLT определено около полусотни элементов.
• Элементы верхнего уровня (17 элементов) (или декларации),
которые могут включаться в корневой элемент «xsl:stylesheet»
– К таким элементам относятся: xsl: import, xsl: include, xsl: attribute-set,
xsl:character-map, xsl:date-format, xsl:decimal-format, xsl:function,
xsl:import-schema, xsl:key, xsl:namespace-alias, xsl:output, xsl:param,
xsl:preserve-space, xsl:sort-key, xsl:strip-space, xsl:template, xsl:variable.
– Кроме xsl:param и xsl: variable все другие элементы верхнего уровня
могут включаться только непосредственно в к корневой элемент
«xsl:stylesheet».
• Другие элементы (более 30) - могут записываться в теле
элементов верхнего уровня.
– Наиболее часто используемыми элементами являются: xsl:applytemplates, xsl:value-of, xsl:copy-of, xsl:sort, xsl:text.
• Все элементы являются необязательными и могут располагаться в
любом порядке, за одним исключением: декларации xsl:import,
(если они есть) должны быть записаны первыми.
Инструкции
• Формально инструкции XSLT определяются как элементы,
которые можно вставлять в конструктор
последовательности.
• Инструкции являются элементами не верхнего уровня
вложенности.
• К инструкциям относятся следующие элементы
– элементы, создающие узлы всех семи видов и
последовательности узлов: xsl:element, xsl:attribute, xsl:text,
xsl:comment, xsl:processing-instruction, xsl:namespace, xsl:resultdocument, xsl:sequence.
– элементы xsl:apply-templates, xsl:value-of, xsl: variable и др.
(всего более двадцати элементов).
– элементы, определяющие правила выбора преобразования:
xsl:if, xsl:for-each, xsl:choose,
– элементы, копирующие узлы xsl:copy, xsl:copy-of.
Инструкция xsl:output
• Задает параметры сериализации
результирующего дерева.
<xsl:output
method = "xml" | "html" | "text" | QName
version = nmtoken
encoding = string
omit-xml-declaration = "yes" | "no"
standalone = "yes" | "no"
doctype-public = string
doctype-system = string
cdata-section-elements = QNames
indent = "yes" | "no"
media-type = string />
Шаблон (pattern)
• Прежде чем сделать преобразование дерева документа
XML, из него следует выбрать те узлы, которые подвергнутся
тому или иному преобразованию.
• Их можно выбирать по некоторому образцу (XPath
выражению), который может содержать
–
–
–
–
имени элементов,
имена атрибутов
содержимое атрибутам
другие признаки.
• Условия отбора узлов задаются образцом (pattern),
записанным в виде одного или нескольких выражений
языка XPath 2.0.
• Выражения, содержащиеся в образце, объединяются
вертикальной чертой |, означающей, что выбираемый узел
должен удовлетворять хотя бы одному выражению образца.
Декларация xsl:template
• Шаблоны описываются с помощью элемента
xsl:template, который содержит:
– не обязательный атрибут «match» в котором задается
XPath маршрут поиска (XPath выражение, образец) для
отбора узлов, подлежащих преобразованию,
– не обязательный атрибут «name», в котором
определяется имя шаблона.
– тело содержит конструктор последовательности узлов и
атомарных значений, которая и будет результатом
преобразования отобранных по образцу узлов.
• Например
<xsl: template match="Образец" name="Имя">
Конструктор
</хsl:template>
Атрибуты xsl:template
• Каждый из атрибутов «match» и «name» не
обязателен, но хотя бы один из них должен
присутствовать.
• Шаблон можно вызвать по имени элементом
«xsl:call-template», а если он не содержит атрибута
«match», то такой вызов обязателен, поскольку
неизвестны узлы, к которым его надо применить, и
он не будут применяться автоматически.
• Очень часто именованный шаблон содержит
параметры, заданные элементами «xsl:param», и
вызывается с различным параметрами совсем как
обычная функция.
• В образце можно записать не всякое выражение XPath, а
только путь, каждый шаг которого определяется осью,
причем допускаются только три оси:
– child (по умолчанию),
– // и
– attribute.
• Это означает, что, находясь в каком-то узле, можно
"видеть", кроме него самого, только его атрибуты и узлыпотомки.
– Обратите внимание на то, что явная запись оси descendant-orself недопустима, применяется только сокращенная запись //.
• Запись оси attribute:: можно сократить до одной "собачки"
@.
• Текущий узел очень часто обозначается точкой.
• Каждое XSLT-преобразование должна
содержать один и только один шаблон с
атрибутом match, который имеет значение "/".
• Хотя образец и строится как выражение языка XPath,
но его цель — не отобрать последовательность узлов, а
проверить соответствие узла данному образцу.
• Узел Node соответствует образцу (pattern) тогда и
только тогда, когда узел Node принадлежит
последовательности узлов -результату вычисления
выражения //Pattern.
– Например, образцу person//street будут соответствовать
все узлы из последовательности //person//street, а именно
все узлы street, вложенные в узлы-элементы person даже
через несколько промежуточных узлов.
• Перечисленные ограничения касаются только
образцов.
• В других конструкциях языка XSLT можно применять
выражения XPath в полном объеме.
XSLT копирующее входной документ в
выходной
•
Если таблица стилей состоит из единственного правила, предназначенного для
обработки корневого узла, в результате просто копируется всё содержимое
шаблона, а XSLT-инструкции (элементы 'xsl:…') заменяются вычисляемым
содержимым.
– XSLT предлагает даже специальный формат («literal result element as stylesheet») для таких
простых, одношаблонных трансформаций.
• XSLT по умолчанию в XML-редакторе VS 2010
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl=http://www.w3.org/1999/XSL/Transform
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Инструкция xsl:apply-templates
• Элемент xsl:apply-templates указывает XSLT
процессору найти для применения подходящий
шаблон, на основе типа и контекста, каждого
выбранного узла.
• Элемент xsl:apply-templates, записываемый чаще
всего внутри элемента xsl: template, в
простейшем виде пуст:
<xsl:apply-templates />
• Он предписывает обработать рекурсивно все
узлы-потомки узлов, отобранных родительским
элементом xsl:template.
Атрибуты элемента
«xsl:apply-templates»
• У элемента xsl:apply-templates есть необязательные
атрибуты «select» и «mode».
– атрибут select, в котором задается выражение, дающее
последовательность узлов.
• Если атрибут «select» задан, то список узлов формируется на основе
указанного запроса XPath.
• В противном случае список содержит все дочерние узлы.
– атрибут mode выбирает режим обработки из режимов, уже
определенных в элементах xsl:template. Режим — это
любое имя, но два режима предопределены.
• текущий режим, отмечаемый словом #current, и
• режим по умолчанию, принимаемый при отсутствии атрибута
mode, или отмечаемый явно словом #default.
• Содержимым элемента xsl: apply-templates могут
служить элементы xsl:sort и xsl:with-param.
Встроенные шаблоны (правила)
•
Встроенные шаблоны (правила) выполняют обход дерева входного документа
(depth-first обход) и переписывают в выходной документ содержание всех
встречающихся текстовых узлов и атрибутов.
• Встроенные шаблоны включают следующие три правила:
1. для текущего узла или корневого узла вызвать шаблоны, которые подходят
для его дочерних узлов:
<xsl:template match="* | /">
<xsl:apply-templates />
</xsl:template>
2. если текущий узел является текстовым узлом или атрибутом, то его значение
переносится в результирующий документ:
<xsl:template match="text() | @*">
<xsl:value-of select="." />
</xsl:template>
3. если текущий узел является инструкцией для XML процессора или
комментарием, то ничего не делается:
<xsl:template match="processing-instruction() | comment()" />
Шаблонное правило по умолчанию для
узлов элементов и корневого узла
• Самое важное шаблонное правило гарантирует обработку дочерних
элементов. Правило выглядит следующим образом:
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
Символ «звездочка» (*) является подстановочным выражением XPath,
соответствующим всем узлам элементов, независимо от имени и
пространства имен, к которому они относятся. Но звездочка не
соответствует атрибутам, текстовым узлам, комментариям или узлам
инструкций обработки.
• Косая черта (/) – это выражение XPath, соответствующее корневому
узлу, который выбирается для обработки первым, следовательно, и
этот шаблон процессор исполняет первым (если только не
существует другого шаблона, отличного от встроенного,
который также соответствовал бы корневому узлу).
• Если рассматривать данное правило изолированно, оно означает,
что XSLT в итоге находит и применяет шаблоны ко всем узлам,
кроме узлов атрибутов и пространств имен
– так как любой узел, кроме узлом атрибутов или пространств
имен, является корневым узлом или его наследником (дочерним
узлом корневого узла или дочерним узлом элемента).
• Только узлы атрибутов и пространств имен не являются
дочерними узлами своих родителей (их можно рассматривать
как узлы, «лишенные наследства»).
• Конечно, конкретные шаблоны могут переопределить это
встроенное правило.
– Например, когда в таблицу преобразований включен шаблон,
соответствующий элементам person, дочерние элементы person не
обязательно будут обрабатываться, если только особый шаблон не
укажет на необходимость их обработки.
Шаблонное правило по умолчанию для текстовых
узлов и узлов атрибутов
•
Самое основное из встроенных шаблонных правил копирует значение текстовых
узлов и узлов атрибутов в выходной документ. Это выглядит следующим образом:
<xsl:template match="text()|@*">
<xsl:value-of select="."/>
</xsl:template>
•
•
•
•
•
Функция text() – это выражение XPath, соответствующее всем текстовым узлам,
аналогично тому, как first_name является выражением XPath, соответствующим
всем узлам элементов first_name.
@* – это выражение XPath, соответствующее всем узлам атрибутов. Вертикальная
черта объединяет эти два выражения, выбирая и текстовые узлы и узлы атрибутов.
Содержимое этого шаблона говорит о том, что при обнаружении текстового узла
или узла атрибута процессор должен вывести значение этого узла.
Для текстового узла это значение равно просто его тексту.
Для атрибута значение равно значению атрибута узла, но не его имени.
Шаблон по умолчанию для узлов комментариев и
узлов инструкций обработки
• Встроенное шаблонное правило для
комментариев и инструкций обработки выглядит
следующим образом:
<xsl:template
match="processing-instruction()|comment()"/>
• Это правило относится ко всем комментариям и
инструкциям обработки.
• Оно ничего не выводит в дерево результата.
• Если не предоставить конкретных правил для
комментариев и инструкций обработки, никакие
части этих узлов не будут скопированы из
входного документа в выходной.
Инструкция xsl:value-of
• Элемент value-of добавляет текстовое содержимое
заданного XML-элемента – а также любых его дочерних
элементов, которые он имеет – в выходной XML документ.
• Заданный XML-элемент указывается заданием образца,
который присваиваете атрибуту «select» XSL-элемента
value-of.
• Элемент «xsl:value-of» вычисляет выражение, записанное в
его обязательном атрибуте select, и преобразует его в
строку.
– Например, чтобы для ранее определенного объекта var2,
получить значение надо записать:
<xsl:value-of select="$var2" />
• Если в результате вычисления выражения получается
последовательность, то процессор XSLT выберет из нее
только первый элемент, преобразованный в строку.
• На рисунке показано как браузер генерирует первую часть
блока HTML-разметки для документа и таблицы стилей.
Порядок работы XSLT процессора
Последовательность работы процессора
XSLT
1.
2.
3.
4.
5.
6.
7.
8.
Строится дерево, являющуюся внутренним представлением XML
документа.
Создается структура для XSLT документа (это может быть также дерево
или структура любого типа, оптимизированная для обработки шаблонов
и соответствия образцов).
Выбирается корневой элемент входного документа (оно становится
контекстным).
Каждый раз, встретив элемент типа <xsl:apply-templates>, процессор
формируется список узлов и работа продолжается с этим списком.
Если элемент <xsl:apply-templates> содержит атрибут «select», список
узлов формируется на основе указанного запроса XPath.
В противном случае список содержит все дочерние узлы.
Каждый раз, встретив элемент типа <xsl:value-of>, процессор извлекает
значение из исходного дерева, основываясь на выражении XPath его
атрибута select.
Трансформация не ограничивается только трансляцией типа один-кодному: она позволяет добавлять новое информационное содержание,
добавлять и удалять элементы, а также осуществлять преобразование
типа один-ко-многим.
• Затем процессор проделывает следующие шаги для
получения и сериализации результирующего дерева:
– Создаёт корневой узел результирующего дерева.
– Обрабатывает корневой узел исходного дерева. Процедура обработки
узла описана ниже.
– Сериализует результирующее дерево, если необходимо, согласно
подсказкам, описанным инструкцией xsl:output.
Порядок обработки текущего узла
•
Поиск наиболее подходящего шаблона правила.
–
–
–
–
•
Выполнение содержания правил шаблона .
–
–
–
–
–
•
Выполняется проверка соответствия шаблона (который является выражением XPath) для каждого
правила, указывая узлы, для которых правило может быть применено.
XSLT процессор назначает каждому шаблону относительный приоритет и старшинство для
облегчения разрешения конфликтов.
Порядок шаблонных правил в таблице стилей также может помочь разрешению конфликтов между
шаблонами, которые соответствуют одинаковым узлам,
но это не оказывает влияния на порядок, в котором узлы будут обрабатываться.
Не XSLT-элементы и текстовые узлы, обнаруженные в правиле, копируются, «дословно», в
результирующее дерево.
Комментарии и управляющие инструкции игнорируются.
XSLT элементы рассматриваются, как инструкции и имеют специальную семантику, которая
указывает на то, как они должны интерпретироваться.
Одни XSLT элементы предназначены для добавления узлов в результирующее дерево,
другие XSLT элементы являются управляющими конструкциями.
Обработка инструкции xsl:apply-templates приводит к выборке и обработке
нового набора узлов.
–
Узлы идентифицируются с помощью выражения XPath. Все узлы обрабатываются в том порядке, в
котором они содержатся в исходном документе.
• XSLT расширяет библиотеку XPath функций и позволяет определять
XPath-переменные.
– Эти переменные имеют разную область видимости в таблице стилей, в
зависимости от того, где они были определены и их значения могут
задаваться за пределами таблицы стилей.
– Значения переменных не могут быть изменены во время обработки.
• Хотя эта процедура может показаться сложной, однако она делает
XSLT по возможностям похожей на другие языки web-шаблонов.
• Если таблица стилей состоит из единственного правила,
предназначенного для обработки корневого узла, в результате
просто копируется всё содержимое шаблона, а XSLT-инструкции
(элементы 'xsl:…') заменяются вычисляемым содержимым.
– XSLT предлагает даже специальный формат («literal result element as
stylesheet») для таких простых, одношаблонных трансформаций.
• Однако, возможность определять отдельные шаблоны и правила
сильно увеличивает гибкость и эффективность XSLT, особенно при
генерации результата, который очень похож на исходный документ.
Пример XSLT трансформации
Пример преобразования XML
документа
<?xml version="1.0"?>
<?xml version="1.0"?>
<!-- File name: XslDemo01.xsl -->
<!-- File name: XslDemo01.xml -->
<?xml-stylesheet type="text/xsl"
href="XslDemo01.xsl"?>
<BOOK>
<TITLE>Moby-Dick</TITLE>
<AUTHOR>
<FIRSTNAME>Herman</FIRSTNAME>
<LASTNAME>Melville</LASTNAME>
</AUTHOR>
<BINDING>hardcover</BINDING>
<PAGES>724</PAGES>
<PRICE>$9.95</PRICE>
</BOOK>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<H2>Book Description</H2>
<SPAN STYLE="font-style:italic">Author: </SPAN>
<xsl:value-of select="BOOK/AUTHOR"/><BR/>
<SPAN STYLE="font-style:italic">Title: </SPAN>
<xsl:value-of select="BOOK/TITLE"/><BR/>
<SPAN STYLE="font-style:italic">Price: </SPAN>
<xsl:value-of select="BOOK/PRICE"/><BR/>
<SPAN STYLE="font-style:italic">Binding type: </SPAN>
<xsl:value-of select="BOOK/BINDING"/><BR/>
<SPAN STYLE="font-style:italic">Number of pages: </SPAN>
<xsl:value-of select="BOOK/PAGES"/>
</xsl:template>
</xsl:stylesheet>
Использование нескольких
шаблонов
•
Другой способ отображения повторяющихся XML-элементов состоит в создании отдельного
шаблона для каждого элемента с последующим вызовом этого шаблона с использованием XSLэлемента apply-templates.
–
Например:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<H2>Book Inventory</H2>
<xsl:apply-templates select="INVENTORY/BOOK" />
</xsl:template>
<xsl:template match="BOOK">
<SPAN STYLE="font-style:italic">Title: </SPAN>
<xsl:value-of select="TITLE"/><BR/>
<SPAN STYLE="font-style:italic">Author: </SPAN>
<xsl:value-of select="AUTHOR"/><BR/>
<SPAN STYLE="font-style:italic">Binding type: </SPAN>
<xsl:value-of select="BINDING"/><BR/>
<SPAN STYLE="font-style:italic">Number of pages: </SPAN>
<xsl:value-of select="PAGES"/><BR/>
<SPAN STYLE="font-style:italic">Price: </SPAN>
<xsl:value-of select="PRICE"/><P/>
</xsl:template>
</xsl:stylesheet>
• В данном примере таблицы преобразования содержится два
шаблона.
• Один шаблон содержит инструкции для отображения всего документа
(путем установки match="/", указывающей на корневую часть
документа).
– Все XSL-таблицы стилей требуют наличия такого шаблона.
• Другой шаблон содержит инструкции для отображения элемента
BOOK (шаблон с установкой match="BOOK").
• Сначала браузер обрабатывает шаблон, соответствующий корневой
части элемента:
<xsl:template match="/">
<H2>Book Inventory</H2>
<xsl:apply-templates select="INVENTORY/BOOK" />
</xsl:template>
• XSL-элемент apply-templates сообщает браузеру, что для каждого
элемента BOOK внутри корневого элемента INVENTORY он должен
обрабатывать шаблон, отвечающий элементу BOOK – т. е. шаблон, для
атрибута match которого установлено значение "BOOK".
•
•
Таблица стилей включает следующий шаблон, отвечающий элементу BOOK:
<xsl:template match="BOOK">
<SPAN STYLE="font-style:italic">Title: </SPAN>
<xsl:value-of select="TITLE"/><BR/>
<SPAN STYLE="font-style:italic">Author: </SPAN>
<xsl:value-of select="AUTHOR"/><BR/>
<SPAN STYLE="font-style:italic">Binding type: </SPAN>
<xsl:value-of select="BINDING"/><BR/>
<SPAN STYLE="font-style:italic">Number of pages: </SPAN>
<xsl:value-of select="PAGES"/><BR/>
<SPAN STYLE="font-style:italic">Price: </SPAN>
<xsl:value-of select="PRICE"/><P/>
</xsl:template>
Поскольку этот шаблон отвечает элементу BOOK, элемент BOOK является
текущим элементом в контексте шаблона. В связи с этим доступ к дочерним
элементам BOOK осуществляется посредством образца, содержащего только
имя элемента, как в нашем примере:
<xsl:value-of select="TITLE"/>
Пример простого XML документа
<?xml version="1.0"?>
<people xmlns="http://namespaces.oreilly.com/people">
<person born="1912" died="1954">
<name>
<first_name>Алан</first_name>
<last_name>Тьюринг</last_name>
</name>
<profession>специалист по информатике</profession>
<profession>математик</profession>
<profession>криптограф</profession>
</person>
<person born="1918" died="1988">
<name>
<first_name>Ричард</first_name>
<middle_initial>Ф</middle_initial>
<last_name>Фейнман</last_name>
</name>
<profession>физик</profession>
<hobby>Игра на бонгах</hobby>
</person>
</people>
Результат обработки вcтроенными
правилами (пустое XSLT)
<?xml version="1.0" encoding="utf-8"?>
Алан
Тьюринг
специалист по информатике
математик
криптограф
Ричард
Ф
Фейнман
физик
Игра на бонгах
Именованные шаблоны
• Именованный шаблон это шаблон, котором задан атрибут «name».
• Он принимает переданные параметры с помощью инструкции
«xsl:param». Например:
<xsl:template name="print">
<xsl:param name="message"/>
<!-- template content goes here -->
</xsl:template>
• Вызов на выполнение именованного шаблона выполняется с
помощью инструкции xsl:call-template (вместо использования
инструкции xsl:apply-templates). Например:
<xsl:call-template name="print">
<xsl:with-param name="message"
select="'See if it prints this message.'"/>
</xsl:call-template>
Режимы
• Иногда одно и то же содержимое из входного
документа должно появиться в выходном документе
несколько раз, каждый раз отформатированное в
соответствии с разными шаблонами.
• Например, заголовки глав книги могут
форматироваться в одном стиле в самих главах и в
другом – в оглавлении книги.
• Оба элемента – xsl:apply-templates и xsl:template –
могут иметь необязательный атрибут «mode»,
ставящий разные шаблоны в соответствие разным
применениям.
– Атрибут mode элемента xsl:template указывает, в каком
режиме следует активизировать этот шаблон. Элемент
xsl:apply-templates с атрибутом mode активизирует только
шаблоны с соответствующими атрибутами mode.
Пример использования шаблонов в таблице стилей,
начинающей выходной документ со списка имен.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0” xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="people">
<html>
<head><title>Знаменитые ученые</title></head>
<body>
<ul><xsl:apply-templates select="person" mode="toc"/></ul>
<xsl:apply-templates select="person"/>
</body>
</html>
</xsl:template>
<!-- Шаблоны режима оглавления -->
<xsl:template match="person" mode="toc“> <xsl:apply-templates select="name"
mode="toc"/> </xsl:template>
<xsl:template match="name" mode="toc">
<li><xsl:value-of select="last_name"/>,
<xsl:value-of select="first_name"/></li>
</xsl:template>
<!-- Шаблоны обычного режима -->
<xsl:template match="person“> <p><xsl:apply-templates/></p> </xsl:template>
</xsl:stylesheet>
Результат
<html>
<head>
<title>Знаменитые ученые</title>
</head>
<body>
<ul>
<li>Тьюринг,
Алан</li>
<li>Фейнман,
Ричард</li>
</ul>
<p>
Алан
Тьюринг
специалист по информатике
математик
криптограф
</p>
<p>
Ричард
М
Фейнман
физик
Игра на бонгах
</p>
</body>
</html>
Результат
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="people">
<html>
<head>
<title>Знаменитые ученые</title>
</head>
<body>
<dl>
<xsl:apply-templates />
</dl>
</body>
</html>
</xsl:template>
<xsl:template match="person">
<dt>
<xsl:apply-templates select="name"/>
</dt>
<dd>
<ul>
<li>
Родился: <xsl:apply-templates select="@born"/>
</li>
<li>
Умер: <xsl:apply-templates select="@died"/>
</li>
</ul>
</dd>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<html>
<head>
<title>Знаменитые ученые</title>
</head>
<body>
<dl>
<dt>
Алан
Тьюринг
</dt><dd><ul><li>
Родился: 1912</li><li>
Умер: 1954</li></ul></dd>
<dt>
Ричард
Ф
Фейнман
</dt><dd><ul><li>
Родился: 1918</li><li>
Умер: 1988</li></ul></dd>
</dl>
</body>
</html>
Фильтрация XML данных
• Значение, которое присваивается атрибутам «match» или
«select», представляет собой образец, соответствующий
одному или нескольким элементам в XML-документе.
– атрибут «match» используется для элемента template,
– атрибут «select» – для элементов «value-of», «for-each» и «applytemplates».
• Количество элементов, соответствующих шаблону, можно
ограничить с помощью фильтров.
• Фильтр это выражение, заключенное в квадратные скобки ([])
и следующее непосредственно за оператором пути.
– Например, образец, присвоенный следующему атрибуту match,
указывает, что соответствующий элемент должен носить имя
BOOK, и кроме того (это определяется фильтром), должен иметь
дочерний элемент BINDING, который содержит текст "trade
paperback":
<xsl:template match="BOOK[BINDING='trade paperback']">
• Если в фильтр включено только имя элемента, то соответствующий
элемент должен иметь дочерний элемент с указанным именем.
Например, следующий образец отвечает любому элементу ITEM,
имеющему дочерний элемент с именем CD, независимо от
содержимого элемента CD:
match="ITEM[CD]"
• Следующий образец отвечает любому элементу SHIRT, имеющему
дочерний элемент COLOR, содержащий текст "red":
match="SHIRT[COLOR='red']"
• А следующий образец, наоборот, отвечает любому элементу SHIRT,
имеющему дочерний элемент COLOR, который не содержит текст
"red":
select="SHIRT[COLOR!='red']"
• Примечание. Если элемент имеет более одного дочернего
элемента с именем, указанным в условии фильтрации, оператор
сравнения применяется только к первому дочернему элементу.
Например, если элемент SHIRT имеет два дочерних элемента
COLOR, образец "SHIRT[COLOR='red']" будет отвечать элементу,
только если первый элемент COLOR содержит слово "red".
• Если опустить атрибут «select» для XSLTэлемента «value-of», элемент будет
осуществлять вывод текстового
содержимого плюс текстовое содержимое
всех дочерних элементов текущего
элемента.
Сортировка данных XML
• C помощью атрибута «order-by» в элементах «for-each» и «applytemplates», можно задавать порядком, в котором XSLT-процессор
будет обрабатывать элементы, тем самым осуществляя сортировку
данных XML.
• Можете назначать атрибуту «order-by» один или несколько
образцов, разделяя их точкой с запятой.
• XSLT-процессор будет сортировать элементы с использованием
образцов в том порядке, в котором они перечислены.
• Для указания направления сортировки (по возрастанию или по
убыванию) следует предварить образец префиксом + или – .
– Например, атрибут order-by, установленный для следующего элемента
for-each, предписывает браузеру сортировать элементы BOOK по
фамилиям авторов в порядке возрастания, а также осуществлять
сортировку для одинаковых фамилий по именам, также по
возрастанию:
<xsl:for-each select="INVENTORY/BOOK"
order-by="+AUTHOR/LASTNAME; +AUTHOR/FIRSTNAME">
• В другом примере следующая установка «order-by»
осуществляет сортировку элементов BOOK по
названиям книг по убыванию:
<xsl:apply-templates
select="INVENTORY/BOOK" order-by="-TITLE">
• Присваиваемый атрибуту «order-by» оператор пути,
действует относительно образца, назначенного
атрибуту select.
– Например установка order-by="-TITLE" указывает на
элемент TITLE внутри элемента BOOK, вложенного в
элемент INVENTORY.
Работа с XML атрибутами
• XSLT рассматривает атрибут, принадлежащий элементу в XMLдокументе, как дочерний элемент.
• В XPath маршрутах в ссылках на атрибуты перед их именем
должен ставиться символом @, указывающий на то, что имя
относится к атрибуту, а не к элементу.
• Например, фильтр в следующем начальном тэге выделяет все
элементы BOOK с атрибутом InStock, имеющем значение "yes".
Другими словами, он выбирает только книги, которые имеются в
наличии:
<xsl:for-each select="INVENTORY/BOOK[@InStock='yes']">
• Можете использовать XSLT-элемент value-of для извлечения
значений атрибута точно так же, как вы это делаете для
извлечения текстового содержимого элемента.
– Например, следующий элемент value-of получает значение атрибута
Born, принадлежащего элементу AUTHOR:
<xsl:value-of select="AUTHOR/@Born"/>
Пример работы с атрибутами
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform” >
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<html> <xsl:apply-templates select="people"/> </html>
</xsl:template>
<xsl:template match="people">
<table> <xsl:apply-templates select="person"/> </table>
</xsl:template>
<xsl:template match="person">
<tr>
<td> <xsl:value-of select="name"/></td>
<td> <xsl:value-of select="@born"/> </td>
<td> <xsl:value-of select="@died"/> </td>
</tr>
</xsl:template>
</xsl:stylesheet>
Результат
<?xml version="1.0" encoding="utf-8"?>
<html>
<table>
<tr>
<td>
Алан
Тьюринг
</td>
<td>1912</td>
<td>1954</td>
</tr>
<tr>
<td>
Ричард
Ф
Фейнман
</td>
<td>1918</td>
<td>1988</td>
</tr>
</table>
</html>
Таблица стилей XSLT, использующая
полный синтаксис XPath
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<dl> <xsl:apply-templates select="descendant::person"/> </dl>
</xsl:template>
<xsl:template match="person">
<dt> <xsl:value-of select="child::name"/> </dt>
<dd> <ul> <xsl:apply-templates select="child::name/following-sibling::*"/> </ul> </dd>
</xsl:template>
<xsl:template match="*">
<li> <xsl:value-of select="self::*"/> </li>
</xsl:template>
<xsl:template match="homepage" xmlns:XLink="http://www.w3.org/1999/XLink">
<li> <xsl:value-of select="attribute::XLink:href"/> </li>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<dl>
<dt>
Алан
Тьюринг
</dt>
<dd>
<ul>
<li>специалист по информатике</li>
<li>математик</li>
<li>криптограф</li>
</ul>
</dd>
<dt>
Ричард
Ф
Фейнман
</dt>
<dd>
<ul>
<li>физик</li>
<li>Игра на бонгах</li>
</ul>
</dd>
</dl>
Декларация xsl:function
• Элемент xsl:function позволяет описывать обычные пользовательские
функции.
– в обязательном атрибуте «nаmе» задается имя функции. Имя функции - это
уточненное имя типа QName, причем оно должно обязательно записываться с
префиксом.
– в необязательным атрибутом «аs» можно указать тип функции.
• В элементе описания функции записываются элементы с аргументами и
тело функции.
– с помощью элементов xsl:param задаются аргументы функции.
– в содержимом элемента xsl:function задается тело функции. Это конструктор
последовательности.
• Результатом функции будет последовательность, созданная
конструктором.
• Все аргументы функции позиционные, следовательно, все элементы
xsl:param должны быть записаны в начале тела функции и порядок их
записи имеет значение при вызове функции.
• У аргументов функции не может быть значений по умолчанию,
следовательно, элементы xsl:param должны быть пустыми и у них не
должно быть атрибутов select.
Пример функции
• Например:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:usr="http://myexamples.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl: function nаme= “usr:sum" as="xsl:integer">
<xsl:param name="x" as="xsl:integer" />
<хsl:раrаm name="y" as="xsl:integer" />
<xsl:value-of select="$x + $y" />
</xsl:function>
• вызвать функцию можно в любом выражении подходящего
типа, записав ее имя и аргументы в скобках. Например:
<хsl:value-of select="10 + 2 * usr:sum(2, 3)" />
Инструкции управления
Инструкции управления xsl:if
• Элемент «xsl:if» запускает конструктор
последовательности, содержащийся в его теле,
только если выражение, записанное в
обязательном и единственном атрибуте «test»,
является истинным :
<xsl:if test="$x > $у">
<xsl:value-of select="$x" />
больше
<xsl:value-of select="$y" />
</xsl:if>
Инструкции управления xsl:for-each
• Элемент «xsl:for-each» задает цикл,
выполняющийся для каждого элемента
последовательности, полученной в результате
вычисления выражения атрибута «select».
• У элемента «xsl:for-each» имеет один
обязательны атрибуте «select», в котором
задается выражение, дающее в результате
последовательность.
• Для каждого члена этой последовательности
выполняется конструктор, содержащийся в
теле элемента xsl:for-each.
Инструкция управления xsl:choose
• У элемента xsl:choose нет ни одного атрибута, но в его теле
записывается один или несколько элементов «xsl:when» (варианты)
и один необязательный элемент «xsl:otherwise»:
• Например:
<xsl:choose>
<xsl when test="$day=l">Понедельник</xsl:when>
<xsl when test="$day=2">Bторник</xsl:when>
<xsl when test="$day=3">Cреда</xsl:when>
<xsl when test="$day=4">Четверг</xsl:when>
<xsl when test="$day=5">Пятница</xsl:when>
<xsl when test="$day=6">Cy66oтa</xsl:when>
<xsl when test="$day=7">Bocкpeceнье</xsl:when>
<xsl otherwise>Ошибка определения дня нeдeли</xsl:otherwise>
</xsl:choose>
• Элемент xsl:when имеет
– один обязательный параметр «test», содержащий логическое выражение,
– тело, содержащее конструктор последовательности.
• Элемент xsl: otherwise
– не имеет атрибутов,
– есть только тело, содержащее конструктор последовательности.
• В инструкции xsl: choose всегда выполняется не больше одного
варианта.
• Элементы xsl:when (варианты) просматриваются в порядке их записи
в инструкции xsl:choose.
• Как только будет найден вариант с истинным значением выражения
test, он будет выполнен, и результат этого варианта будет результатом
всей инструкции.
• Варианты, следующие за ним по порядку, не рассматриваются.
• Если ни один вариант не подойдет, то результатом инструкции будет
результат конструктора, записанного в элементе xsl:otherwise.
• Если элемента xsl:otherwise в инструкции нет, то результатом будет
пустая строка.
Пояснение работы XSLT
трансформации с помощью
использования именованных
шаблонов
XSLT работает следующим образом
• Загружает входной документ в виде DOM дерева (внутренне
процессор оптимизирует работу с DOM, но для пояснения работы
процессора это не важно).
• Выполняет обход дерева входного документа по принципу
«вначале в глубину» (depth-first walk) (это обычный алгоритм
обхода деревьев из теории алгоритмов) (но это если используется
инструкция <xsl:apply-templates/> ???? Или в результате
использования шаблона по умолчанию ????).
• По мере обхода документа выполняется выбор шаблона (template)
в таблице преобразования (stylesheet) для текущего узла (node).
• Выполняется применение данного шаблона, который описывает,
как создать ноль, один или несколько узлов (nodes) в
формируемом дереве (output tree).
• В результате выполнения обхода из входного дерева и правил,
заданных в шаблонах, создается новое дерево (выходное дерево).
• Выходное дерево записывается в соответствии с HTML или XML
синтаксисом.
Пример XML-документа с описанием
статьи
<?xml version="1.0"?>
<db:article xmlns:db="http://ananas.org/2002/docbook/subset">
<db:title>XSLT, JSP and PHP</db:title>
<db:section>
<db:title>Is there a difference?</db:title>
<db:para>Yes there is! XSLT is a pure XML technology that traces its roots
to <db:emphasis>tree manipulation algorithms</db:emphasis>. JSP and PHP offer an
ingenious solution to combine scripting languages with HTML/XML
tagging.</db:para>
<db:para>The difference may not be obvious when you're first learning
XSLT (after all, it offers tags and instructions), but understanding the difference will
make you a <db:emphasis role="bold">stronger and better</db:emphasis>
developer.</db:para>
</db:section>
<db:section>
<db:title>How do I learn the difference?</db:title>
<db:para>Interestingly enough, you can code the XSLT algorithm in XSLT... one cool way
to experiment with the difference.</db:para>
</db:section>
</db:article>
Как процессор видит XML документ
Пример 1: простое преобразования XML
документа в HTML
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:db="http://ananas.org/2002/docbook/subset">
<xsl:output method="html"/>
<xsl:template match="db:article"> // поиск корневого элемента ???
<html> <head>
<title> <xsl:value-of select="db:articleinfo/db:title"/> </title></head>
<body>
<xsl:apply-templates/>
// выполняется обход «сначала вглубь» ???
</body> </html>
</xsl:template>
<xsl:template match="db:para">
<p><xsl:apply-templates/></p>
// выполняется обход «сначала вглубь» ???
</xsl:template>
<xsl:template match="db:ulink">
<a href="{@url}"><xsl:apply-templates/></a> // выполняется обход «сначала вглубь» ???
</xsl:template>
<xsl:template match="db:article/db:title">
<h1><xsl:apply-templates/></h1> // выполняется обход «сначала вглубь» ???
</xsl:template>
<xsl:template match="db:title">
<h2><xsl:apply-templates/></h2> // выполняется обход «сначала вглубь» ???
</xsl:template>
<xsl:template match="db:emphasis[@role='bold']">
<b><xsl:apply-templates/></b>
</xsl:template>
<xsl:template match="db:emphasis“>
<i><xsl:apply-templates/></i>
// выполняется обход «сначала вглубь» ???
</xsl:template>
</xsl:stylesheet>
Пример 2
• Пример 2 является аналогом примера 1, но в нем обход
дерева выполняется более явно.
• Вместо того, чтобы рассчитывать, что процессор будет
выполнять обход, данное преобразование использует
именованный шаблоны «main», который реализует
требуемый обход дерева.
• Именованный шаблоны«main» является рекурсивной
функцией, которая принимает набор узлов в текущем
аргументе и выполняет циклы по этому множеству узлов.
• Основной частью данного шаблона является инструкция
«choose», которая пытается найти наиболее подходящие
правила для рассматриваемого узла (given node).
• При обработке узла (node), данный шаблон рекурсивно
вызывает себя для обработки дочерних узлов текущего
узла.
Именованные шаблоны
• Именованный шаблон это шаблон, котором задан атрибут «name».
• Он принимает переданные параметры с помощью инструкции
«xsl:param». Например:
<xsl:template name="print">
<xsl:param name="message"/>
<!-- template content goes here -->
</xsl:template>
• Вызов на выполнение именованного шаблона выполняется с
помощью инструкции xsl:call-template (вместо использования
инструкции xsl:apply-templates). Например:
<xsl:call-template name="print">
<xsl:with-param name="message"
select="'See if it prints this message.'"/>
</xsl:call-template>
Пример 2 таблицы преобразования,
явно задающую порядок обхода вершин
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:db="http://ananas.org/2002/docbook/subset">
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:call-template name="main">
<xsl:with-param name="nodes" select="."/> // задается параметр
</xsl:call-template>
</xsl:template>
<xsl:template name="main">
<xsl:param name="nodes"/>
<xsl:for-each select="$nodes">
// цикл по параметрам
<xsl:choose>
// задается параметр
<xsl:when test="self::db:article">
// если это элемент db:article
<html> <head><title>
<xsl:value-of select="db:title"/> </title></head> <body>
<xsl:call-template name="main">
// рекурсивный вызов !?
<xsl:with-param name="nodes" select="child::node()"/>
</xsl:call-template> </body> </html>
</xsl:when>
<xsl:when test="self::db:para"> <p>
<xsl:call-template name="main">
<xsl:with-param name="nodes" select="child::node()"/>
</xsl:call-template> </p>
</xsl:when>
<xsl:when test="self::db:ulink">
// если это элемент db:ulink
<a href="{@url}">
<xsl:call-template name="main">
// рекурсивный вызов !?
<xsl:with-param name="nodes" select="child::node()"/>
</xsl:call-template> </a>
</xsl:when>
<xsl:when test="self::db:title[parent::db:article]"> // если это элемент db:title[parent::db:article
<h1>
<xsl:call-template name="main">
// рекурсивный вызов !?
<xsl:with-param name="nodes" select="child::node()"/>
</xsl:call-template>
</h1>
</xsl:when>
<xsl:when test="self::db:title">
// если это элемент db:title
<h2>
<xsl:call-template name="main">
// рекурсивный вызов !?
<xsl:with-param name="nodes" select="child::node()"/>
</xsl:call-template>
</h2>
</xsl:when>
<xsl:when test="self::db:emphasis[@role='bold']"> <b>
<xsl:call-template name="main">
// рекурсивный вызов !?
<xsl:with-param name="nodes" select="child::node()"/>
</xsl:call-template> </b>
</xsl:when>
<xsl:when test="self::db:emphasis“> <i>
<xsl:call-template name="main">
// рекурсивный вызов !?
<xsl:with-param name="nodes" select="child::node()"/>
</xsl:call-template> </i>
</xsl:when>
<xsl:when test="self::text()">
<xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="main">
// рекурсивный вызов !?
<xsl:with-param name="nodes" select="child::node()"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Рекомендация
• На практике не используется явный способ обхода вершин графа (как
показано в примере 2).
• XSLT процессор обеспечивает базовое выполнение обхода «depth-first»
(такое, как выполнение цикла и передача параметров).
• Например, для обработки элементов db:emphasis начинающие разработчики
могут записать следующий код:
<xsl:template match="db:emphasis">
// если встречается элемент
выделения текста «db:emphasis»
<xsl:choose>
<xsl:when test="@role='bold'">
// если задан атрибут role='bold‘,
// то «жирный шрифт»
<b><xsl:apply-templates/></b>
</xsl:when>
<xsl:otherwise>
<i><xsl:apply-templates/></i>
// иначе «курсив»
</xsl:otherwise>
</xsl:choose>
</xsl:template>
• Однако зная порядок работы XSLT процессора проще записать следующий
полностью эквивалентный код:
<xsl:template match="db:emphasis[@role='bold']">
<b><xsl:apply-templates/></b>
</xsl:template>
<xsl:template match="db:emphasis">
<i><xsl:apply-templates/></i>
</xsl:template>
Шаблоны значений атрибутов
• Легко включить известные значения атрибутов в выходной документ в
виде строкового содержимого элемента результата.
– Например, данное шаблонное правило заключает каждый входной элемент
person в HTMLэлемент span с атрибутом class, имеющим значение person:
<xsl:template match="person">
<span class="person"><xsl:apply-templates/></span>
</xsl:template>
• Однако задача усложняется, если значение атрибута при написании
таблицы стилей не известно и должно быть прочитано из входного
документа.
• Решением будет использование шаблона значения атрибута.
• Шаблон значения атрибута – это выражение XPath, заключенное в
фигурные скобки и помещаемое внутрь значения атрибута в таблице
стилей.
• Когда процессор выводит этот атрибут, он заменяет шаблон значения
атрибута на фактическое значение.
• Например, предположим, что составляется шаблон имени, который
заменяет входные элементы name на пустые элементы с
атрибутами first_name, middle_initial и last_name следующего вида:
<name first="Ричард" initial="Ф" last="Фейнман"/>
• Такую задачу выполняет следующий шаблон:
<xsl:template match="name">
<name first="{first_name}"
initial="{middle_initial}"
last="{last_name}" />
</xsl:template>
• Значение атрибута first в таблице стилей заменяется значением
элемента first_name из входного документа, значение атрибута
initial меняется на значение элемента middle_initial из входного
документа, а значение атрибута last – на значение элемента
last_name.
Пример XML документа
<?xml version="1.0"?>
<people xmlns="http://namespaces.oreilly.com/people">
<person born="1912" died="1954“>
<name>
<first_name>Алан</first_name>
<last_name>Тьюринг</last_name>
</name>
<profession>специалист по информатике</profession>
<profession>математик</profession>
<profession>криптограф</profession>
</person>
<person born="1918" died="1988">
<name>
<first_name>Ричард</first_name>
<middle_initial>Ф</middle_initial>
<last_name>Фейнман</last_name>
</name>
<profession>физик</profession>
<hobby>Игра на бонгах</hobby>
</person>
</people>
Пример XSLT преобразования
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:pe="http://namespaces.oreilly.com/people">
<xsl:template match="pe:people">
<html> <head><title>Знаменитые ученые</title></head><body>
<xsl:apply-templates/>
</body></html>
</xsl:template>
<xsl:template match="pe:name">
<p><xsl:value-of select="pe:last_name"/>,
<xsl:value-of select="pe:first_name"/></p>
</xsl:template>
<xsl:template match="pe:person">
<xsl:apply-templates select="pe:name"/>
</xsl:template>
</xsl:stylesheet>
• Элемент <stylesheet> содержит три шаблона, каждый из
которых вложен в элемент <template>.
• В таблице стилей этот элемент фактически называется
<xsl:template>, так как задано пространство имен.
• У элемента <template> есть атрибут match, значением
которого является образец (pattern) в форме выражения
XPath.
• С ним сравнивается узел дерева, к которому применяется
шаблон.
• Прежде всего процессору XSL надо сообщить желаемую
форму вывода.
• Узнав ожидаемый формат вывода, процессор начнет
исследовать исходный документ с корневого узла.
XML документ
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="XslDemo06.xsl"?>
<INVENTORY>
<BOOK InStock="yes“> <TITLE>The Adventures of Huckleberry Finn</TITLE>
<AUTHOR Born="1835">Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING>
<PAGES>298</PAGES> <PRICE>$5.49</PRICE>
</BOOK>
<BOOK InStock="no"> <TITLE>Leaves of Grass</TITLE>
<AUTHOR Born="1819">Walt Whitman</AUTHOR> <BINDING>hardcover</BINDING>
<PAGES>462</PAGES> <PRICE>$7.75</PRICE>
</BOOK>
<BOOK InStock="yes"> <TITLE>The Marble Faun</TITLE>
<AUTHOR Born="1804">Nathaniel Hawthorne</AUTHOR>
<BINDING>trade paperback</BINDING> <PAGES>473</PAGES>
<PRICE>$10.95</PRICE> </BOOK>
<BOOK InStock="yes"> <TITLE>Moby-Dick</TITLE>
<AUTHOR Born="1819">Herman Melville</AUTHOR> <BINDING>hardcover</BINDING>
<PAGES>724</PAGES> <PRICE>$9.95</PRICE>
</BOOK>
</INVENTORY>
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform”>
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<HTML> <TITLE> Список книг </TITLE>
<BODY> <H2>Книги на складе</H2>
<TABLE BORDER="1" CELLPADDING="5">
<THEAD> <TH>Название</TH> <TH>Автор</TH>
<TH>Тип переплета</TH> <TH>Кол-во страниц</TH> <TH>Цена</TH>
</THEAD>
<xsl:for-each select="INVENTORY/BOOK[@InStock='yes']">
<TR ALIGN="CENTER"> <TD> <xsl:value-of select="TITLE"/> </TD>
<TD> <xsl:value-of select="AUTHOR"/> <BR/>
(born <xsl:value-of select="AUTHOR/@Born"/>)
</TD>
<TD> <xsl:value-of select="BINDING"/> </TD>
<TD> <xsl:value-of select="PAGES"/> </TD>
<TD> <xsl:value-of select="PRICE"/> </TD>
</TR>
</xsl:for-each>
</TABLE> </BODY> </HTML>
</xsl:template>
</xsl:stylesheet>
Примеры XSLT преобразований
XML документа в HTML документ
Пример XML документа
<?xml version="1.0" encoding="utf-8"?>
<PlayList>
<Track Id="1170056tuNb" Length="280">
<Artist>Рихард Вагнер</Artist>
<Title>Полёт валькирии</Title>
</Track>
<Track Id="938304vu1E" Length="163">
<Artist>Эдвард Григ</Artist>
<Title>В пещере горного короля</Title>
</Track>
<Track Id="35532014SEz" Length="187">
<Artist>Иоган Бах</Artist>
<Title>Токката и фуга ре-минор</Title>
</Track>
<Track Id="264667GXiD" Length="203">
<Artist>Антонио Вивальди</Artist>
<Title>Времена года. Лето. Шторм</Title>
</Track>
<Track Id="613982Fj9E" Length="103">
<Artist>Джузеппе Верди</Artist>
<Title>Триумфальный марш (Аида)</Title>
</Track>
</PlayList>
Требуется создать список
Пример XSLT преобразования
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY mdash "—"> ]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="PlayList"/> // тоже самое без select="PlayList"
</xsl:template>
<xsl:template match="PlayList">
<ul> <xsl:apply-templates select="Track"/> </ul>
</xsl:template>
<xsl:template match="Track">
<li> <a href="http://prostopleer.com/tracks/{@Id}">
<xsl:value-of select="Artist"/>
<xsl:text> — </xsl:text>
<xsl:value-of select="Title"/>
</a>
</li>
</xsl:template>
</xsl:stylesheet>
• Данное XSLT-преобразование состоит из трёх шаблонов
(xsl:template).
• Каждый шаблон обслуживает свою сущность, что даёт
возможность легко вносить изменения и делает код понятным.
• Если требуется поменять отображение списка (например,
добавить атрибут class), то надо редактировать шаблон
match="PlayList".
• Если требуется изменить отображение элементов списка, то
следует менять шаблон match="Track"
• Фактически, XSLT не только даёт возможность разделить
данные и представление, но и позволяет разделить
представления различных сущностей.
• Конечно, в более сложных случаях добиться такого разделения
бывает сложно.
Получаемый результат
<ul>
<li>
<a href="http://prostopleer.com/tracks/1170056tuNb">
Рихард Вагнер — Полёт валькирии</a>
</li>
<li>
<a href="http://prostopleer.com/tracks/938304vu1E">
Эдвард Григ — В пещере горного короля</a>
</li>
...
</ul>
Получаемый результат
преобразования
<ul>
<li>
<a href="http://prostopleer.com/tracks/1170056tuNb">Рихард Вагнер — Полёт валькирии</a>
</li>
<li>
<a href="http://prostopleer.com/tracks/938304vu1E">Эдвард Григ — В пещере горного короля</a>
</li>
<li>
<a href="http://prostopleer.com/tracks/35532014SEz">Иоган Бах — Токката и фуга ре-минор</a>
</li>
<li>
<a href="http://prostopleer.com/tracks/264667GXiD">Антонио Вивальди — Времена года. Лето.
Шторм</a>
</li>
<li>
<a href="http://prostopleer.com/tracks/613982Fj9E">Джузеппе Верди — Триумфальный марш
(Аида)</a>
</li>
</ul>
Немного измененное преобразование
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY mdash "—">
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<ul>
<xsl:apply-templates />
</ul>
</xsl:template>
<xsl:template match="Track">
<li>
<a href="http://prostopleer.com/tracks/{@Id}">
<xsl:value-of select="Artist"/>
<xsl:text> — </xsl:text>
<xsl:value-of select="Title"/>
</a>
</li>
</xsl:template>
</xsl:stylesheet>
Результат такой же
<ul>
<li><a href="http://prostopleer.com/tracks/1170056tuNb">Рихард
Вагнер — Полёт валькирии</a></li>
<li><a href="http://prostopleer.com/tracks/938304vu1E">Эдвард Григ —
В пещере горного короля</a></li>
<li><a href="http://prostopleer.com/tracks/35532014SEz">Иоган Бах —
Токката и фуга ре-минор</a></li>
<li><a href="http://prostopleer.com/tracks/264667GXiD">Антонио
Вивальди — Времена года. Лето. Шторм</a></li>
<li><a href="http://prostopleer.com/tracks/613982Fj9E">Джузеппе
Верди — Триумфальный марш (Аида)</a></li>
</ul>
• Отметим, что в приведенном примере используется
сущность “—”, которая определяется в начале XSLTдокумента
<!DOCTYPE xsl:stylesheet
[
<!ENTITY mdash "—">
]>
• Таким образом, — выводится, как символ с кодом
—.
• Если нужно вывести строку «какая она есть», то стоит
использовать CDATA следующим образом:
<xsl:text disable-output-escaping="yes">
<![CDATA[ — ]]>
</xsl:text>
Элемент xsl:text
•
•
•
•
Элемент xsl:text позволяет контролировать, что именно будет содержать TEXTэлемент.
Если элемент xsl:text не использовать:
<xsl:template match="Track">
<li>
<a href="http://prostopleer.com/tracks/{@Id}">
<xsl:value-of select="Artist"/>
—
<xsl:value-of select="Title"/>
</a>
</li>
</xsl:template>
То в результате получается следующий HTML код:
<li>
<a href="http://prostopleer.com/tracks/264667GXiD">
Антонио Вивальди
–
Времена года. Лето. Шторм
</a>
</li>
Т.е., отсутствие элемента xsl:text привело к появлению в HTML лишних переводов
строк и пробелов.
• Конечно, можно написать XSLT преобразование и без xsl:text,
следующим образом:
<xsl:template match="Track">
<li>
<a href="http://prostopleer.com/tracks/{@Id}">
<xsl:value-of select="Artist"/> — <xsl:value-of
select="Title"/>
</a>
</li>
</xsl:template>
• Но такой шаблон тяжелее читать и есть больше возможности, при
сопровождении, сделать в нем ошибку.
• Нужно стараться, чтобы форматирование XSLT-шаблона не
влияло на результат трансформации.
• Именно хорошая практикой считается использование элемента
xsl:text.
Ветвление
• Для ветвления в XSLT есть специальные
элементы: xsl:if и xsl:choose.
• Но ими не следует сильно злоупотреблять.
• Лучше использовать приёмы, позволяющие не
загромождать преобразование ветвлениями.
Решение с использованием xsl:choose
Пример
использования
ветвлений:
дополнение
предыдущего
примера
возможностью
выводить
сообщения «Список
пуст» в случае, если
PlayList не содержит
элементов Track.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY mdash "—"> ]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="PlayList"/>
</xsl:template>
<xsl:template match="PlayList">
<xsl:choose>
<xsl:when test="count(Track) = 0">
<div> <xsl:text><![CDATA[Список пуст]]></xsl:text> </div>
</xsl:when>
<xsl:otherwise>
<ul> <xsl:apply-templates select="Track"/> </ul>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Track">
<li> <a href="http://prostopleer.com/tracks/{@Id}">
<xsl:value-of select="Artist"/> <xsl:text> — </xsl:text> <xsl:value-of select="Title"/>
</a>
</li>
</xsl:template>
</xsl:stylesheet>
Решение с использованием дополнительного
шаблона
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY mdash "—"> ]>
<xsl:stylesheet version="1.0” xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="PlayList"/>
</xsl:template>
<xsl:template match="PlayList[count(Track) = 0]" >
<div> <xsl:text><![CDATA[Список пуст]]></xsl:text> </div>
</xsl:template>
<xsl:template match="PlayList">
<ul> <xsl:apply-templates select="Track"/> </ul>
</xsl:template>
<xsl:template match="Track">
<li><a href="http://prostopleer.com/tracks/{@Id}">
<xsl:value-of select="Artist"/> <xsl:text> — </xsl:text>
<xsl:value-of select="Title"/> </a>
</li>
</xsl:template>
</xsl:stylesheet>
• Второе решение, является более эффектным: новая
функциональность не добавила нового кода в старые
шаблоны, новый шаблон максимально изолирован.
• Если понадобится добавить картинку к сообщению о пустом
списке, то в первом случае скорее всего будет сделано
дополнение к элементу xsl:when в шаблоне match="PlayList".
• А вот во втором случае изменения будут только в
специализированном шаблоне.
• В предыдущем примере было выполнено разделение на две
абсолютно разные ветки отображения элемента списка.
• Если ветви различаются незначительно то использование xsl:if
и xsl:choose вполне оправдано.
• Имеется другой подход: использование параметра mode у
элемента xsl:template.
Задание разных стилей на чётные и нечётные
элементы списка
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY mdash "—"> ]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="PlayList">
<ul> <xsl:apply-templates select="Track"/> </ul>
</xsl:template>
<xsl:template match="Track“> <li>
<xsl:attribute name="class">
<xsl:apply-templates select="." mode="add-track-class"/>
</xsl:attribute>
<a href="http://prostopleer.com/tracks/{@Id}">
<xsl:value-of select="Artist"/> <xsl:text> — </xsl:text> <xsl:value-of select="Title"/>
</a></li>
</xsl:template>
<xsl:template mode="add-track-class" match="Track[position() mod 2 = 0]" >
<xsl:text>even</xsl:text>
</xsl:template>
<xsl:template mode="add-track-class" match="Track" >
<xsl:text>odd</xsl:text>
</xsl:template>
</xsl:stylesheet>
Результат
<ul>
<li class="odd">
<a href="http://prostopleer.com/tracks/1170056tuNb">Рихард Вагнер — Полёт валькирии</a>
</li>
<li class="even">
<a href="http://prostopleer.com/tracks/938304vu1E">Эдвард Григ — В пещере горного
короля</a>
</li>
<li class="odd">
<a href="http://prostopleer.com/tracks/35532014SEz">Иоган Бах — Токката и фуга ре-минор</a>
</li>
<li class="even">
<a href="http://prostopleer.com/tracks/264667GXiD">Антонио Вивальди — Времена года. Лето.
Шторм</a>
</li>
<li class="odd">
<a href="http://prostopleer.com/tracks/613982Fj9E">Джузеппе Верди — Триумфальный марш
(Аида)</a>
</li>
</ul>
Циклы и сортировка в XSLT
• Для циклов в XSLT есть элемент xsl:for-each, но аналогичные
действия можно выполнить с помощью обычного элемента
xsl:apply-templates.
• Например: требуется вывести список произведений,
отсортированный по длительности.
<ul>
<li>Рихард Вагнер — Полёт валькирии — 280</li>
<li>Антонио Вивальди — Времена года. Лето. Шторм — 203</li>
<li>Иоган Бах — Токката и фуга ре-минор — 187</li>
<li>Эдвард Григ — В пещере горного короля — 163</li>
<li>Джузеппе Верди — Триумфальный марш (Аида) — 103</li>
</ul>
Сортировка с использованием элемента
xsl:for-each
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY mdash "—“>]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="PlayList">
<ul>
<xsl:for-each select="Track">
<xsl:sort select="@Length" data-type="number" order="descending"/>
<li>
<xsl:value-of select="concat(Artist, ' — ', Title, ' — ', @Length)"/>
</li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
Сортировка с использованием
элемента xsl:apply-templates
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY mdash "—“> ]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="PlayList">
<ul>
<xsl:apply-templates select="Track">
<xsl:sort select="@Length" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:template>
<xsl:template match="Track">
<li>
<xsl:value-of select="concat(Artist, ' — ', Title, ' — ', @Length)"/>
</li>
</xsl:template>
</xsl:stylesheet>
• Как видно из кода, первый вариант короче и
проще, но он нарушил принцип разделения
ответственности для шаблонов.
• В этом варианте шаблон match="PlayList" стал
содержать логику отображения элемента
Track.
• Казалось бы, ничего страшного, но
представим задачу, когда в списке
встречаются композиции с ID и без ID.
• Для композиции с ID нужно показать ссылку, а
для остальных вывести только текст.
Вариант с использованием xsl:for-each
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [<!ENTITY mdash "—“>]>
<xsl:stylesheet version="1.0“ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="PlayList"> <ul>
<xsl:for-each select="Track">
<xsl:sort select="@Length" data-type="number" order="descending"/><li>
<xsl:choose>
<xsl:when test="not(@Id)“>
<xsl:apply-templates select="." mode="TrackName" />
</xsl:when>
<xsl:otherwise>
<a href="http://prostopleer.com/tracks/{@Id}">
<xsl:apply-templates select="." mode="TrackName" /> </a>
</xsl:otherwise>
</xsl:choose></li>
</xsl:for-each> </ul>
</xsl:template>
<xsl:template match="Track" mode="TrackName">
<xsl:value-of select="concat(Artist, ' — ', Title, ' — ', @Length)"/>
</xsl:template>
</xsl:stylesheet>
Результат
<?xml version="1.0" encoding="utf-8"?>
<PlayList>
<Track Id="1170056tuNb" Length="280">
<Artist>Рихард Вагнер</Artist>
<Title>Полёт валькирии</Title>
</Track>
<Track Length="163">
<Artist>Эдвард Григ</Artist>
<Title>В пещере горного короля</Title>
</Track>
<Track Id="35532014SEz" Length="187">
<Artist>Иоган Бах</Artist>
<Title>Токката и фуга ре-минор</Title>
</Track>
<Track Id="264667GXiD" Length="203">
<Artist>Антонио Вивальди</Artist>
<Title>Времена года. Лето. Шторм</Title>
</Track>
<Track Id="613982Fj9E" Length="103">
<Artist>Джузеппе Верди</Artist>
<Title>Триумфальный марш (Аида)</Title>
</Track>
</PlayList>
<ul>
<li>
<a href="http://prostopleer.com/tracks/1170056tuNb">Рихард Вагнер — Полёт
валькирии — 280</a>
</li>
<li>
<a href="http://prostopleer.com/tracks/264667GXiD">Антонио Вивальди — Времена
года. Лето. Шторм — 203</a>
</li>
<li>
<a href="http://prostopleer.com/tracks/35532014SEz">Иоган Бах — Токката и фуга реминор — 187</a>
</li>
<li>Эдвард Григ — В пещере горного короля — 163</li>
<li>
<a href="http://prostopleer.com/tracks/613982Fj9E">Джузеппе Верди —
Триумфальный марш (Аида) — 103</a>
</li>
</ul>
Вариант с использованием xsl:applytemplates
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY mdash "—“> ]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="PlayList">
<ul> <xsl:apply-templates select="Track">
<xsl:sort select="@Length" data-type="number" order="descending"/>
</xsl:apply-templates> </ul>
</xsl:template>
<xsl:template match="Track">
<li> <a href="http://prostopleer.com/tracks/{@Id}">
<xsl:apply-templates select="." mode="TrackName" />
</a> </li>
</xsl:template>
<xsl:template match="Track[not(@Id)]">
<li> <xsl:apply-templates select="." mode="TrackName" /> </li>
</xsl:template>
<xsl:template mode="TrackName" match="Track">
<xsl:value-of select="concat(Artist, ' — ', Title, ' — ', @Length)"/>
</xsl:template>
</xsl:stylesheet>
• При использовании элемента xsl:for-each потребовалось добавить
ветвление.
• При использовании элемента xsl:apply-templates — новый шаблон.
• Если бы шаблон match="PlayList" уже содержал ветвления и логику,
то понадобилось бы некоторое время, чтобы разобраться, куда
именно нам нужно вставить ветку.
• Вариант с xsl:apply-templates лишён этого недостатка, поскольку мы
лишь декларируем новый шаблон, а не пытаемся внедриться в
старые.
• Использование xsl:for-each имеет ещё одну большую опасность.
Если анализируется произвольный участок кода внутри шаблона
match="PlayList", то предполагается, что текущий элемент это
PlayList, однако xsl:for-each меняет контекст.
– Например следующий код код:
<xsl:apply-templates select="." mode="TrackName" />
Потребуется внимательно присмотреться к контексту, чтобы понять,
что select="." на самом деле выбирает текущий Track.
• Шаблон mode="TrackName" match="Track" был
добавлен для избежания дублирования кода,
отображающего название.
• Этого не было сделано раньше, так, как не было
необходимости.
– Как только появилось дублирование, то понадобилось
вынести общую логику отображения в новый шаблон.
• Элемент xsl:for-each не плодить сущности. Просто
нужно добавить логику отображения внутрь xsl:foreach и всё хорошо работает.
• Проблемы начинаются в том случае, когда тело цикла
разрастается, и приходится проводить изменения
xsl:for-each, которые намного сложнее, чем вынесение
повторяющегося кода.
• И наконец, рассмотрим XSLT, которая позволит прослушать все композиции
из демонстрационной XML.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="Track">
<div>
<object width="411" height="28">
<param name="movie" value =
"http://embed.prostopleer.com/track?id={@Id}">
</param>
<embed src="http://embed.prostopleer.com/track?id={@Id}"
type = "application/x-shockwave-flash" width="411" height="28">
</embed>
</object>
</div>
</xsl:template>
</xsl:stylesheet>
Результат
<div><object width="411" height="28"><param name="movie"
value="http://embed.prostopleer.com/track?id=1170056tuNb" /><embed
src="http://embed.prostopleer.com/track?id=1170056tuNb" type="application/xshockwave-flash" width="411" height="28" /></object></div>
<div><object width="411" height="28"><param name="movie"
value="http://embed.prostopleer.com/track?id=938304vu1E" /><embed
src="http://embed.prostopleer.com/track?id=938304vu1E" type="application/xshockwave-flash" width="411" height="28" /></object></div>
<div><object width="411" height="28"><param name="movie"
value="http://embed.prostopleer.com/track?id=35532014SEz" /><embed
src="http://embed.prostopleer.com/track?id=35532014SEz" type="application/xshockwave-flash" width="411" height="28" /></object></div>
<div><object width="411" height="28"><param name="movie"
value="http://embed.prostopleer.com/track?id=264667GXiD" /><embed
src="http://embed.prostopleer.com/track?id=264667GXiD" type="application/xshockwave-flash" width="411" height="28" /></object></div>
<div><object width="411" height="28"><param name="movie"
value="http://embed.prostopleer.com/track?id=613982Fj9E" /><embed
src="http://embed.prostopleer.com/track?id=613982Fj9E" type="application/xshockwave-flash" width="411" height="28" /></object></div>
Результат рендеринга
Download