3.04. Справочник по XSLT
Разработчику
Аналитику
Тестировщику
Архитектору
Инженеру
Справочник по XSLT
🔹 Часть 1. Структура XSLT-таблицы стилей и глобальные элементы
XSLT-таблица — это XML-документ (обычно с пространством имён http://www.w3.org/1999/XSL/Transform, сокращённо xsl:). Корневой элемент — <xsl:stylesheet> или <xsl:transform> (синонимы).
🔸 1.1 Корневые элементы
| Элемент | Обязательные атрибуты | Необязательные атрибуты | Замечания |
|---|---|---|---|
<xsl:stylesheet> | version | id, extension-element-prefixes, exclude-result-prefixes, xpath-default-namespace, default-collation, default-validation, default-mode, expand-text, use-package, package-version, streamability, default-attribute-version, default-function-namespace, input-type-annotations, output-version, _xml:id и др. | Основной корневой элемент. Поддерживает модульность (XSLT 3.0 — пакеты). |
<xsl:transform> | То же | То же | Семантический синоним <xsl:stylesheet>. |
Атрибуты корневого элемента (обязательные и ключевые необязательные)
| Атрибут | Возможные значения | Применимость | Пояснение |
|---|---|---|---|
version | "1.0", "2.0", "3.0" | Обяз. | Определяет версию XSLT. Должна соответствовать реализации (напр., xsl:stylesheet version="3.0" требует XSLT 3.0-процессора: Saxon-EE/PE/HE, MorganaXSLT и др.). |
id | xs:ID | Необяз. | Идентификатор элемента для внешней ссылки (например, xml:id). |
extension-element-prefixes | список префиксов пространств имён | Необяз. | Префиксы, используемые для элементов-расширений (например, saxon:, exsl:). Процессор не будет пытаться интерпретировать эти элементы как XSLT. |
exclude-result-prefixes | "#all" или список префиксов | Необяз. | Префиксы, которые не должны копироваться в результирующий XML (кроме случаев, когда они используются в результатах). #all исключает все, кроме xml, xsl, xmlns, xs, xsi, err и префиксов, объявленных в use-attribute-sets. |
xpath-default-namespace | IRI | XSLT 2.0+ | Значение по умолчанию для default element/type namespace в XPath-выражениях (аналогично xpath-default-namespace в XQuery). Полезно при работе с XML с пространством имён, но без префиксов. |
default-collation | IRI | XSLT 2.0+ | URI коллации по умолчанию для xsl:sort, compare(), starts-with() и т.д. Стандартные: http://www.w3.org/2005/xpath-functions/collation/codepoint (по кодам Unicode), http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive. |
default-validation | "strip", "preserve", "strict", "lax" | XSLT 2.0+ | Управляет обработкой xsi:schemaLocation и xsi:noNamespaceSchemaLocation входного XML. strip — игнорировать типы; preserve — сохранять типы, не проверяя; strict/lax — проверять против схемы (требуется XSD). |
default-mode | xs:QName | XSLT 3.0+ | Имя режима, используемого по умолчанию, если в xsl:apply-templates не указан mode. Может быть #unnamed, #default, #current, #text-only, #deep-copy. |
expand-text | "yes", "no" | XSLT 3.0+ | Разрешает или запрещает text value templates ({...} внутри текстового содержимого). По умолчанию no. |
use-package | URI пакета | XSLT 3.0+ | Указывает пакеты, из которых импортируются функции, переменные, шаблоны через <xsl:use-package>. |
package-version | версия (строка) | XSLT 3.0+ | Версия текущего пакета. |
streamability | "unclassified", "shallow-sibling", "deep-sibling", "shallow-descent", "deep-descent", "absorbing" | XSLT 3.0+ | Подсказка для потоковой обработки (streaming). Требуется Saxon-EE. |
default-attribute-version | "1.0", "2.0", "3.0" | XSLT 3.0+ | Версия атрибутов по умолчанию для xsl:attribute, xsl:element и др. |
default-function-namespace | IRI | XSLT 3.0+ | Пространство имён, в котором искать функции без префикса. По умолчанию http://www.w3.org/2005/xpath-functions. |
input-type-annotations | "strip", "preserve", "unspecified" | XSLT 3.0+ | Управляет, сохраняются ли аннотации типа узлов входного документа. |
output-version | "1.0", "2.0", "3.0" | XSLT 3.0+ | Версия XSLT, для которой оптимизирован вывод (влияет на сериализацию). |
🔸 1.2 Глобальные объявления (дочерние <xsl:stylesheet>)
| Элемент | Краткое назначение | Ключевые атрибуты |
|---|---|---|
<xsl:import> | Импорт другой таблицы стилей (в начале, до любых других объявлений). Упорядочен: импортированные стили имеют меньший приоритет, чем основная таблица. | href (обяз.), use-when |
<xsl:include> | Включение содержимого другой таблицы стилей (как макроподстановка). Должен находиться после всех <xsl:import>. | href, use-when |
<xsl:namespace-alias> | Сопоставление префиксов пространств имён (для генерации XSLT из XSLT). | stylesheet-prefix, result-prefix |
<xsl:preserve-space> / <xsl:strip-space> | Управление обработкой whitespace-only текстовых узлов входного XML. | elements (QName*, #all) |
<xsl:output> | Определение параметров сериализации результата. | name, method, version, encoding, omit-xml-declaration, standalone, doctype-public, doctype-system, cdata-section-elements, indent, media-type, use-character-maps, suppress-indentation, html-version, json-node-output-method, build-tree, allow-duplicate-names, byte-order-mark, escape-uri-attributes, include-content-type, include-xml-declaration, item-separator, suppress-indentation (XSLT 3.0+) |
<xsl:param> | Глобальный параметр (доступен во всей таблице). | name, select, as, tunnel, required, static |
<xsl:variable> | Глобальная переменная. | name, select, as, static |
<xsl:function> | Определение пользовательской функции. | name, as, override, visibility, override-extension-function, streamability, saxon:memo-function, saxon:lazy и др. |
<xsl:attribute-set> | Именованный набор атрибутов для <xsl:element> и др. | name, use-attribute-sets |
<xsl:key> | Индекс по пути (для key() и xsl:key()). | name, match, use, composite |
<xsl:decimal-format> | Формат для format-number(). | name, атрибуты форматирования (decimal-separator, grouping-separator, infinity, minus-sign, NaN, percent, per-mille, zero-digit, digit, pattern-separator) |
<xsl:character-map> | Замена символов при сериализации (например, © → ©). | name, use-character-maps |
<xsl:accumulator> | Накопитель для потоковой обработки (XSLT 3.0). | name, initial-value, as, streamable, initial-value, phase |
<xsl:mode> | Определение поведения режима (XSLT 3.0). | name, streamable, on-no-match, on-multiple-match, warning-on-no-match, build-tree, typed |
<xsl:expose> | Экспорт компонентов из пакета (XSLT 3.0). | component, names, visibility |
<xsl:package> | (Внешне) — корневой элемент пакета XSLT 3.0. | name, package-version, declared-modes, visibility, default-validation, default-collation, xpath-default-namespace |
🔸 1.3 Элемент <xsl:output> — детализация
| Атрибут | Возможные значения | Примечания |
|---|---|---|
method | "xml", "html", "xhtml", "text", "json" (XSLT 3.0+), "adaptive" | "adaptive": вывод зависит от типа результирующего узла (элемент → XML, текст → текст и т.д.) |
version | "1.0", "4.0", "5.0" (для HTML), "1.0" (для XML), "1.1" (редко) | |
encoding | "UTF-8", "UTF-16", "windows-1251", "KOI8-R" и др. | Кодировка результирующего потока. |
omit-xml-declaration | "yes", "no" | Для method="xml" — подавлять <?xml version="1.0"?>. |
standalone | "yes", "no" | Атрибут standalone в декларации XML. |
doctype-public / doctype-system | "..." | Для DTD. |
cdata-section-elements | список QNames | Элементы, содержимое которых сериализуется в <![CDATA[...]]>. |
indent | "yes", "no" | Форматирование отступами. Не гарантируется. |
media-type | "text/html", "application/xml", "application/json" и др. | HTTP Content-Type. |
use-character-maps | имена карт (через пробел) | Применяются при сериализации. |
suppress-indentation | список QNames или "#all" | Элементы, у которых отключается indent="yes" (XSLT 3.0). |
html-version | "5.0", "4.01" | Версия HTML (для method="html"). |
json-node-output-method | "xml", "json", "text" | Для узлов типа map(*)/array(*) → как сериализовать в JSON. |
build-tree | "yes", "no" | no — в потоковом режиме: узлы не строятся в памяти. |
item-separator | строка | Разделитель для method="text" при выводе последовательности. |
⚠️ Важно: в XSLT 3.0
xsl:outputможет быть объявлен внутри<xsl:package>,<xsl:function>,<xsl:template>— локальный вывод.
🔹 Часть 2. Шаблоны (xsl:template), контекст выполнения, режимы и управление применением
🔸 2.1 Элемент <xsl:template>
Это базовая единица обработки в XSLT. Определяет правило сопоставления и тело преобразования.
| Атрибут | Обяз. | Возможные значения | Примечания |
|---|---|---|---|
match | ❌ (но обязателен, если нет name) | XPath-шаблон (Pattern) — подмножество XPath | Сопоставляется с узлами входного дерева. См. ниже раздел «XPath Patterns». |
name | ❌ (но обязателен, если нет match) | xs:QName | Именованный шаблон — вызывается через <xsl:call-template>. Может совмещаться с match. |
mode | ❌ | xs:QName, #default, #unnamed, #current, #text-only, #deep-copy, #all (XSLT 3.0) | Режим обработки. Если не указан — #default. |
priority | ❌ | xs:decimal | Явный приоритет шаблона при разрешении конфликтов. По умолчанию вычисляется автоматически (см. ниже). |
as | ❌ | SequenceType (XSLT 2.0+) | Тип возвращаемого значения (например, xs:string*, element()*, item()*). Проверяется при xsl:sequence/автовыводе. |
visibility | ❌ | "public", "private", "final", "abstract", "hidden" (XSLT 3.0) | Контроль доступа (пакеты). hidden — не наследуется и не переопределяется. |
override | ❌ | "yes", "no" (XSLT 3.0, устаревшее) | Заменяет шаблон из импортированной таблицы с тем же match/mode. В XSLT 3.0 предпочтительно использовать visibility. |
streamable | ❌ | "yes", "no", "sliding", "absorbing" (XSLT 3.0) | Поддержка потоковой обработки. Требует Saxon-EE. |
use-when | ❌ | XPath-выражение (вычисляется на этапе компиляции) | Условная компиляция шаблона. Должно быть статическим выражением (без ссылок на узлы/параметры времени выполнения). |
Вложенность и содержимое <xsl:template>
- Может содержать любые XSLT-инструкции, текст, литеральные элементы результата.
- Допустимы
<xsl:param>(локальные параметры шаблона). - Начиная с XSLT 3.0:
<xsl:context-item>— декларация типа контекстного элемента (as,use).
🔸 2.2 Контекст выполнения шаблона
При срабатывании шаблона устанавливается динамический контекст (dynamic context), который включает:
| Компонент | Описание | Доступ в XPath/XSLT |
|---|---|---|
| Контекстный узел (context node) | Узел, для которого вызван шаблон (совпал с match) | ., self::node(), name(), local-name(), namespace-uri() |
| Контекстная позиция (context position) | Позиция узла в текущей последовательности (например, 1-й из 5) | position() — в xsl:for-each, xsl:apply-templates, xsl:for-each-group |
| Контекстный размер (context size) | Общее число узлов в текущей последовательности | last() |
| Контекстные переменные | Параметры (xsl:param), локальные переменные (xsl:variable), глобальные переменные/параметры | $name |
| Текущий режим (current mode) | Режим, в котором вызван шаблон (xsl:apply-templates/@mode) | Не напрямую, но влияет на разрешение xsl:apply-templates без mode |
| Текущая группа (current group) | При xsl:for-each-group — текущая группа узлов | current-group(), current-grouping-key(), current-grouping-key() |
| Предшествующий и последующий узел (preceding/following) | В потоковом режиме — ограниченный доступ | Только через аккумуляторы (XSLT 3.0) |
⚠️ Ограничения в потоковом режиме (XSLT 3.0 streaming):
- Нельзя использовать
//,preceding::,following::,ancestor::,position() > 1,last(),count(//*)и др.- Допустимо:
child::,attribute::,self::,parent::(еслиstreamable="absorbing"),xsl:iterate,xsl:accumulator.
🔸 2.3 XPath Patterns (шаблонные выражения для match)
Элемент match принимает Pattern, а не произвольный XPath. Pattern — это подмножество XPath с ограничениями.
✅ Допустимые конструкции:
| Конструкция | Пример | Примечания |
|---|---|---|
| Тест имени | para, *:section, svg:rect, Q{http://example.com}foo | Пространства имён должны быть объявлены. |
| Тест типа | text(), comment(), processing-instruction(), node(), document-node(), element(), attribute() | |
| Комбинированные тесты | element(book), attribute(id), document-node(element(bookstore)) | XSLT 2.0+ |
| Комбинирование через ` | ` | `chapter |
| С предикатами | para[@lang='en'], section[heading], *[position() mod 2 = 1] | Предикаты могут содержать любые XPath-выражения, кроме ссылок на контекст (кроме . и @*). |
| Оси | child::para, attribute::id, self::node() | Только child, attribute, self, parent, ancestor, descendant, following-sibling, preceding-sibling. descendant-or-self::node() разрешён (для /). |
| Универсальные шаблоны | /, *, @*, node() |
❌ Запрещено в Pattern:
//— недопустимо. Используйтеdescendant-or-self::node()только в/.position(),last()— только внутри предикатов, и то ограниченно.- Переменные (
$var) — нельзя в Pattern (XSLT 3.0 позволяет только в<xsl:evaluate>). - Вызовы функций, зависящие от контекста (кроме
name(),local-name(),namespace-uri()для текущего узла). id(),key()— нельзя вmatch(только в предикатах при вызове, но не в самом шаблоне).
✅ XSLT 3.0 позволяет использовать параметризованные шаблоны через
<xsl:use-when>, но не через$varвmatch.
🔸 2.4 Приоритет шаблонов и разрешение конфликтов
Если несколько шаблонов подходят одному узлу — выбирается наиболее приоритетный.
Алгоритм:
-
У всех подходящих шаблонов вычисляется priority:
- Явно заданный через
@priority(xs:decimal, напр.priority="2.5"); - Иначе — автоматически:
*|/|@*|node()→-0.5ns:*→-0.25*для элемента без префикса →0.0name→0.0name[expr]→0.5ns:name[expr]→0.5node()[expr]→0.5/(корневой) →0.5id('x')— недопустимо вmatch, но если бы —0.5//name— недопустимо, но если бы —-0.5
- Явно заданный через
-
Из шаблонов с максимальным приоритетом:
- Если ровно один — берётся он.
- Если несколько — ошибка времени выполнения «ambiguous rule match», если только:
- Все шаблоны находятся в одной таблице → ошибка.
- Шаблоны в разных таблицах — побеждает шаблон из таблицы с большим приоритетом импорта (последняя импортированная имеет больший приоритет, чем импортировавшая её).
✅ XSLT 3.0 смягчает это через
<xsl:mode on-multiple-match="use-last" | "use-first" | "fail">.
🔸 2.5 Режимы (mode)
Режим — механизм полиморфной обработки одного и того же узла по-разному.
Значение mode | Пояснение |
|---|---|
не указан / #default | Стандартный режим. |
#unnamed | То же, что #default. |
QName (например, toc, html:body) | Пользовательский режим. |
#current (XSLT 2.0+) | Передаёт текущий режим вложенному xsl:apply-templates без указания mode. |
#text-only (XSLT 3.0) | Автоматический режим: копирует только текстовое содержимое (аналог xsl:apply-templates select="text()"/>). |
#deep-copy (XSLT 3.0) | Полное глубокое копирование (аналог copy-of). |
#all (XSLT 3.0, в xsl:apply-templates) | Применяет шаблоны во всех именованных режимах (редко используется). |
Управление по умолчанию (XSLT 3.0, <xsl:mode>):
<xsl:mode name="toc" on-no-match="shallow-skip"/>
<xsl:mode name="#default" on-no-match="shallow-copy"/>
<xsl:mode name="strict" on-no-match="fail"/>
Возможные значения on-no-match:
shallow-copy— копировать элемент и атрибуты, но не детей (стандартное поведение XSLT 1.0).deep-copy— полное копирование.shallow-skip— пропустить (ничего не выводить).text-only— только текст.fail— ошибка.use-next-match— применить следующий по приоритету шаблон (рекурсивно).
🔸 2.6 <xsl:apply-templates> — управление применением
| Атрибут | Обяз. | Значения | Пояснение |
|---|---|---|---|
select | ❌ | XPath-выражение → node()* | Последовательность узлов для обработки. По умолчанию — дочерние узлы контекстного узла (child::node()). |
mode | ❌ | xs:QName, #default, #current, #text-only, #deep-copy и др. | Режим. Если #current — наследует режим текущего шаблона. |
tunnel | ❌ | "yes", "no" | Передача туннельных параметров (см. ниже). |
use-accumulators | ❌ | "yes", "no" | Использовать аккумуляторы (XSLT 3.0 streaming). |
saxon:threads | ❌ | число | Параллельная обработка (Saxon-PE/EE). |
xsl:fallback | — | — | Дочерний элемент для fallback-обработки при ошибке (редко). |
Поведение по умолчанию:
<xsl:apply-templates/>
≡
<xsl:apply-templates select="child::node()" mode="#default"/>
Туннельные параметры (tunnel="yes"):
- Параметр объявляется с
tunnel="yes"в<xsl:with-param>. - Может быть принят любым шаблоном на пути, даже если он не объявлен как
<xsl:param name="x" tunnel="yes"/>. - Если шаблон не объявляет параметр — он автоматически «протуннелируется» дальше.
Пример:
<xsl:apply-templates select="chapter">
<xsl:with-param name="lang" tunnel="yes" select="'en'"/>
</xsl:apply-templates>
<!-- в шаблоне для para (вложен в chapter) -->
<xsl:template match="para">
<xsl:param name="lang" tunnel="yes" as="xs:string"/>
<p class="{$lang}">{.}</p>
</xsl:template>
🔸 2.7 <xsl:call-template>
Вызов именованного шаблона (аналог подпрограммы).
| Атрибут | Обяз. | Пояснение |
|---|---|---|
name | ✅ | xs:QName шаблона с name="...". |
tunnel | ❌ | "yes" — передаёт все туннельные параметры. |
<xsl:with-param> | ❌ | Передача параметров (со select, as, tunnel). |
❗ Контекстный узел не меняется — остаётся тот же, что и в вызывающем шаблоне.
🔹 Часть 3. Генерация результата: статические и динамические конструкции
🔸 3.1 Литеральные элементы результата
Любой элемент вне пространства имён xsl: (и не исключённый через exclude-result-prefixes) копируется «как есть» в выходной документ, с заменой:
{...}— Attribute Value Templates (AVT): в значениях атрибутов — интерполируются как XPath-выражения (XSLT 1.0+).{ {...} }— в XSLT 3.0 приexpand-text="yes"— Text Value Templates (TVT): в текстовом содержимом элементов.
Пример (XSLT 1.0):
<a href="report-{$id}.html" title="Report for {name(.)}">
<xsl:value-of select="title"/>
</a>
Пример (XSLT 3.0, expand-text="yes"):
<xsl:stylesheet version="3.0" expand-text="yes">
<xsl:template match="book">
<div class="book" id="b-{isbn}">
Title: {title}, Price: {format-number(price, '¤#,##0.00')}
</div>
</xsl:template>
</xsl:stylesheet>
⚠️ AVT/TVT экранируются:
{→{{,}→}}.
🔸 3.2 Динамическое создание узлов
| Элемент | Назначение | Обяз. атрибуты | Ключевые необяз. атрибуты |
|---|---|---|---|
<xsl:element> | Создаёт элемент с динамическим именем | name (XPath, xs:QName) | namespace, inherit-namespaces, use-attribute-sets, validation, type (XSLT 2.0+) |
<xsl:attribute> | Создаёт атрибут | name | namespace, select, separator, validation, type, use-when |
<xsl:namespace> | Создаёт узел пространства имён (редко) | name | select |
<xsl:processing-instruction> | PI-узел | name | select, use-when |
<xsl:comment> | Комментарий | — | select, use-when |
<xsl:text> | Текстовый узел (гарантированно) | — | disable-output-escaping, use-when |
<xsl:value-of> | Вывод значения выражения | — | select, separator, disable-output-escaping |
<xsl:sequence> | Вывод последовательности (XSLT 2.0+) | — | select, use-when |
<xsl:document> | Создаёт фрагмент документа (XSLT 1.0) или временный документ-узел (XSLT 2.0+) | — | validation, type, abort, use-when |
Атрибут validation (XSLT 2.0+):
"strip"— игнорировать типы (по умолчанию),"preserve"— сохранять типы из схемы,"strict"/"lax"— валидировать против схемы (требуется XSD).
Атрибут type (XSLT 2.0+):
xs:QNameтипа (например,xs:integer,element(book)).
Атрибут inherit-namespaces (xsl:element и xsl:copy):
"yes"(по умолчанию) — копировать все объявленияxmlns:*из текущего узла."no"— не наследовать (только пространства, используемые в имени/атрибутах).
🔸 3.3 Копирование узлов
| Элемент | Назначение | Атрибуты |
|---|---|---|
<xsl:copy> | Поверхностное копирование узла (только сам узел и его пространства имён/атрибуты) | copy-namespaces, inherit-namespaces, use-attribute-sets, validation, type |
<xsl:copy-of> | Глубокое копирование (всё поддерево) | select, copy-accumulators, copy-namespaces, type, validation |
Особенности:
<xsl:copy>— не копирует детей; обычно используется в шаблонеmatch="node()"с<xsl:apply-templates/>.<xsl:copy-of>работает с любыми узлами, а также сmap(*),array(*)(XSLT 3.0 → сериализует в JSON, еслиmethod="json").copy-namespaces="no"— отключает копированиеxmlns:*, кроме тех, что нужны для имён узлов/атрибутов.
🔸 3.4 Управление последовательностями и типами
| Элемент | Назначение | Примечания |
|---|---|---|
<xsl:sequence> | Вывод последовательности (замена xsl:copy-of для нетипизированных данных) | Рекомендуется вместо xsl:copy-of, когда копирование не требуется. Не создаёт узлов — передаёт значения напрямую. |
<xsl:map> / <xsl:map-entry> | (XSLT 3.0) Создание map(*) | <xsl:map> — корневой; <xsl:map-entry key="..." select="..."/> |
<xsl:array> / <xsl:array-member> | (XSLT 3.0) Создание array(*) | <xsl:array> — корневой; <xsl:array-member select="..."/> или вложенное содержимое |
<xsl:merge> | (XSLT 3.0) Объединение нескольких источников в потоковом режиме | Требует streamable="yes"; работает с xsl:merge-source, xsl:merge-key — для join-подобных операций. |
Пример map:
<xsl:variable name="config" as="map(xs:string, item()*)">
<xsl:map>
<xsl:map-entry key="'version'" select="3.0"/>
<xsl:map-entry key="'lang'" select="'en'"/>
<xsl:map-entry key="'features'">
<xsl:array>
<xsl:array-member select="'streaming'"/>
<xsl:array-member select="'packages'"/>
</xsl:array>
</xsl:map-entry>
</xsl:map>
</xsl:variable>
Доступ: $config?version, $config?features?2.
🔸 3.5 Сериализация: управление выходным форматом
XSLT 3.0 ввёл гибкую сериализацию, включая JSON.
Методы вывода (xsl:output/@method):
| Метод | Особенности | Поддержка |
|---|---|---|
xml | Стандартный XML (с декларацией, сущностями, и т.д.) | XSLT 1.0+ |
html | HTML-совместимый вывод (без закрывающих /, регистронезависимые имена, и др.) | XSLT 1.0+ |
xhtml | XHTML (корректный XML с HTML-семантикой) | XSLT 2.0+ |
text | Чистый текст (без разметки; item-separator используется между элементами последовательности) | XSLT 1.0+ |
json | Сериализация map(*), array(*), xs:string, xs:double, xs:boolean, null в JSON | XSLT 3.0+ |
adaptive | Автоопределение: элемент → XML, строка → текст, map/array → JSON и т.д. | XSLT 3.0+ |
Параметры JSON-сериализации (через xsl:output):
| Атрибут | Значения | Примечание |
|---|---|---|
json-node-output-method | "xml", "json", "text" | Как выводить не-JSON-узлы внутри map/array. |
allow-duplicate-names | "yes", "no" | Разрешить дубли ключей в map(*) → при no — ошибка. |
escape-uri-attributes | "yes", "no" | Экранировать URI в атрибутах (для xml/xhtml). |
include-content-type | "yes", "no" | Добавлять Content-Type: application/json в комментарий. |
include-xml-declaration | "yes", "no" | Для method="xml"/xhtml. |
Пример JSON-вывода:
<xsl:output method="json" indent="yes"/>
<xsl:template match="/">
<xsl:sequence select="
map {
'books': array {
//book ! map {
'title': string(title),
'price': number(price),
'authors': array { author ! string(.) }
}
}
}"/>
</xsl:template>
Результат:
{
"books": [
{
"title": "XSLT Guide",
"price": 29.99,
"authors": ["Timur"]
}
]
}
🔸 3.6 Управление экранированием: disable-output-escaping
| Элементы | Атрибут | Возможные значения |
|---|---|---|
<xsl:value-of>, <xsl:text> | disable-output-escaping | "yes", "no" (по умолчанию) |
"yes"— отключает экранирование&,<,>→ выводит «как есть».- Предупреждение: не поддерживается:
- При
method="text"(игнорируется), - При потоковой обработке (XSLT 3.0 streaming),
- В некоторых процессорах (например, в браузерных XSLT 1.0 — может не работать).
- При
🚫 Не рекомендуется для генерации XML/HTML — нарушает well-formedness. Использовать только для legacy-совместимости (например, вставки CDATA или pre-сериализованного HTML).
🔹 Часть 4. Управление потоком: условия, циклы, группировка, обработка исключений
🔸 4.1 Условные конструкции
| Элемент | Назначение | Обяз. атрибуты | Замечания |
|---|---|---|---|
<xsl:if> | Простая условная ветвь | test (XPath-выражение) | Эквивалент xsl:choose с одним xsl:when. Не имеет else. |
<xsl:choose> | Многоусловная конструкция | — | Обязательно содержит ≥1 <xsl:when>; опционально <xsl:otherwise>. |
<xsl:when> | Ветвь условия внутри xsl:choose | test | Выполняется первая истинная ветвь. |
<xsl:otherwise> | Ветвь по умолчанию | — | Должна быть последней в xsl:choose. |
Пример:
<xsl:choose>
<xsl:when test="price < 10">cheap</xsl:when>
<xsl:when test="price < 50">moderate</xsl:when>
<xsl:otherwise>expensive</xsl:otherwise>
</xsl:choose>
⚠️ Оптимизация: XSLT-процессоры (например, Saxon) могут оптимизировать
xsl:chooseвswitch-подобные конструкции, если условия — простые строковые или целочисленные сравнения.
🔸 4.2 Итерация: <xsl:for-each>
| Атрибут | Обяз. | Значения | Пояснение |
|---|---|---|---|
select | ✅ | XPath → item()* | Последовательность для итерации. |
sort (вложенный <xsl:sort>) | ❌ | — | Сортировка перед итерацией (см. ниже). |
saxon:threads | ❌ | xs:integer | Параллельная обработка (Saxon PE/EE). Требует идемпотентности тела. |
Контекст внутри <xsl:for-each>:
- Контекстный узел — текущий элемент последовательности.
position()— позиция в текущей итерации (1…N).last()— общее число итераций (count($seq)).
Пример сортировки:
<xsl:for-each select="book">
<xsl:sort select="author" order="ascending" lang="en"/>
<xsl:sort select="year" data-type="number" order="descending"/>
<li>{author}, {title} ({year})</li>
</xsl:for-each>
Атрибуты <xsl:sort>:
| Атрибут | Возможные значения | Примечания |
|---|---|---|
select | XPath | Выражение для извлечения ключа сортировки. По умолчанию — строковое значение текущего узла. |
order | "ascending", "descending" | По умолчанию — "ascending". |
data-type | "text", "number", "qname" | "text" — лексикографически (по lang/collation), "number" — численно. |
lang | xs:language (например, "ru", "en-US") | Язык для локализованной сортировки (например, ё после е). |
collation | URI коллации | Перекрывает lang. Стандартные URI: http://www.w3.org/2005/xpath-functions/collation/codepoint, .../html-ascii-case-insensitive. |
case-order | "upper-first", "lower-first" | Влияет при data-type="text". |
stable | "yes", "no" (XSLT 2.0+) | Устойчивая сортировка (сохранение исходного порядка при равенстве ключей). |
🔸 4.3 Группировка: <xsl:for-each-group>
Ключевой механизм XSLT 2.0+ для агрегации данных.
| Атрибут | Обяз. | Значения | Пояснение |
|---|---|---|---|
select | ✅ | item()* | Последовательность для группировки. |
group-by | ✅ (или group-adjacent, group-starting-with, group-ending-with) | XPath | Выражение, возвращающее ключ группы (любой тип, но сравнимый). |
collation | ❌ | URI | Коллация для строковых ключей. |
Типы группировки:
| Тип | Атрибут | Поведение |
|---|---|---|
| По значению | group-by | Все узлы с одинаковым ключом → одна группа (аналог SQL GROUP BY). |
| По смежности | group-adjacent | Группа формируется из смежных узлов с одинаковым ключом. |
| По началу | group-starting-with | XPath-шаблон: новая группа начинается при совпадении. |
| По окончанию | group-ending-with | XPath-шаблон: группа заканчивается при совпадении. |
Контекстные функции внутри тела:
| Функция | Возвращает | Примечание |
|---|---|---|
current-group() | item()* | Все элементы текущей группы. |
current-grouping-key() | xs:anyAtomicType | Ключ текущей группы (для group-by/group-adjacent). |
current-grouping-start() | node()? | Узел, начавший группу (group-starting-with). |
current-grouping-end() | node()? | Узел, завершивший группу (group-ending-with). |
Пример (группировка книг по автору):
<xsl:for-each-group select="book" group-by="author">
<h2>{current-grouping-key()}</h2>
<ul>
<xsl:for-each select="current-group()">
<li>{title} ({year})</li>
</xsl:for-each>
</ul>
</xsl:for-each-group>
⚠️ Производительность:
group-byстроит хеш-таблицу → O(n log n);group-adjacent— линейный проход → O(n). При потоковой обработке допустим толькоgroup-adjacent(и то с ограничениями).
🔸 4.4 Итерация с состоянием: <xsl:iterate> (XSLT 3.0)
Обобщённая итерация с передачей состояния (аналог fold).
| Атрибут | Обяз. | Значения | Пояснение |
|---|---|---|---|
select | ✅ | item()* | Исходная последовательность. |
initial-value | ❌ | XPath | Начальное состояние (по умолчанию — пустая последовательность). |
Вложенность:
<xsl:iterate>содержит:<xsl:param name="x" as="..." select="..."/>— входное состояние,- Тело итерации (может содержать
<xsl:on-completion>,<xsl:break>), <xsl:on-completion>— результат после последней итерации (по умолчанию — значение последнего$x).
Пример (накопление суммы):
<xsl:variable name="total" as="xs:double">
<xsl:iterate select="item" initial-value="0.0">
<xsl:param name="sum" as="xs:double"/>
<xsl:next-iteration>
<xsl:with-param name="sum" select="$sum + number(price)"/>
</xsl:next-iteration>
<xsl:on-completion select="$sum"/>
</xsl:iterate>
</xsl:variable>
✅ Поддерживает потоковую обработку, если тело — потоковое.
🔸 4.5 Анализ строк: <xsl:analyze-string>
Разбор текста по регулярному выражению (XSLT 2.0+).
| Атрибут | Обяз. | Значения | Пояснение |
|---|---|---|---|
select | ✅ | xs:string | Анализируемая строка. |
regex | ✅ | xs:string | Регулярное выражение (синтаксис XPath 2.0, почти как ICU). |
flags | ❌ | "i", "m", "s", "x" и др. | Флаги: i — case-insensitive, m — ^/$ по строкам, s — . включает \n, x — игнорировать пробелы в regex. |
Дочерние элементы:
| Элемент | Назначение |
|---|---|
<xsl:matching-substring> | Обработка совпадающих фрагментов. |
<xsl:non-matching-substring> | Обработка несовпадающих фрагментов. |
<xsl:fallback> | Обработка ошибок (редко). |
Контекст внутри:
.— текущий подстроковый фрагмент (xs:string),regex-group(n)— n-я захваченная группа (n ≥ 0; 0 — всё совпадение),regex-group()— все группы какxs:string*.
Пример (извлечение ссылок):
<xsl:analyze-string select="." regex="https?://[^\s]+">
<xsl:matching-substring>
<a href="{.}">{.}</a>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
⚠️ Производительность: сложные regex с backtracking могут быть медленными. Избегайте
.*без ограничений.
🔸 4.6 Обработка ошибок: <xsl:try> / <xsl:catch> (XSLT 3.0)
Аналог try/catch в императивных языках.
| Элемент | Назначение | Атрибуты |
|---|---|---|
<xsl:try> | Блок, в котором могут возникнуть ошибки | — |
<xsl:catch> | Обработчик исключения | errors (список QNames ошибок), select (для ошибки как узла) |
Структура:
<xsl:try>
<!-- защищённый код -->
<xsl:sequence select="doc('missing.xml')"/>
<xsl:fallback>
<xsl:message>Fallback used</xsl:message>
</xsl:fallback>
<xsl:catch errors="err:FODC0002">
<xsl:message>Error loading document</xsl:message>
<xsl:sequence select="()"/> <!-- пустая последовательность -->
</xsl:catch>
<xsl:catch>
<xsl:message>Other error</xsl:message>
</xsl:catch>
</xsl:try>
Встроенные ошибки (примеры):
| Код | Описание |
|---|---|
err:XTDE0050 | Ошибка в xsl:message terminate="yes" |
err:FODC0002 | Ошибка загрузки документа (doc()) |
err:FORG0001 | Ошибка приведения типа (например, xs:integer('abc')) |
err:XPDY0002 | Обращение к контекстному узлу вне контекста |
✅ Можно генерировать ошибки через
<xsl:error>(Saxon-расширение) илиerror()в XPath.
🔹 Часть 5. Переменные, параметры, функции, типы, модульность и потоковая обработка
🔸 5.1 Переменные и параметры
Объявление
| Элемент | Область видимости | Обяз. атрибуты | Особенности |
|---|---|---|---|
<xsl:variable> | Глобальная (дочерний <xsl:stylesheet>) или локальная (внутри шаблона/инструкции) | name | Неизменяема после инициализации. |
<xsl:param> | Глобальная или локальная (в <xsl:template>, <xsl:function>, <xsl:iterate>) | name | Может быть переопределён при вызове (xsl:with-param, xsl:with-param tunnel). |
Атрибуты (общие для xsl:variable/xsl:param):
| Атрибут | Значения | Примечания |
|---|---|---|
name | xs:QName | Обязательный. |
select | XPath-выражение | Инициализация. Если указано — тело игнорируется. |
as | SequenceType (XSLT 2.0+) | Ограничение типа (строгая типизация). Проверяется при присвоении. |
static | "yes", "no" (XSLT 3.0) | Статическая переменная/параметр — вычисляется на этапе компиляции. Доступна в use-when. |
tunnel | "yes", "no" (только для <xsl:param>) | Параметр передаётся «сквозь» промежуточные шаблоны. |
required | "yes", "no" (XSLT 3.0) | Обязательный параметр: если не передан — ошибка. |
visibility | "public", "private", "final", "abstract", "hidden" (XSLT 3.0, глобальные) | Контроль доступа в пакетах. |
Важные правила:
- Глобальная переменная/параметр вычисляется лениво (при первом обращении) и один раз.
- Локальная переменная вычисляется при входе в блок.
- Тип
xs:untypedAtomic— промежуточный тип строк без пространства имён (используется при чтении XML без схемы). - Если
asуказан иselectотсутствует, инициализация — пустая последовательность().
Примеры:
<!-- Глобальная строго типизированная переменная -->
<xsl:variable name="max-length" as="xs:integer" select="100"/>
<!-- Локальный параметр с типом и значением по умолчанию -->
<xsl:param name="lang" as="xs:string" select="'en'"/>
<!-- Статический параметр (доступен в use-when) -->
<xsl:param name="debug" static="yes" as="xs:boolean" select="true()"/>
🔸 5.2 Пользовательские функции (<xsl:function>)
| Атрибут | Обяз. | Значения | Пояснение |
|---|---|---|---|
name | ✅ | xs:QName | Имя функции (обычно с префиксом, отличным от xsl:). |
as | ❌ | SequenceType | Тип возвращаемого значения. |
override | ❌ | "yes", "no" (устаревшее) | Разрешить переопределение импортированной функции. |
visibility | ❌ | "public", "private", "final", "abstract", "hidden" (XSLT 3.0) | Контроль доступа. |
override-extension-function | ❌ | "yes", "no" | Разрешить перекрытие встроенных функций (например, math:sin). Опасно. |
streamability | ❌ | "yes", "no", "shallow-descent" и др. | Поддержка потоковой обработки. |
saxon:memo-function | ❌ | "yes", "no" (Saxon) | Мемоизация (кеширование результатов по аргументам). |
saxon:lazy | ❌ | "yes" (Saxon) | Ленивая оценка результата (для больших последовательностей). |
Тело функции:
- Обязательно содержит
<xsl:param>(аргументы), затем — последовательность инструкций илиxsl:sequence. - Возвращаемое значение — результат последней инструкции или явно через
<xsl:sequence select="..."/>.
Пример:
<xsl:function name="my:format-price" as="xs:string">
<xsl:param name="amount" as="xs:decimal"/>
<xsl:param name="currency" as="xs:string" select="'USD'"/>
<xsl:sequence select="concat(format-number($amount, '¤#,##0.00'), ' ', $currency)"/>
</xsl:function>
Вызов: my:format-price(29.99, 'RUB').
⚠️ Ограничения:
- Функции не имеют доступа к контекстному узлу (
.,position(),last()запрещены).- Не могут модифицировать глобальные переменные (чистые функции).
- В XSLT 3.0 допустимы higher-order functions (функции как аргументы/возврат).
🔸 5.3 Типы данных и строгая типизация
XSLT 3.0 поддерживает полную систему типов XPath 3.1 (на основе XSD 1.1 + расширения).
Иерархия типов (упрощённо):
item()
├── node()
│ ├── document-node()
│ ├── element()
│ ├── attribute()
│ ├── text()
│ ├── comment()
│ └── processing-instruction()
├── function(*)
├── map(*)
├── array(*)
└── xs:anyAtomicType
├── xs:untypedAtomic
├── xs:string
│ ├── xs:normalizedString
│ └── xs:token
│ ├── xs:language, xs:NMTOKEN и др.
├── xs:boolean
├── xs:decimal
│ ├── xs:integer
│ ├── xs:long, xs:int, xs:short, xs:byte
│ └── xs:nonNegativeInteger и др.
├── xs:float, xs:double
├── xs:dateTime, xs:date, xs:time, xs:gYearMonth и др.
├── xs:QName, xs:NOTATION
└── xs:anyURI, xs:base64Binary, xs:hexBinary
SequenceType (синтаксис в as):
| Конструкция | Примеры | Значение |
|---|---|---|
T | xs:string, element(book) | Ровно один элемент типа T |
T? | xs:integer?, node()? | 0 или 1 элементов |
T* | item()*, xs:string* | 0 или более |
T+ | attribute(id)+ | 1 или более |
empty-sequence() | — | Только пустая последовательность |
(T1, T2, T3) | (xs:string, xs:integer) | Точная последовательность из 3 элементов заданных типов |
✅ Типизация помогает:
- Выявлять ошибки на этапе компиляции (если включено:
xsl:stylesheet/@schema-aware="yes"в Saxon-EE),- Оптимизировать выполнение (например,
xs:integer→ машинное целое).
🔸 5.4 Модульность: импорт, пакеты, пакетные зависимости (XSLT 3.0)
<xsl:import> и <xsl:include>
<xsl:import> | <xsl:include> | |
|---|---|---|
| Приоритет | Низкий (переопределяется основной таблицей) | Равный основной таблице |
| Расположение | Только в начале, до любых объявления | После <xsl:import>, до остальных |
| Повторное включение | Запрещено (ошибка) | Разрешено, но не рекомендуется |
Пакеты (<xsl:package>)
- Единица модульности в XSLT 3.0.
- Корневой элемент —
<xsl:package>(вместо<xsl:stylesheet>). - Имеет
name,package-version,visibility.
<xsl:use-package>
<xsl:use-package name="http://example.com/lib" package-version="1.0">
<xsl:accept component="function" names="lib:format-date"/>
<xsl:accept component="template" names="lib:toc"/>
<xsl:override>
<xsl:function name="lib:format-date" override="yes">
<!-- переопределение -->
</xsl:function>
</xsl:override>
</xsl:use-package>
<xsl:expose>
<xsl:expose component="function" names="my:format-price" visibility="public"/>
<xsl:expose component="variable" names="my:config" visibility="private"/>
✅ Пакеты позволяют:
- Изолировать реализацию (
visibility="private"),- Управлять версиями,
- Избегать конфликтов имён.
🔸 5.5 Аккумуляторы (Accumulators, XSLT 3.0)
Механизм для поддержания состояния при потоковой обработке (streaming).
Объявление:
<xsl:accumulator name="section-depth" as="xs:integer" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="section" select="$value + 1"/>
<xsl:accumulator-rule match="section/section" select="$value - 1"/>
</xsl:accumulator>
| Атрибут | Значения | Пояснение |
|---|---|---|
name | xs:QName | Имя аккумулятора. |
as | SequenceType | Тип значения. |
initial-value | XPath | Начальное значение ($value — предыдущее). |
streamable | "yes", "no" | Обязателен для streaming. |
phase | "start", "end" | Когда обновлять: при входе в узел (start) или выходе (end). По умолчанию — end. |
Использование:
- В шаблоне:
accumulator-before('section-depth'),accumulator-after('section-depth'). - В
xsl:apply-templates:use-accumulators="yes".
✅ Аккумуляторы — единственный способ доступа к «предыдущему состоянию» в потоковом режиме. ❌ Нельзя использовать
preceding::,//,xsl:key, глобальные переменные.
🔸 5.6 Потоковая обработка (Streaming, XSLT 3.0)
Цель: обработка XML-документов больше, чем RAM, за один проход.
Требования:
- Процессор: Saxon-EE (единственный полноценный поддерживаемый).
xsl:stylesheet/@streamable="yes"или<xsl:mode streamable="yes"/>.- Все шаблоны и функции — потоковые.
Правила потоковости (упрощённо):
✅ Разрешено:
child::,attribute::,self::node(),xsl:apply-templates select="child::node()",xsl:iterate,xsl:accumulator,xsl:copy,xsl:element,xsl:attribute(без ссылок назад),xsl:if,xsl:choose— еслиtestпотоковый.
❌ Запрещено:
//,descendant::,ancestor::,preceding::,following::,position() > 1,last(),count(//*),id(),key(),$global-variable,document(),doc(),xsl:for-each-group(кромеgroup-adjacentв особых случаях).
Пример потокового шаблона:
<xsl:mode streamable="yes"/>
<xsl:template match="book" streamable="yes">
<book id="{@id}" title="{title}"/>
</xsl:template>
📊 Скорость: 50–200 МБ/с на SSD, потребление памяти — O(1) по глубине вложенности.
🔹 Часть 6. Встроенные функции: полный справочник
🔸 6.1 Последовательности и агрегация
| Функция | Сигнатура | Версия | Пояснение |
|---|---|---|---|
empty($seq) | item()* → xs:boolean | XPath 2.0 | true() если последовательность пуста. |
exists($seq) | item()* → xs:boolean | XPath 2.0 | true() если не пуста. |
count($seq) | item()* → xs:integer | XPath 1.0 | Число элементов. |
distinct-values($seq, $collation?) | xs:anyAtomicType* [, xs:string] → xs:anyAtomicType* | XPath 2.0 | Уникальные значения (с учётом коллации). |
index-of($seq, $value, $collation?) | xs:anyAtomicType*, xs:anyAtomicType [, xs:string] → xs:integer* | XPath 2.0 | Позиции вхождений (1-based). |
insert-before($seq, $pos, $val) | item()*, xs:integer, item()* → item()* | XPath 2.0 | Вставка перед позицией $pos. |
remove($seq, $pos) | item()*, xs:integer → item()* | XPath 2.0 | Удаление элемента. |
reverse($seq) | item()* → item()* | XPath 2.0 | Разворот. |
subsequence($seq, $start, $len?) | item()*, xs:double, xs:double? → item()* | XPath 1.0 | Подпоследовательность (1-based, $len не обяз.). |
unordered($seq) | item()* → item()* | XPath 2.0 | Указывает, что порядок не важен (оптимизация). |
⚠️
count(//node())не streamable — требует полной загрузки.
🔸 6.2 Строки
| Функция | Сигнатура | Версия | Пояснение |
|---|---|---|---|
string($arg?) | item()? → xs:string | XPath 1.0 | Приведение к строке. Без аргумента — string(.). |
string-length($arg?) | xs:string? → xs:integer | XPath 1.0 | Длина в символах Unicode (не байтах). |
normalize-space($arg?) | xs:string? → xs:string | XPath 1.0 | Удаление leading/trailing whitespace, замена внутренних #x20. |
upper-case($arg) | xs:string → xs:string | XPath 2.0 | Приведение к верхнему регистру (по Unicode). |
lower-case($arg) | xs:string → xs:string | XPath 2.0 | К нижнему. |
contains($haystack, $needle, $collation?) | xs:string, xs:string, xs:string? → xs:boolean | XPath 1.0 | Проверка подстроки. |
starts-with($str, $prefix, $collation?) | xs:string, xs:string, xs:string? → xs:boolean | XPath 1.0 | Начинается с… |
ends-with($str, $suffix, $collation?) | xs:string, xs:string, xs:string? → xs:boolean | XPath 2.0 | Заканчивается на… |
substring($str, $start, $len?) | xs:string, xs:double, xs:double? → xs:string | XPath 1.0 | Подстрока (1-based, $start может быть дробным — интерполяция). |
substring-before($str, $substr, $collation?) | xs:string, xs:string, xs:string? → xs:string | XPath 1.0 | Часть до первого вхождения. |
substring-after($str, $substr, $collation?) | xs:string, xs:string, xs:string? → xs:string | XPath 1.0 | Часть после. |
translate($str, $map1, $map2) | xs:string, xs:string, xs:string → xs:string | XPath 1.0 | Поэлементная замена (аналог tr). |
codepoints-to-string($cp) | xs:integer* → xs:string | XPath 2.0 | Из кодовых точек Unicode. |
string-to-codepoints($str) | xs:string → xs:integer* | XPath 2.0 | В кодовые точки. |
matches($input, $pattern, $flags?) | xs:string, xs:string, xs:string? → xs:boolean | XPath 2.0 | Regex-совпадение. |
replace($input, $pattern, $replacement, $flags?) | xs:string, xs:string, xs:string, xs:string? → xs:string | XPath 2.0 | Regex-замена. $1, $2 — группы. |
tokenize($input, $pattern, $flags?) | xs:string?, xs:string, xs:string? → xs:string* | XPath 2.0 | Разбиение по регулярке. |
analyze-string($input, $pattern, $flags?) | xs:string, xs:string, xs:string? → document-node() | XPath 2.0 | Возвращает XML-структуру совпадений (альтернатива xsl:analyze-string). |
✅
matches('abc', '^\p{L}+$')— проверка, что строка состоит только из букв.
🔸 6.3 Числа и математика
| Функция | Сигнатура | Версия | Пояснение |
|---|---|---|---|
number($arg?) | item()? → xs:double | XPath 1.0 | Приведение к числу. |
abs($arg) | xs:double → xs:double | XPath 2.0 | Модуль. |
ceiling($arg) | xs:double → xs:double | XPath 1.0 | Округление вверх. |
floor($arg) | xs:double → xs:double | XPath 1.0 | Вниз. |
round($arg, $precision?) | xs:double, xs:integer? → xs:double | XPath 2.0 | Округление (банковское). |
round-half-to-even($arg, $precision?) | xs:double, xs:integer? → xs:double | XPath 2.0 | Округление «банкира». |
sum($seq, $zero?) | xs:anyAtomicType*, xs:anyAtomicType? → xs:anyAtomicType | XPath 2.0 | Сумма. $zero — значение при пустой последовательности. |
avg($seq) | xs:anyAtomicType* → xs:anyAtomicType | XPath 2.0 | Среднее. |
min($seq, $collation?) | xs:anyAtomicType* [, xs:string] → xs:anyAtomicType | XPath 2.0 | Минимум. |
max($seq, $collation?) | xs:anyAtomicType* [, xs:string] → xs:anyAtomicType | XPath 2.0 | Максимум. |
math:pi() | → xs:double | XPath 3.0 | π. |
math:exp($arg) | xs:double → xs:double | XPath 3.0 | e^x. |
math:log($arg) | xs:double → xs:double | XPath 3.0 | Натуральный логарифм. |
math:pow($base, $exp) | xs:double, xs:double → xs:double | XPath 3.0 | Возведение в степень. |
math:sin($arg), math:cos($arg), math:tan($arg) | xs:double → xs:double | XPath 3.0 | Тригонометрия (аргумент — радианы). |
math:sqrt($arg) | xs:double → xs:double | XPath 3.0 | Квадратный корень. |
⚠️
sum(//price)не streamable, ноsum(xsl:stream(//price))— streamable в XSLT 3.0 (с аккумулятором).
🔸 6.4 Дата и время
| Функция | Сигнатура | Версия | Пояснение |
|---|---|---|---|
current-dateTime() | → xs:dateTime | XPath 2.0 | Текущие дата и время (с часовым поясом). |
current-date() | → xs:date | XPath 2.0 | Только дата. |
current-time() | → xs:time | XPath 2.0 | Только время. |
adjust-dateTime-to-timezone($dt, $tz?) | xs:dateTime, xs:dayTimeDuration? → xs:dateTime | XPath 2.0 | Смещение часового пояса. |
days-from-duration($dur) | xs:duration → xs:integer | XPath 2.0 | Число дней в xs:dayTimeDuration. |
hours-from-dateTime($dt) | xs:dateTime → xs:integer | XPath 2.0 | Часы (0–23). |
format-dateTime($value, $picture, $lang?, $calendar?, $place?) | xs:dateTime, xs:string, xs:string?, xs:string?, xs:string? → xs:string | XPath 3.0 | Форматирование даты (ICU-подобный синтаксис). |
parse-ietf-date($str) | xs:string → xs:dateTime | XPath 3.1 | Разбор Thu, 20 Nov 2025 12:34:56 GMT. |
Пример format-dateTime:
format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01][Z00:00:00]', 'en', (), ())
→ "2025-11-20T12:34:56+05:00"
🔸 6.5 Узлы и навигация
| Функция | Сигнатура | Версия | Пояснение |
|---|---|---|---|
node-name($node) | node()? → xs:QName | XPath 2.0 | Имя узла (для элементов/атрибутов); () для текста/комментариев. |
name($node?) | node()? → xs:string | XPath 1.0 | Строка вида prefix:local или local. |
local-name($node?) | node()? → xs:string | XPath 1.0 | Только локальная часть. |
namespace-uri($node?) | node()? → xs:string | XPath 1.0 | URI пространства имён. |
root($node?) | node()? → node() | XPath 2.0 | Корневой узел документа/фрагмента. |
base-uri($node?) | node()? → xs:anyURI | XPath 2.0 | Базовый URI (из xml:base). |
document-uri($node) | node() → xs:anyURI? | XPath 2.0 | URI документа (только для корневых узлов). |
id($idvals, $node?) | xs:string*, node()? → element()* | XPath 1.0 | Поиск по @xml:id или @id (если DTD/схема определяет ID). |
idref($idrefvals, $node?) | xs:string*, node()? → node()* | XPath 2.0 | Обратный id(). |
key($name, $keyvals, $top?) | xs:string, xs:anyAtomicType*, node()? → node()* | XSLT 1.0 | Поиск по <xsl:key>. $top — узел для поиска (по умолчанию — корень). |
unparsed-text($href, $encoding?) | xs:string, xs:string? → xs:string | XSLT 2.0 | Чтение текстового файла (не XML). |
unparsed-text-lines($href, $encoding?) | xs:string, xs:string? → xs:string* | XPath 3.0 | По строкам. |
unparsed-text-available($href, $encoding?) | xs:string, xs:string? → xs:boolean | XSLT 2.0 | Проверка существования. |
⚠️
key()не streamable — требует индекса в памяти.
🔸 6.6 Карты и массивы (XSLT 3.0 / XPath 3.1)
Карты (map:*)
| Функция | Сигнатура | Пояснение |
|---|---|---|
map:contains($map, $key) | map(*), xs:string → xs:boolean | Есть ли ключ. |
map:get($map, $key) | map(*), xs:string → item()* | Получить значение. |
map:put($map, $key, $value) | map(*), xs:string, item()* → map(*) | Новый map с добавленной парой. |
map:remove($map, $key) | map(*), xs:string → map(*) | Удалить ключ. |
map:keys($map) | map(*) → xs:string* | Все ключи. |
map:size($map) | map(*) → xs:integer | Число пар. |
map:for-each($map, $function) | map(*), function(xs:string, item()*) as item()* → item()* | Итерация (higher-order). |
map:merge($maps, $options?) | map(*)*, map(xs:string, item()*)? → map(*) | Объединение карт (конфликты: use-first, use-last, combine, combine-into-array). |
Массивы (array:*)
| Функция | Сигнатура | Пояснение |
|---|---|---|
array:size($array) | array(*) → xs:integer | Длина. |
array:get($array, $index) | array(*), xs:integer → item()* | Элемент (1-based). |
array:append($array, $value) | array(*), item()* → array(*) | Добавить в конец. |
array:subarray($array, $start, $len?) | array(*), xs:integer, xs:integer? → array(*) | Подмассив. |
array:head($array) | array(*) → item()* | Первый элемент. |
array:tail($array) | array(*) → array(*) | Все, кроме первого. |
array:reverse($array) | array(*) → array(*) | Разворот. |
array:join($arrays) | array(*)* → array(*) | Конкатенация массивов. |
array:for-each($array, $function) | array(*), function(item()*) as item()* → item()* | Итерация. |
array:filter($array, $function) | array(*), function(item()*) as xs:boolean → array(*) | Фильтрация. |
array:fold-left($array, $zero, $function) | array(*), item()*, function(item()*, item()*) as item()* → item()* | Левая свёртка. |
✅
map:merge(($m1, $m2), map{'duplicates': 'combine'})— объединение с сохранением дублей какarray(*).
🔸 6.7 Потоки и отладка
| Функция | Сигнатура | Версия | Пояснение |
|---|---|---|---|
trace($value, $label) | item()*, xs:string → item()* | XPath 3.0 | Вывод значения в лог (Saxon — в stderr). |
error($code?, $description?, $error-object?) | xs:QName?, xs:string?, item()? → none | XPath 3.0 | Генерация ошибки. |
xsl:original() | → item()* | XSLT 3.0 | Внутри xsl:override — доступ к оригинальной реализации. |
xsl:evaluate($expr, $context-item?, $base-uri?, $namespace-context?, $schema-aware?) | xs:string, item()?, xs:anyURI?, element(), xs:boolean? → item()* | XSLT 3.0 | Динамическая оценка XPath-выражения (потенциально опасна). |
⚠️
xsl:evaluateотключает проверку типов и оптимизации — используйте осторожно.
🔹 Часть 7. Практические шаблоны и идиомы XSLT
🔸 7.1 Identity Transform (полное копирование)
XSLT 1.0 / 2.0 / 3.0
Базовый шаблон для любых изменяющих трансформаций («изменяй только нужное»).
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode on-no-match="shallow-copy"/>
<!-- или явно: -->
<!--
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
-->
</xsl:stylesheet>
✅ XSLT 3.0:
<xsl:mode on-no-match="shallow-copy"/>— короче, быстрее, поддерживает потоковость.
🔸 7.2 Фильтрация узлов при копировании
Удалить элементы по условию:
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="debug"/> <!-- удалить <debug> -->
<xsl:template match="comment()"/> <!-- удалить комментарии -->
<xsl:template match="processing-instruction()"/> <!-- удалить PI -->
<xsl:template match="@temp"/> <!-- удалить атрибут temp -->
Сохранить только определённые элементы:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="* | @* | text()"/>
</xsl:copy>
</xsl:template>
<!-- отключить копирование по умолчанию для нежелательных узлов -->
<xsl:template match="script | style | @class"/>
🔸 7.3 Преобразование атрибутов в элементы («атрибуты → дочерние элементы»)
Часто требуется для нормализации в NoSQL/JSON.
<xsl:template match="*">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:element name="{local-name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
Результат:
<book id="123" lang="en">…</book> → <book><id>123</id><lang>en</lang>…</book>
⚠️ Конфликт имён: если атрибут и элемент имеют одинаковое имя — потребуется префикс (
attr-), например:<xsl:element name="attr-{local-name()}"/>.
🔸 7.4 «Выпрямление» иерархии (flattening)
Преобразование вложенных структур в плоский список.
Пример: из <chapter><section><subsection>… → <section level="1">, <section level="2"> и т.д.
<xsl:template match="*">
<xsl:variable name="level" as="xs:integer">
<xsl:number level="multiple" count="chapter | section | subsection"/>
</xsl:variable>
<section level="{$level}">
<xsl:apply-templates select="@* | node()"/>
</section>
<xsl:apply-templates select="*"/>
</xsl:template>
✅ Использует
<xsl:number level="multiple"/>— стандартный механизм нумерации.
🔸 7.5 Глубокое объединение (deep merge) XML
Объединение двух XML-документов с приоритетом «новый поверх старого».
<xsl:function name="my:deep-merge" as="node()*">
<xsl:param name="primary" as="node()*"/>
<xsl:param name="secondary" as="node()*"/>
<xsl:for-each-group select="$primary, $secondary" group-by="node-name(.)">
<xsl:choose>
<xsl:when test="current-group()[2] and self::element()">
<xsl:copy>
<!-- объединить атрибуты: из secondary, затем primary (переопределение) -->
<xsl:copy-of select="current-group()[2]/@*"/>
<xsl:copy-of select="current-group()[1]/(@* except @*[name() = current-group()[2]/@*/name()])"/>
<!-- рекурсивно объединить детей -->
<xsl:sequence select="
my:deep-merge(
current-group()[1]/node(),
current-group()[2]/node()
)"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()[1]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
⚠️ Не обрабатывает текстовые узлы (требует уточнения стратегии: конкатенация / замена).
🔸 7.6 XML ↔ JSON
XML → JSON (XSLT 3.0)
<xsl:output method="json" indent="yes"/>
<xsl:template match="/">
<xsl:sequence select="my:xml-to-json(*)"/>
</xsl:template>
<xsl:function name="my:xml-to-json" as="item()*">
<xsl:param name="node" as="node()"/>
<xsl:choose>
<xsl:when test="$node instance of element()">
<xsl:map>
<xsl:map-entry key="name($node)">
<xsl:sequence select="
if ($node/*) then
array { $node/* ! my:xml-to-json(.) }
else if ($node/@*) then
map:merge((
map { 'text': string($node) },
$node/@* ! map:entry(local-name(), string(.))
))
else
string($node)
"/>
</xsl:map-entry>
</xsl:map>
</xsl:when>
</xsl:choose>
</xsl:function>
Пример входа:
<book id="123">
<title>XSLT Guide</title>
<author>Timur</author>
</book>
→
{
"book": [
{
"text": "",
"id": "123",
"title": ["XSLT Guide"],
"author": ["Timur"]
}
]
}
JSON → XML (обратное преобразование)
<xsl:template match="map(*)" mode="json-to-xml">
<xsl:for-each select="map:keys(.)">
<xsl:element name="{.}">
<xsl:apply-templates select="map:get(., .)" mode="json-to-xml"/>
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="array(*)" mode="json-to-xml">
<xsl:for-each select="?*">
<item>
<xsl:apply-templates select="." mode="json-to-xml"/>
</item>
</xsl:for-each>
</xsl:template>
<xsl:template match="xs:string | xs:double | xs:boolean" mode="json-to-xml">
<xsl:value-of select="."/>
</xsl:template>
✅ Требует
method="adaptive"или обработки черезxsl:sequence.
🔸 7.7 Отладка и профилирование
Встроенные средства:
<xsl:message terminate="no">Debug: {$var}</xsl:message><xsl:comment>Debug: <xsl:value-of select="$var"/></xsl:comment>trace($value, 'label')→ Saxon выводит в stderr:[label] value
Профилирование в Saxon:
java -cp saxon-he.jar net.sf.saxon.Transform \
-xsl:transform.xsl -s:input.xml -t --profile:profile.xml
Результат — XML-отчёт с временем выполнения каждого шаблона/функции.
Проверка потоковости:
java -cp saxon-ee.jar net.sf.saxon.Transform \
-xsl:transform.xsl -s:input.xml -val:strict --streaming:on
Saxon выдаст ошибку, если трансформация не streamable.
🔸 7.8 Оптимизация производительности
| Приём | Эффект | Примечание |
|---|---|---|
Использовать xsl:key вместо //book[@id=$id] | O(1) vs O(n) | Требует индекса в памяти. |
Избегать // в match и select | — | Особенно в streaming. |
Предпочитать xsl:sequence перед xsl:copy-of для нетипизированных данных | Меньше аллокаций | xsl:copy-of копирует узлы, xsl:sequence — передаёт ссылки/значения. |
Использовать tunnel="yes" вместо явной передачи параметров | Чистота кода | Нет overhead’а (Saxon оптимизирует). |
Статические параметры (static="yes") для use-when | Условная компиляция | Уменьшает размер скомпилированной таблицы. |
xsl:mode streamable="yes" + аккумуляторы | Память O(1) | Только Saxon-EE. |
Избегать disable-output-escaping="yes" | Безопасность, потоковость | Заменить на CDATA или character-map. |
Пример кэширования через saxon:memo-function:
<xsl:function name="my:expensive" saxon:memo-function="yes" as="xs:string">
<xsl:param name="input" as="xs:string"/>
<!-- дорогостоящее вычисление -->
</xsl:function>
⚠️ Мемоизация потребляет память — используйте для функций с малым числом уникальных аргументов.