Содержание


Подготовка к переходу с XSLT 1.0 на 2.0, Часть 1

Улучшения в XSLT

Основные функциональные возможности XSLT 2.0 и исправления недостатков версии 1.0

Comments

Серия контента:

Этот контент является частью # из серии # статей: Подготовка к переходу с XSLT 1.0 на 2.0, Часть 1

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Подготовка к переходу с XSLT 1.0 на 2.0, Часть 1

Следите за выходом новых статей этой серии.

О серии

XSLT поддерживается и используется для гораздо более широкого круга проблем, чем этого ожидала команда разработчиков XSL (Working Group - WG). Если вы пишете листы стилей XSLT, вы, наверняка, знаете определенные блоки кодов для получения результатов, выходящих за рамки явного значения кода. Что приходит вам на ум, когда вы видите generate-id()? node-set()? substring-before()? disable-output-escaping? XSLT 2.0 в скором времени будет образцом качества, и вы сможете использовать его для создания более читабельного кода. Новые функции в XSLT позволят вам использовать выражения более близкие к значениям, которые вы хотите в них вложить.

Последняя спецификация XSLT 2.0, выпущенная W3C, является языком для преобразования XML-документов. Он включает множество новых функциональных возможностей, некоторые из которых специально созданы для исправления недостатков в XSLT 1.0. В данном сборнике статей, вы получите высококвалифицированный и всесторонний обзор языка XSLT 2.0 с точки зрения пользователя XSLT 1.0, который хочет исправить старые проблемы, научиться новым методикам и узнать, что еще нового можно найти. Примеры из простых приложений, а также практические предложения помогут вам лучше разобраться в материале. Чтобы вы начали использовать XSLT 2.0, вам предоставляются методики миграции.

XSLT расширяется и улучшается

XSLT поддерживается и используется для гораздо более широкого круга проблем, чем этого ожидала команда разработчиков XSL (Working Group - WG). Если вы пишете листы стилей XSLT, вы, наверняка, знаете определенные блоки кодов для получения результатов, выходящих за рамки явного значения кода. Что приходит вам на ум, когда вы видите generate-id()? node-set()? substring-before()? disable-output-escaping? XSLT 2.0 в скором времени будет образцом качества, и вы сможете использовать его для создания более читабельного кода. Новые функции в XSLT позволят вам использовать выражения более близкие к значениям, которые вы хотите в них вложить.

XSLT 1.0, главным образом, был определен в двух документах W3C: XSLT и XPath. Версия 2.0 была создана только для регулировки с XQuery, а теперь семья XSLT включает шесть спецификаций внутри ядра: XSLT, XPath, Функции и Операции (Functions and Operators - F&O), Модель Данных (Data Model - XDM), Формальные семантики (Formal Semantics) и Сериализация (Serialization). (См. Похожие темы для ссылок на документы W3C.) Как и версия 1.0, он построен на нескольких других основах спецификаций (XML, области имен (namespaces) и др.), и создает XML-схему в своем окружении. Этому предшествовал документ технических требований, в котором были установлены ориентиры для новых функциональных возможностей и была обоснована работа над спецификацией 2.0.

Данная статья основана на Candidate Recommendation от июня 2006 года, и в ней описаны улучшения в XSLT 2.0, которые должны убедить вас перейти на новую версию. Даже если W3C захочет изменить некоторые нюансы между Candidate Recommendation и последними Рекомендациями, данная статья все равно останется актуальной.

Группировка

Одной из ранних специальных методик, появившихся в XSLT 1.0, было средство для обработки набора элементов, каждый из которых имел атрибут (или наследника), который определял группу, к которой он принадлежал. Группировка элементов не была описана в спецификации 1.0. Программисты листов стилей в ранней версии 1.0 усовершенствовали эту методику, которую нельзя было четко прочесть в коде и которая часто распознавалась только когда цикл for-each имел очередной паттерн <xsl:if test="generate-id(.)=generate-id(set[@grp=$thisvalue][1])">... once-per-group code ...</xsl:if>, где сравнение значений generate-id() является попыткой распознавания того, является ли настоящий узел первым найденным узлом со значением $thisvalue в атрибуте @grp. Данный метод распознавания первого узла может быть совершенно бесполезным, когда вы должны очистить огромный набор (совокупность) каждого из значений ($thisvalue в данном примере), использующихся в качестве ключа.

Группировка в версии 2.0 выполняется новым оператором xsl:for-each-group и двумя вспомогательными функциями: current-group() и current-grouping-key(). Они работают над набором сходных узлов, так же как функция xsl:for-each и current(). Как for-each, for-each-group могут принимать xsl:sort, как дочерний элемент для управления порядком, в котором обрабатываются группы. Если вам удобно использовать xsl:for-each, то вам также будет намного проще и естественнее использовать xsl:for-each-group. Группировка должна улучшить производительность, потому что процессор сможет оптимизировать средства определения связок групп. Можно написать много всего о группировке и о методиках для достижения желаемых результатов, но в данной статье мы представляем лишь несколько простых методов, таких как группировка совокупности элементов, который является распространенным методом в большинстве случаев.

Вы можете разделить данную совокупность на группы четырьмя способами. Три способа заключаются в порядке появления сгруппированных узлов, когда как четвертый - группирует в соответствие с ключевым значением, что знакомо пользователям SQL. Каждый раз, когда вы используете оператор xsl:for-each-group, вы будете определять один из четырех методов:

В методе group-by вы определяете выражение, которое говорит, где получить ключевое значение для каждого члена совокупности. (Это так же, как @use в xsl:key или @select в xsl:sort.) В типичной ситуации, совокупность многих элементов организуется в группы на основания атрибута, который имеет каждый из элементов. Представьте, что у вас есть данные о финансах большого количества офисов филиалов вашей организации, и каждому филиалу соответствует географический регион. XML-данные могут выглядеть следующим образом:

Листинг 1. Данные, которые подлежат группировке.
<branch id="B723" region="Northeast">...data...</branch>
<branch id="B201" region="North">...data...</branch>
<branch id="B558" region="Northeast">...data...</branch>
<branch id="B064" region="West">...data...</branch>
etc.

Для сбора элементов <branch> по регионам, используйте следующий оператор: <xsl:for-each-group select="branch" group-by="@region">... once-per-region code...</xsl:for-each-group>. Внутри тела цикла у вас current-grouping-key(), чтобы знать какое значение региона (@region) является настоящим, и вы можете использовать <xsl:for-each select="current-group()">...once-per-branch code...</xsl:for-each>, чтобы производить итерацию над данной группой, все филиалы в одном регионе. Знайте, что получить список всех значений групповых ключей (имена регионов в данном примере) очень легко без настройки группировки. Просто используйте новую функцию distinct-values(). Для более подробной информации о функции отдельных значений читайте статью "XML для Данных: Что нового в XPath 2.0?" (см. Похожие темы).

Метод group-by не относится к последовательности узлов. Он позволяет использовать множественные ключи (multiple keys), с помощью которых вы можете дублировать узлы в группе. Правило состоит в том, что каждая из данных групп должна иметь только одно событие для каждого узла. Однако один и тот же узел может быть членом нескольких групп.

Метод group-ending-with создан для того, чтобы преобразовывать совокупность элементов, размещенных в определенном порядке и имеющих флаг-узел более или менее часто для обозначения конца группы. Во многих приложениях в списке встречаются флаги <subtotal>, <total> и <grand-total>. В xsl:for-each-group, @group-ending-with используется часть синтаксиса XSLT, чтобы установить, как определяется флаг-узел. Тоже самое в XSLT 1.0 будет довольно трудной комбинацией position(), пошаговой обработки, оси координат preceding-sibling и, возможно, двухфазовой обработки.

Метод group-starting-with очень похож на group-ending-with, но флаг-узел находится вначале группы. Вы можете использовать данную форму группировки, когда вы обрабатываете XML-версии пьес Шекспира (это было возможно в Сети (Web) многие годы.) Существуют элементы <speech> и <line>, которые выполняются последовательно. Герой, который ведет речь, определяется в отдельный элемент и получает в начало строки черту, а элементы <StageDir> выполняются, когда это необходимо в сцене, на своем собственном месте в последовательности. В некоторых случаях, вы можете захотеть, чтобы элементы одного уровня разместились в виде вложенности, или наоборот, и как раз группировка может решить эти проблемы. Один способ - это отмечать элементы флагом <StageDir>, чтобы группировать все другие встречающиеся элементы, во время того, как постановка имеет место.

Четвертый метод группировки - это group-adjacent. Как и group-by он использует значения узлов паттернов (patterns) для разграничения групп, но он "знает" о последовательности элементов в совокупности. По существу, он сообщает управляющей программе определенный узел (атрибут или узел-потомок), который будет иметь каждый из элементов и сформирует группу, когда значение этого узла изменится по сравнению с последним узлом. Это может быть использовано для формирования групп фиксированных размеров с помощью следующей в будущем популярной методики:

<xsl:for-each-group select="item" group-adjacent="ceiling(position() div 4)">

Это позволяет располагать <item>-элементы в группы по четыре.

В частности, XSLT 2.0 предоставляет некоторые операторы, которые определяют порядок узлов или равенство узлов более удобно. Использование generate-id(), расположенное в начале данного раздела, на самом деле показывает различие между двумя путями к одному и тому же узлу. В версии 2.0, оператор для данного случая называется is. Аналогично, оператор >> и << позволяют проверять, где именно находится узел, позднее или ранее другого узла в порядке документов. Это может упростить прогнозирование еще не определенных xsl:for-each-group.

Существует много других полезных советов и методик группировки. Теперь, данный раздел даст вам общее представление о потенциале языка.

Скрытые узлы документа

Одним из источников разочарования в языке XSLT 1.0 является ограничение Фрагментов дерева результатов (Result Tree Fragments - RTF). Когда переменная содержала дерево, вы могли скопировать его в набор результатов или обходиться с ним, как со строковой переменной, но вы не могли управлять ею, как деревом с помощью простых инструментов XSLT/XPath. Возможно, как и многие другие люди, вы читаете и перечитываете параграф в части 11.1, в которой говорилось, что "Фрагмент дерева результатов такой же, как и набор узлов (node-set), который содержит просто один единственный корневой узел. Однако операторы, запрещенные во фрагменте дерева результатов являются поднабором тех операторов, которые были запрещены в самом наборе узлов. Операция запрещена во фрагменте дерева результатов, только если этот оператор будет запрещен в строке...". По прочтении этого, вы думаете, почему дерева было недостаточно, чтобы управлять XPath-выражениями.

Большая часть поставщиков процессора XSLT добавили функцию расширения, обычно называемую node-set(), которая позволяет управлять и фильтровать дерево RTF. Вспомните, что в версии 1.0 xsl:variable могла принять @select, и её значение было бы либо набором узлов (node-set), либо единичным неделимым значением, либо она могла создать RTF с помощью конструктора контента, как дочернего элемента. Эта последняя форма создает Скрытый узел документа - Implicit Document Node (IDN) в версии 2.0, который является одной формой новой структуры временного дерева - temporary tree. Если в версии 1.0 лист стилей создавал RTF-переменные, то те же самые листы стилей в версии 2.0 будут создавать IDN-ы. Вам все еще нужно конструктор контента (content constructor, переименованный в sequence constructor (конструктор последовательности) в версии 2.0) в xsl:variable, если вам требуются программируемые операторы, такие как xsl:choose или xsl:call-template, из-за которых вам приходится создавать RTF/IDN-дерево. Вы можете использовать xsl:copy-of для копирования целого IDN-дерева в продукте, как и раньше, но вы также можете использовать переменную в выражении пути без конвертации набора узлов (node-set).

IDN, или его поддерево, может быть в выбранном выражении xsl:apply-templates, позволяющем обработку дерева так же, как и во входном XML-документе. Если это производится в более широком масштабе, то будет выполняться в форме двухфазового преобразования без разделения запусков обработки для фазы 1 и фазы 2. Две или более фазы полезно использовать, когда вам нужно создать XML-документ с расширенными перекрестными ссылками. Неиспользование функции node-set устраняет возможность ошибок, где две копии дерева, одна - RTF, а другая - набор узлов, путаются. Для больших промежуточных деревьев это также позволяет сохранить память. Если вы устанавливаете атрибуты ID-типа или подходящие значения ключей, когда вы уже сконструировали IDN, вы можете использовать функции id() и key() для индексированного доступа, а в тех же функциях версии 2.0 даже есть удобный дополнительный аргумент для ограничения индексированного поиска для установленного дерева.

За ссылкой на переменную IDN может следовать шаг пути (например, /child) и фильтр (например, [@foo="yes"]), который позволяет вам выбрать набор узлов для цикла xsl:for-each, или адресовать значения так же, как вы будете их использовать в других выбранных выражениях. Такие же функциональные возможности применимы для тестового выражения в xsl:if и xsl:when.

Отметим, что xsl:variable имеет опции для управления ввода данных с клавиатуры. Помимо всего прочего, это позволяет конструктору последовательности создавать в xsl:variable контент вместо того, чтобы @select создавал полнофункциональное IDN и единичные узлы параметров, комментарии и работающие операторы. Он может создать единичные элементы, имеющие контент, которые, в отличие от IDN-ов, не имеют узел документа вверху дерева. Он также может создавать последовательности элементарных значений, которые могут перепутаться с наборами ссылок. Следующий пример показывает, как использовать @as для блокировки создания узла документа и других элементов, вместо чего создаётся последовательность.

Листинг 2. Переменная, обусловленная @as быть последовательностью значений xs:double без узлов документов или элементов
<xsl:variable name="values" as="xs:double*">
    <xsl:sequence select="(1,3,5)"/>
    <xsl:if test="@m='large'">
        <xsl:sequence select="(2,4,10)"/>
    </xsl:if>
</xsl:variable>

Переменная $values не является ни набором узлов, ни IDN-ом. Это просто последовательность элементарных двухразрядных чисел. (Примечание: В тексте данной статьи префикс "xs" в области имен относится к XML-схеме области имен для типов данных).

Функции, определяемые пользователем

Новый оператор xsl:function, представленный в XSLT 2.0, позволяет программистам листов стилей создавать свои собственные функции в листе стилей с помощью чистого синтаксиса и семантики языка XSLT. Это, конечно, полезно, только если вы не можете найти необходимую функцию среди 128 функций и 68 операторов, предоставляемых в спецификациях F&O и XSLT 2.0 (см. Похожие темы). Смотрите следующий раздел о преобразовании символов - (character maps) для примера xsl:function.

Без возможности легко создавать определяемые пользователем функции, программисты листов стилей XSLT 1.0 часто пытаются решить задачу с помощью вызова именованного шаблона, определяя свое собственное расширение функции в другом языке, или надеяться, что процессор XSLT 1.0 поддерживает псевдо-стандартное расширении библиотек, как EXSLT (см. Похожие темы для ссылки на сайт EXSLT). Некоторые функции в библиотеке F&O совмещаются с функциями, определяемыми в EXSLT, когда как библиотека предоставляет не поддерживаемые другими функции. EXSLT также определяет оператор расширения func:function с идентичным синтаксисом xsl:function. (Если вы уже используете func:function, то вам следует переключиться на адаптированную функцию в XSLT 2.0.) Недостаток использования расширения из EXSLT состоит в том, что некоторые продукты предоставляют только выборочную поддержку, и нет гарантии, что эти продукты будут продолжать поддерживать эти расширения в будущем.

Написание своего собственного расширения на другом языке часто бывает сложным и занимает много времени. Ваша реализация функции расширения может быть ограничена работой только на одном процессоре и всегда будет ограничивается механизмами и структурами данных, находящихся под действием данного процессора. В XSLT 1.0, написание именованного шаблона для достижения желаемой функциональности является надежной альтернативой без каких-либо специфических ограничений данного продукта. Однако чтобы вызвать именованный шаблон требуется больше XSLT-операторов, когда как вызов функции является более компактным и может быть встроен в XPath-выражение. Другое ограничение заключается в лимитировании, включенном в фрагмент результирующего дерева при вызове именованного шаблона прямо из xsl:variable. (См. предыдущий раздел, Скрытые узлы документа). Если у вас есть лист стилей версии 1.0, но он больше не запускается на процессоре версии 2.0, потому что требует реализации функции расширения, сперва посмотрите в спецификации F&O и XSLT 2.0, чтобы понять, сделано ли все правильно. Если же вы не нашли то, что вам нужно, научитесь писать свои собственные функции в листе стилей. Для некоторых, но не всех, EXSLT-функций, EXSLT предоставляет почти такой же именованный шаблон, который вы можете использовать как гида, чтобы он помогал вам писать функцию в синтаксисе языка XSLT. (Помните, что под EXSLT имеется в виду XSLT 1.0, поэтому использование нового синтаксиса версии 2.0 упростит в дальнейшем вашу функцию.) Если вы обнаружите, что функция расширения может лучше работать, чем функция листа стилей, то вы можете определить эту функцию листа стилей, как вторую в порядке выбора, если функция расширения недоступна.

Данные даты/времени

Семейство стандартов XSLT 2.0 предлагает поддержку для данных даты/времени, включая набор функций и операторов, которые могут производить времязависимые вычисления. Теперь вам не придется управлять датами и временем, как строковыми данными, и разделять строки, чтобы каждая из них получила индивидуальный номер или название месяца. Типы дат берутся из спецификации XML-схемы, части 2 (XML Schema Part 2 - см. Похожие темы), которая дает вам как точки во времени, так и отрезки времени. Значения этих типов могут приходить из входного документа преобразования, если информация о схеме активна (см. Schema awareness), или как возвращаемое значение функции. Некоторые операторы в XSLT 2.0 имеют такие механизмы, как новый @as-атрибут (см. пример @as в разделе о Скрытых узлах документа) для утверждения типа данных.

Когда вы хотите создать элементарное значение одного из времязависимых типов данных, используйте функцию создания типов (type-constructor) и представьте его в виде строки, как аргумент. Например, xs:time('12:34:56') берет строку, представляющую показанное время, и возвращает значение, которое имеет метку типа для обозначения настоящего значения времени дня. Функции конструктора в данной категории такие же, как и имена встроенных типов в XML-схеме: xs:date, xs:time, xs:dateTime, xs:duration, xs:gYear, xs:gMonth, xs:gDay, xs:gYearMonth, xs:gMonthDay, с добавлением xs:yearMonthDuration и xs:dayTimeDuration.

Как только у вас появилось значение 12:34:56 в качестве настоящего времени, вы можете добавить к нему значение длительности, чтобы получить результирующее время. Многие из предоставленных новых функций и операторов позволяют выполнять все соответствующие арифметические операции между точками во времени и отрезками времени. Вы можете перемножать отрезки времени со скалярным числом, чтобы получить более длительный или короткий отрезок времени, а также можете делить на скалярное число или на другой отрезок времени. Если один dateTime вычесть из другого, то получим отрезок, как разницу между исходными отрезками времени. Вы также можете сравнивать два значения одного типа. Например, dayTimeDuration (отрезок времени) в PT90S (90 секунд) будет равен нормальному значению в виде PT1M30S (1 минута и 30 секунд). Для некоторых типов также определяется неравенство взаимосвязей. Больше-чем для отрезка означает большую длину. Больше-чем для даты означает более позднюю дату.

Кроме того, набор функций component extraction (извлечения компонентов) позволяет одну операцию, с читабельным именем, для получения одного поля из даты, времени и отрезка времени. Например, сравнение:

minutes-from-dateTime(xs:dateTime('2005-07-01T14:06:32'))

возвращает целочисленное значение 6 по старому пути, где петля функций substring-before() и substring-after() и, возможно number(), будут использоваться для освобождения от минуса. По новому пути, имя функции объясняет то, что подразумеваете.

Если у вас есть лист стилей 1.0, который четко управляет времязависимыми значениями, у вас, наверняка, есть несколько операций, которые действуют при вызове специализированных именованных шаблонов. Если возвращаемое значение шаблона нуждается в загрузке в XPath-выражение, то это большой недостаток, так как вам необходимо циклически переходить к вызову xsl:variable в шаблоне, и данная переменная является RTF (см. Скрытые узлы документа). В общем, xsl:function (см. Функции, определяемые пользователем) является решением версии 2.0, но с времязависимыми значениями вы можете обнаружить, что 24 новых функции и 44 новых оператора, плюс функции конструктора, удовлетворяют всем вашим потребностям. Для сравнения отметим, что пакет EXSLT (см. Похожие темы), который предоставляет некоторые из процессоров из XSLT 1.0, имеет только 28 времязависимых функции, включая те, которые производят форматирование.

По просьбе многих пользователей новый набор функций также заключает в себе функции для возврата на настоящее время, дату или dateTime, таким образом лист стилей может пометить время и дату продукта.

Все вышесказанное велось к тому, что все значения должны быть соответствующих типов. Функции используются и в XSLT, и в XQuery. Поскольку цель XSLT по-прежнему предоставить информацию в удобном виде, XSLT добавляет функции форматирования, которые берут дату, время или значение dateTime, введенное с клавиатуры, и выдают строку в нужном вам виде, например с написанием месяцев словами, а не цифрами. Спецификация XSLT 2.0 позволяет каждой реализации выбирать языки, числительные и другими подобные аспекты. Если для вас это важно, можете начать придумывать список ваших потребностей, а затем сравнить его с функциональными возможностями в процессорах версии 2.0, которые будут доступны после завершения спецификации.

Информация о схеме

Schema-awareness (информация о схеме) является дополнительной функциональной возможностью в XSLT 2.0. Если вы нашли поддерживающий ее процессор, то вам она может пригодиться. Функция schema-aware главным образом используется для проверки ошибок. Она согласовывает вход и выход вашей XML-схемы, а также позволяет вам ссылаться на исходные узлы в листе стилей, основанных на их типе схемы. Эта функциональная возможность спроектирована для программистов листов стилей версии 1.0 с целью помочь обнаружить ошибки в преобразовании перед началом отладки программы. Вам доступны следующие механизмы, чтобы вы смогли использовать все преимущества данной возможности:

Таблица 1. Атрибуты операторов и XPath-компоненты, на которых действует функция schema-aware
Синтаксическая единицаИспользование
@as-атрибутИспользуйте данный атрибут в xsl:variable, xsl:param, xsl:function или в xsl:template, чтобы добавить утверждение о том, что сформированное дерево результатов или последовательность является событием необходимого типа схемы.
instance ofИспользуйте данный оператор в последовательности или в единичном элементарном значении или узле, чтобы подтвердить, что данное событие нужного типа схемы.
Атрибуты @validation и @type [если в Буквенном результирующем элементе - Literal Result Element (LRE), то @xsl:validation и @xsl:type]Используйте эти атрибуты для подтверждения, что узлы основаны на определении типа схемы или не основаны на элементе или определении атрибута верхнего уровня.
cast as и функции конструктораПриводите элементарный тип в типе схемы.
castable asОператор, который проверяет, что приведение успешно завершено.
node-test element(*,type) и attribute(*,type)Возвращают только узлы элемента или атрибута с меткой нужного типа схемы.
тест-узел schema-element(elemDecl) и schema-attribute(attribDecl)Возвращает узлы элемента или атрибута, которые соответствуют элементу схемы или определению атрибута.

Расширение возможностей продукта (сериализации)

xsl:result-document

Один лист стилей версии 2.0 может производить множественные деревья результатов, которые можно сериализовать во многих направлениях. Статья сайта developerWorks, "Создание множественных файлов в XSLT 2.0" (см. Похожие темы), может познакомить вас с общей идеей того, как использовать новый оператор xsl:result-document.

Преобразование символов

Программисты листов стилей версии 1.0 часто неверно используют атрибут disable-output-escaping (d-o-e) из-за неполного понимания различий между разметкой и текстом. Это разрушает всю архитектуру, так как ей требуется сериализатор (serializer) для того, чтобы знать каждое дополнительное поле для каждого узла помимо информации, показываемой моделью данных XPath и параметрами сериализации. Таким образом, различие между преобразованием и сериализацией становится непонятным, из-за чего группа разработчиков XSL WG не хотела создавать данный атрибут. Вместо него, они создали преобразования символов (character maps), которые являются отображениями символов во время сериализации, где все появления специфических символов преобразуются, даже если это повлияет на не очень хорошо сформированный XML, в другие символы, запрашиваемые параметром сериализации use-character-maps. Нижеприведенные листы стилей проиллюстрируют вам то, как использовать преобразования символов с помощью замены функции @disable-output-escaping на my:d-o-e. Вы также можете использовать эту функцию в качестве примера для выполнения преобразований символов только на выборочных узлах в результирующем дереве. Данный пример полагается на преобразования нечасто используемых символов, таких как левая кавычка («, часто кодирующаяся, как «) и предполагает, что такие символы не появляются в результирующей последовательности. Используйте даже более редкие символы, если вы хотите убедиться в том, что преобразуются именно нужные символы.

Листинг 3. Лучший способ получения специальных XML-символов в вашем выводе
<xsl:output use-character-maps="my:charMap" />

<xsl:character-map name="my:charMap">
   <xsl:output-character character="«" string="<" />
   <xsl:output-character character="»" string=">" />
   <xsl:output-character character="§" string="&" />
   <xsl:output-character character="¤" string="'" />
   <xsl:output-character character="¦" string=""" />
</xsl:character-map>
 
<xsl:function name="my:d-o-e" as="xs:string">
   <xsl:param name="str" as="xs:string" />
   <xsl:sequence select="translate($str, '<>&'"',
           '«»§¤¦')" />
</xsl:function>
 
<xsl:template match="/doc">
	Replace
    <xsl:value-of select="." />
	With
    <xsl:value-of select="my:d-o-e (.)"/>
</xsl:template>

Используйте следующее преобразование символов, чтобы избежать пропуска всех знаков амперсанд (&), меньше чем (<), больше чем (>), апострофов (') и двойных кавычек ("). Хотя кажется, что оно просто устанавливает соответствие каждого символа самому себе, на самом деле оно предотвращает фазу пропуска (в соответствии с правилами XML или HTML) в сериализации, потому что эта фаза не может применяться по отношению к уже преобразованным символам.

Листинг 4. Другой способ сохранить особые XML-символы в unscaped-форме
    <xsl:character-map name="my:charMap">
	<xsl:output-character character="<" string="<" />
	<xsl:output-character character=">" string=">" />
	<xsl:output-character character="&" string="&" />
	<xsl:output-character character="'" string="'" />
	<xsl:output-character character=""" string=""" />
</xsl:character-map>

Нормализация юникода

Нормализация юникода была пожеланием пользователей XSLT, и в ответ на это в XSLT 2.0 представлены две опции нормализации. Для осуществления выборочной нормализации, используйте функцию F&O normalize-unicode(). В другом случае, параметр сериализации normalization-form влияет на действительное конечное результирующее дерево. Если используется преобразование символов, то сперва определите, хотите ли вы применить нормализацию к уже преобразованным символам, или хотите применить его до того, как символ уже был преобразован. Используйте normalize-unicode() для первого случая, и применяйте параметр normalization-form для последнего.

Три функции для URI-скрытия

Спецификация F&O определяет три функции: encode-for-uri(), iri-to-uri() и escape-html-uri() - для обеспечения кодирования со знаком процента в строке, что влияет на URI или часть URI. В URI вы можете исключать знаки, которые будут семантически влиять на перестановку настоящего элемента со знаком процента, за которым следует две шестнадцатеричных цифры, например %20 для пробела. EXSLT определяет str:encode-uri(), которая также выполняет percent-encoding, но для пяти меньших зарезервированных знаков, по сравнению с encode-for-uri(). Независимо от ваших потребностей, этих трех функций в F&O должно хватать. Для управления атрибутами URI-скрытия (URI-escaping) в документе HTML, используйте параметр сериализации escape-uri-attributes. Этот параметр был недоступен в XSLT 1.0, и таким образом, URI-скрытие выполнялось всегда.

Далее приведен список печатаемых символов из набора программных знаков US-ASCII, особенно обратите внимание на восемь символов в области от 32 до 126 (десятичных), где функции будут получать знак процента:

  • fn:iri-to-uri() кодирует " < > \ ^ ` { | } пробел
  • EXSLT's str:encode-uri() кодирует " # $ % & + , / : ; < = > ? @ [ \ ] ^ ` { | } пробел
  • fn:encode-for-uri() кодирует ! " # $ % & ' ( ) * + , / : ; < = > ? @ [ \ ] ^ ` { | } пробел
  • fn:escape-html-uri() не кодирует ни один из этих символов

Создание узлов области имен

Новый оператор xsl:namespace является очевидным и простым решением для создания узла области имен (namespace node), этого механизма не хватало в XSLT 1.0. В XSLT 1.0 наивные пользователи, возможно, пытались создать тоже самое, используя вызов xsl:attribute с помощью "xmlns:prefix" в качестве имени. Узлы области имен на самом деле можно создать только неявно, либо через копирование элементов или узлов области имен из источника, копированием областей имен из листа стилей, если LRE уже установлен, либо через прямое создание элемента или атрибута, чье имя находится в области имен. Другими словами, в версии 1.0 вам приходилось либо иметь уже готовый узел области имен, либо создавать другой ненужный узел, который будет просто побочным продуктом.

XML 1.1 (необъявление префикса и нормализация юникода)

Вы можете поддержать XML 1.1 с помощью процессора матрицы отображения XSLT 1.0, как последнего издания исправлений (см. Похожие темы). XML 1.1 является факультативным как для XSLT версии 1.0, так и версии 2.0. Однако если он поддерживается, вам нужно знать, что атрибуты normalization-form и undeclare-prefixes доступны только в XSLT 2.0, и недоступны в XSLT 1.0.

Метод вывода XHTML

В XSLT 2.0 был добавлен дополнительный метод вывода, XHTML, который должен поддерживаться всеми соответствующими процессорами с сериализацией. Сериализация XHTML возможна и в XSLT 1.0 в XML-формате с установкой атрибутов doctype-system и doctype-public в xsl:output. Это даст уверенность в том, что объявление <!DOCTYPE> является сериализованным. Однако это может быть недостаточным для некоторых агентов, созданных для обработки HTML по причине неуловимых различий, перечисленных в Приложении "C" XHTML-спецификации (см. Похожие темы).

Атрибут разделения для xsl:value-of

Возможно, что наиболее часто используемым оператором в XSLT является xsl:value-of, который может быть применен для того, чтобы значение вывода делать строковым типом. Многие программисты листов стилей используют ее в качестве инструмента отладки, но им приходится также использовать count(expr), когда они не уверены в том, сколько узлов имеет expr. В версии 2.0 xsl:value-of не только выдаёт первый член набора, но и сразу выполняет итерацию всей последовательности и даже может управлять разделительной строкой. (Если вы зависели от xsl:value-of, который просто берет первый элемент, вы можете установить version="1.0" в операторе, если в вашем процессоре версии 2.0 поддерживается функциональная возможность обратной совместимости.) Простой оператор <xsl:value-of select="/doc/*" separator="', '"/> замещает весь код, приведенный ниже:

Листинг 5. Типичный код версии 1.0 для форматирования списка значений, который может быть заменен одним оператором в версии 2.0
  <xsl:template match="/doc">
   	 <xsl:call-template name="valueOfWithSeparator">
   	    <xsl:with-param name="nodes" select="*" />
   	    <xsl:with-param name="separator" select="', '" />
   	 </xsl:call-template>
  </xsl:template>

  <xsl:template name="valueOfWithSeparator">
      <xsl:param name="nodes" />
      <xsl:param name="separator" select="' '" />
      <xsl:for-each select="$nodes">
         <xsl:if test="not(position() = 1)">
            <xsl:value-of select="$separator" />
         </xsl:if>
         <xsl:value-of select="." />
      </xsl:for-each>
   </xsl:template>

Метка порядка байтов

Для управления меткой порядка байтов (byte order mark - BOM) в листе стилей вы можете использовать параметр сериализации byte-order-mark. Отметим, что конструкторы могут игнорировать это значение. В XSLT 1.0 выполняемые продукты могут делать BOM для документов UTF-8, а также и для UTF-16 и UTF-32. В XSLT 1.0 либо конструкторам приходится поддерживать атрибут расширения, либо самому пользователю нужно применять внешний (пост-транформация) процесс для того, чтобы убедиться, что BOM добавлен, либо просто забыть про него.

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

В данной статье мы рассмотрели наиболее востребованные основные функциональные возможности XSLT 2.0, оставив XPath и библиотеку функций на потом. Если вы еще не нашли функцию, которая убедила бы вас перейти на новую версию, продолжайте искать.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML
ArticleID=183340
ArticleTitle=Подготовка к переходу с XSLT 1.0 на 2.0, Часть 1: Улучшения в XSLT
publish-date=12122006