XSLT 3.0: Современная обработка данных и миграция с версии 2.0

Курс детально рассматривает нововведения стандарта XSLT 3.0, акцентируя внимание на отличиях от версии 2.0 и методах повышения производительности. Студенты изучат потоковую обработку, работу с JSON и новые архитектурные подходы.

1. Введение в XSLT 3.0: Эволюция стандарта и фундаментальные отличия от версии 2.0

Введение в XSLT 3.0: Эволюция стандарта и фундаментальные отличия от версии 2.0

Приветствую вас, коллеги, на первом занятии нашего курса «XSLT 3.0: Современная обработка данных и миграция с версии 2.0». Сегодня мы начинаем погружение в мир современной трансформации данных. Если вы работали с XSLT 1.0 или 2.0, то знаете, насколько мощным может быть этот инструмент для манипуляции XML. Однако мир не стоит на месте: объемы данных растут, форматы меняются, и требования к производительности становятся всё жестче. Именно здесь на сцену выходит XSLT 3.0.

В этой вводной лекции мы разберем, почему появление третьей версии стало необходимостью, какие фундаментальные проблемы она решает и чем концептуально отличается от своего предшественника — версии 2.0.

Исторический контекст: От дерева к потоку

Чтобы понять величие XSLT 3.0, нужно кратко взглянуть на историю.

* XSLT 1.0 (1999) был революцией, позволившей превращать XML в HTML. Но у него были серьезные ограничения в обработке строк, дат и группировке. * XSLT 2.0 (2007) стал гигантским скачком вперед. Появилась строгая типизация, поддержка схем, мощные функции для работы с регулярными выражениями и датами. Это превратило XSLT из простого шаблонизатора в полноценный функциональный язык программирования.

Однако у версий 1.0 и 2.0 была общая архитектурная особенность, которая со временем стала их «ахиллесовой пятой»: модель обработки в памяти.

!Эволюция стандартов XSLT от обработки небольших деревьев до потоковой обработки и поддержки JSON.

Традиционный XSLT-процессор работает так: он считывает весь исходный документ, строит в оперативной памяти его полное дерево (DOM или аналогичную структуру), и только потом начинает применять шаблоны. Если ваш файл весит 10 МБ — это прекрасно работает. Если 100 МБ — приемлемо. Но если вам нужно обработать банковский лог размером 50 ГБ? Процессор просто «упадет» с ошибкой переполнения памяти (Out of Memory).

XSLT 3.0 (2017) был разработан W3C именно для решения этой проблемы, а также для интеграции с современным веб-стеком, где правит бал JSON.

Потоковая обработка (Streaming): Главный козырь

Самое значимое нововведение XSLT 3.0 — это Streaming (потоковая обработка). Это способность обрабатывать исходный документ по мере его чтения, не загружая его целиком в память.

Представьте, что вы хотите посмотреть фильм.

  • В модели XSLT 2.0 вам пришлось бы сначала скачать весь видеофайл на жесткий диск, и только после завершения загрузки начать просмотр.
  • В модели XSLT 3.0 вы смотрите фильм онлайн (стриминг): данные поступают пакетами, вы видите картинку, а уже просмотренные кадры выбрасываются из памяти.
  • В XSLT 3.0 это реализуется с помощью специального режима mode="streamable".

    Пример концепции в коде:

    Когда процессор встречает такую конструкцию, он понимает: «Я не должен хранить дерево документа. Я читаю элемент transaction, обрабатываю его, записываю результат и тут же забываю исходные данные, освобождая память для следующего элемента».

    Это позволяет обрабатывать файлы терабайтного размера на машине с скромным объемом оперативной памяти.

    Выход за пределы XML: Поддержка JSON и Maps

    Долгое время XSLT жил в изолированном мире XML. Если вам нужно было обработать JSON, приходилось конвертировать его в XML, обрабатывать, а потом (если нужно) конвертировать обратно. Это было неудобно и медленно.

    XSLT 3.0, работающий в связке с XPath 3.1, делает JSON «гражданином первого класса». Теперь вы можете:

  • Парсить JSON напрямую в структуры XDM (XQuery and XPath Data Model).
  • Создавать JSON на выходе.
  • Использовать Maps (ассоциативные массивы) и Arrays (массивы) внутри XSLT-кода как нативные типы данных.
  • !XSLT 3.0 как универсальный мост между мирами XML и JSON.

    Раньше для создания словаря (ключ-значение) в XSLT 2.0 нам приходилось создавать временные XML-деревья или использовать сложные ключи xsl:key. Теперь это выглядит так:

    Это фундаментально меняет подход к написанию кода, делая его ближе к современным языкам программирования вроде JavaScript или Python.

    Модульность и Пакеты (Packages)

    В XSLT 2.0 для повторного использования кода мы использовали xsl:import и xsl:include. Это работало, но имело недостатки: * Все импортируемые стили компилировались каждый раз вместе с основным стилем. * Не было надежного способа скрыть приватные функции или шаблоны библиотеки (инкапсуляция).

    XSLT 3.0 вводит понятие Пакетов (Packages).

    Пакет — это независимо компилируемый модуль. Вы можете скомпилировать библиотеку функций один раз и подключать её к тысячам разных преобразований без повторной компиляции. Кроме того, пакеты позволяют явно определять, какие функции и шаблоны являются публичными (доступными извне), а какие — приватными (внутренними).

    Это критически важно для разработки крупных корпоративных систем (Enterprise development), где над XSLT-кодом работают большие команды.

    Функции высшего порядка

    XSLT 3.0 окончательно утвердился как функциональный язык. Теперь функции являются значениями. Это означает, что: * Вы можете передавать функцию как аргумент в другую функцию. * Функция может возвращать другую функцию. * Вы можете создавать анонимные функции (лямбда-выражения) прямо в выражениях XPath.

    Пример использования функции сортировки:

    Здесь мы передаем анонимную функцию для вычисления ключа сортировки на лету. В версии 2.0 для этого потребовалось бы писать громоздкие именованные шаблоны.

    Сравнительная таблица: XSLT 2.0 vs XSLT 3.0

    Давайте подытожим основные отличия в виде таблицы для наглядности.

    | Характеристика | XSLT 2.0 | XSLT 3.0 | | :--- | :--- | :--- | | Модель памяти | Полное дерево в памяти (DOM) | Поддержка потоковой обработки (Streaming) | | Форматы данных | Только XML | XML, JSON, HTML5, Text | | Структуры данных | Последовательности (Sequences), Деревья | Последовательности, Деревья, Maps, Arrays | | Модульность | Import / Include | Packages (компилируемые модули) | | XPath | Версия 2.0 | Версия 3.0 / 3.1 | | Динамичность | xsl:evaluate (ограничено или расширениями) | xsl:evaluate (стандарт), динамический вызов функций | | Обработка ошибок | Базовая (xsl:message) | xsl:try / xsl:catch (перехват исключений) |

    Заключение

    Переход на XSLT 3.0 — это не просто обновление версии, это смена парадигмы. Если XSLT 2.0 был инструментом для трансформации XML-деревьев, то XSLT 3.0 стал мощным инструментом потоковой обработки данных любого формата.

    В следующих уроках мы будем детально разбирать каждый из этих аспектов. Мы научимся писать эффективные потоковые преобразования, работать с JSON-API и создавать модульные архитектуры.

    Готовьтесь, будет интересно. На следующем занятии мы настроим рабочее окружение и напишем наш первый скрипт на XSLT 3.0.

    2. Потоковая обработка данных: Использование xsl:stream для эффективной работы с гигантскими XML-файлами

    Потоковая обработка данных: Использование xsl:stream для эффективной работы с гигантскими XML-файлами

    Приветствую вас на втором занятии курса «XSLT 3.0: Современная обработка данных и миграция с версии 2.0». В прошлой лекции мы обсудили, что одной из главных проблем предыдущих версий XSLT была необходимость загружать весь документ в оперативную память перед началом обработки. Сегодня мы переходим к практике и детально разберем инструмент, который решает эту проблему раз и навсегда — потоковую обработку (Streaming).

    Мы научимся обрабатывать файлы размером в гигабайты и даже терабайты на обычном ноутбуке, используя инструкцию xsl:stream и новый режим обработки шаблонов.

    Проблема «Стены памяти»

    Давайте вспомним, как работает классический XSLT-процессор (версии 1.0 или 2.0). Когда вы запускаете трансформацию, происходит следующее:

  • Парсер читает XML-файл с диска.
  • В оперативной памяти строится дерево объектов (обычно DOM или аналогичная модель).
  • XSLT-процессор начинает применять шаблоны к этому дереву, свободно перемещаясь по нему вверх, вниз и в стороны.
  • Если ваш XML-файл весит 100 МБ, дерево в памяти может занимать 500 МБ и более. Это приемлемо. Но если вам нужно обработать выгрузку из базы данных весом 50 ГБ? Оперативная память закончится задолго до того, как дерево будет построено. Процесс аварийно завершится с ошибкой Out of Memory.

    С точки зрения теории алгоритмов, потребление памяти в классическом XSLT зависит от размера входного файла линейно:

    где — объем потребляемой памяти, — размер входного файла, а означает, что потребление ресурсов растет прямо пропорционально размеру входа.

    В XSLT 3.0 мы стремимся к константному потреблению памяти:

    где означает, что объем потребляемой памяти остается неизменным (константным) независимо от того, весит ли ваш файл 1 МБ или 1 ТБ.

    Концепция потоковой обработки

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

    !Визуализация принципа потоковой обработки: данные обрабатываются по мере поступления и сразу забываются.

    Ключевые правила потока:

  • Только вперед: Вы не можете вернуться к элементу, который уже прошел через процессор.
  • Ограниченный обзор: Вы не можете заглянуть далеко вперед, чтобы узнать, что будет в конце файла.
  • Немедленная забывчивость: Как только элемент обработан, он удаляется из памяти.
  • Инструкция xsl:stream

    В XSLT 3.0 точкой входа в потоковую обработку является инструкция xsl:stream. Она указывает процессору, что файл нужно читать потоково, а не загружать целиком.

    Синтаксис выглядит так:

    Обратите внимание на атрибут href. В отличие от функции doc(), которая загружает документ в память, xsl:stream гарантирует потоковое чтение.

    Однако одного xsl:stream недостаточно. Шаблоны, которые будут обрабатывать этот поток, должны быть явно помечены как потокобезопасные (streamable).

    Режим streamable="yes"

    Чтобы XSLT-процессор (например, Saxon-EE) разрешил обработку, вы должны объявить режим (mode) как потоковый:

    Это своего рода контракт. Вы обещаете процессору: «В этом режиме я буду писать код, который не нарушает правила потока». Если вы нарушите правила (например, попытаетесь обратиться к preceding-sibling::*), компилятор выдаст ошибку еще до запуска трансформации.

    Пример: Фильтрация транзакций

    Представьте, у нас есть файл transactions.xml весом 20 ГБ:

    Наша задача: выбрать только транзакции в валюте EUR и сохранить их в новый файл.

    Решение на XSLT 3.0:

    Что здесь происходит?

  • Процессор начинает читать transactions.xml.
  • Встречает <bank-log>, заходит внутрь.
  • Встречает <transaction>. Проверяет атрибут @currency.
  • Если это EUR, он копирует элемент в выходной поток.
  • Важно: Сразу после завершения шаблона данные этой транзакции удаляются из памяти. Память освобождается для следующей транзакции.
  • Ограничения и «Позы» (Postures)

    Самая сложная часть освоения XSLT 3.0 — понимание того, какие выражения XPath допустимы в потоке, а какие нет. W3C спецификация вводит понятие Sweep (Размах) и Posture (Поза).

    Не углубляясь в сухую теорию, запомните главные ограничения внутри потокового шаблона:

  • Запрет на оси «назад»: Нельзя использовать parent::, ancestor::, preceding::, preceding-sibling::. Вы не можете спросить «кто был моим соседом сверху?», потому что сосед уже «уехал» по конвейеру.
  • Ограничение на оси «вниз»: Вы можете спускаться вниз (child::, descendant::), но только один раз за проход. Если вы сделали xsl:value-of select="description", вы «потратили» этот кусок потока. Вы не можете потом написать xsl:value-of select="price", если price шел в XML после description.
  • Чтобы обойти ограничение на порядок элементов внутри узла, часто используют xsl:copy-of select=".", который забирает весь поддерево в память (если оно небольшое, например, одна транзакция), и уже внутри копии можно работать как обычно.

    xsl:accumulator: Как помнить прошлое?

    Если мы не можем смотреть назад, как нам, например, посчитать общую сумму транзакций или пронумеровать их?

    Для этого в XSLT 3.0 введены Аккумуляторы (Accumulators). Это специальные объекты, которые живут вне потока и могут накапливать состояние.

    Пример подсчета общей суммы:

    ``xml <!-- Объявляем аккумулятор --> <xsl:accumulator name="total-amount" initial-value="0" streamable="yes"> <!-- Правило: при встрече transaction добавляем её amount к текущему значению --> <xsl:accumulator-rule match="transaction" select="value — это текущее накопленное значение аккумулятора. Мы обновляем его на лету, не сохраняя сами транзакции в памяти.

    Когда использовать потоковую обработку?

    Не нужно использовать xsl:stream везде. Это мощный инструмент, но он накладывает строгие ограничения на стиль кодирования.

    Используйте Streaming, если: * Размер входного файла превышает 100-200 МБ. * Размер файла потенциально не ограничен (логи, потоки событий). * Вам нужно выполнить простую трансформацию (фильтрация, агрегация, конвертация формата).

    Не используйте Streaming, если: * Файл маленький (конфиги, небольшие документы). * Логика требует сложного доступа к данным (например, «найти элемент, у которого есть брат, описанный в конце файла»).

    Заключение

    Потоковая обработка в XSLT 3.0 — это инженерный прорыв, позволяющий обрабатывать данные промышленного масштаба. Используя xsl:stream и xsl:accumulator, вы можете создавать высокопроизводительные приложения, потребляющие минимум памяти.

    В следующей статье мы отойдем от чистого XML и рассмотрим, как XSLT 3.0 научился работать с форматом, который захватил современный веб — JSON. Мы научимся преобразовывать JSON в XML и обратно, используя карты (Maps) и массивы (Arrays).

    3. Расширенные возможности XPath 3.1: Работа с картами, массивами и функциями высшего порядка

    Расширенные возможности XPath 3.1: Работа с картами, массивами и функциями высшего порядка

    Приветствую вас на третьем занятии курса «XSLT 3.0: Современная обработка данных и миграция с версии 2.0». В предыдущих лекциях мы рассмотрели архитектурные изменения XSLT 3.0 и революционную возможность потоковой обработки. Сегодня мы спустимся на уровень ниже и изучим двигатель, который приводит всё это в движение — язык выражений XPath 3.1.

    Многие разработчики ошибочно полагают, что XSLT 3.0 — это просто новые теги xsl:. На самом деле, 80% мощи новой версии кроется именно в расширении системы типов XPath. Если в версии 2.0 мы были ограничены последовательностями узлов и атомарными значениями, то XPath 3.1 превращает XSLT в полноценный язык для работы со сложными структурами данных, включая JSON.

    Сегодня мы разберем три кита современной обработки данных в XSLT: Карты (Maps), Массивы (Arrays) и Функции высшего порядка.

    Карты (Maps): Конец эры «временных деревьев»

    В XSLT 2.0, если вам нужно было создать структуру «ключ-значение» (например, словарь для перевода кодов ошибок в текст), вы обычно создавали переменную с XML-структурой, а затем использовали xsl:key или циклы для поиска. Это было громоздко и неэффективно по памяти.

    XPath 3.1 вводит нативный тип данных Map (Карта). Это функция, которая сопоставляет ключи значениям.

    Создание и использование

    Синтаксис создания карты напоминает JSON, но с ключевым словом map:

    Обратите внимание на оператор ?. Это оператор поиска (lookup operator). Выражение key := 'role' return key) xpath let matrix?2?1 xml <xsl:variable name="json-str" select="'{ &quot;users&quot;: [ {&quot;id&quot;: 1}, {&quot;id&quot;: 2} ] }'"/> <xsl:variable name="data" select="parse-json(data?users?2?id"/> xpath tokenize(normalize-space(upper-case(text => upper-case() => normalize-space() => tokenize(' ') xpath let x) { x } return Sii^2accumulator, accumulator + (current) }) xpath let orders?* (: 1. Преобразуем массив в последовательность карт :) => filter(function(o?total > 1000 }) (: 2. Фильтруем :) => for-each(function(o?id }) (: 3. Извлекаем ID :) `

    Результатом будет последовательность (102, 103).

    Заключение

    XPath 3.1 превращает XSLT из узкоспециализированного инструмента в мощный язык обработки данных.

  • Maps дают быстрый доступ по ключу.
  • Arrays позволяют сохранять структуру вложенности.
  • Функции высшего порядка и оператор =>` делают код чистым, декларативным и легко читаемым.
  • Освоив эти инструменты, вы сможете писать код, который не только работает быстрее, но и гораздо проще в поддержке, чем громоздкие конструкции XSLT 2.0.

    В следующей статье мы вернемся к архитектуре XSLT и разберем Пакеты (Packages) — механизм, позволяющий создавать переиспользуемые библиотеки и скрывать детали реализации, что критически важно для крупных проектов.

    4. Интероперабельность: Преобразование JSON в XML и обратно, работа с текстовыми данными

    Интероперабельность: Преобразование JSON в XML и обратно, работа с текстовыми данными

    Приветствую вас, коллеги, на четвертом занятии курса «XSLT 3.0: Современная обработка данных и миграция с версии 2.0». В предыдущих лекциях мы совершили прорыв: научились обрабатывать гигантские файлы в потоковом режиме и освоили новые типы данных XPath 3.1 — карты (Maps) и массивы (Arrays).

    Сегодня мы соберем эти знания воедино, чтобы решить одну из самых актуальных задач современной разработки — интероперабельность. Мы живем в гибридном мире. Ваши системы могут получать конфигурацию в JSON, данные в XML, а логи в формате CSV. XSLT 3.0 выступает здесь как универсальный «клей», способный трансформировать любой текстовый формат в любой другой.

    Два пути обработки JSON

    Когда мы говорим о работе с JSON в XSLT 3.0, важно понимать, что у нас есть две принципиально разные стратегии. Выбор зависит от того, как вы привыкли писать код.

    !Визуализация двух стратегий парсинга JSON: преобразование в нативные структуры XDM или в виртуальное XML-дерево.

    Стратегия 1: Нативные структуры (parse-json)

    Эту стратегию мы затрагивали в прошлой лекции. Функция parse-json() превращает строку JSON в иерархию карт и массивов.

    Плюсы: * Высокая производительность. * Естественный синтаксис доступа через ? (например, tokens[1]}"> <name><xsl:value-of select="tokens[3]"/></role> </user> </xsl:for-each> </users> </xsl:template> json { "payload": "&lt;order&gt;&lt;id&gt;555&lt;/id&gt;&lt;/order&gt;" } xpath let input) let json?payload let xml-string) return NT(N)O(N)O(N^2)$.

    Заключение

    Мы рассмотрели, как XSLT 3.0 стирает границы между форматами данных.

  • JSON теперь является «гражданином первого класса» благодаря parse-json и xml-to-json.
  • Текстовые данные эффективно обрабатываются через unparsed-text-lines.
  • Генерация JSON стала декларативной и безопасной с помощью xsl:map и xsl:array`.
  • Теперь вы обладаете полным набором инструментов для создания сложных интеграционных шлюзов. В следующей, заключительной статье нашего цикла, мы поговорим о Пакетах (Packages) — механизме, который позволит вам упаковывать ваши наработки в переиспользуемые библиотеки и строить модульную архитектуру приложений.

    До встречи на финальном занятии!

    5. Архитектура и практика: Использование пакетов (Packages) и динамическое выполнение преобразований

    Архитектура и практика: Использование пакетов (Packages) и динамическое выполнение преобразований

    Приветствую вас, коллеги, на финальном занятии нашего курса «XSLT 3.0: Современная обработка данных и миграция с версии 2.0». Мы прошли долгий путь: от понимания потоковой обработки гигабайтных файлов до манипуляции JSON-структурами и использования лямбда-функций.

    Сегодня мы поднимемся на самый высокий уровень абстракции — архитектурный. Мы поговорим о том, как строить большие, поддерживаемые и модульные системы с помощью Пакетов (Packages), и как добавить гибкости вашим приложениям с помощью динамического выполнения кода через xsl:evaluate.

    Если вы когда-либо работали над проектом, где XSLT-файл разрастался до 5000 строк, или пытались управлять зависимостями через бесконечные xsl:import, эта лекция для вас.

    Проблема монолита в XSLT 2.0

    В версиях 1.0 и 2.0 механизмы повторного использования кода ограничивались инструкциями xsl:include и xsl:import. Хотя они выполняли свою функцию, у них были фундаментальные архитектурные недостатки:

  • Отсутствие инкапсуляции: Все переменные, функции и шаблоны из импортируемого файла становились видимыми в основном файле. Нельзя было создать «приватную» вспомогательную функцию.
  • Конфликты имен: Если две разные библиотеки определяли шаблон с одинаковым именем или match, возникали коллизии, которые приходилось решать через приоритеты (priority).
  • Время компиляции: При каждом запуске трансформации процессор должен был заново компилировать всё дерево импортов. Для больших систем это занимало секунды, что недопустимо для высоконагруженных сервисов.
  • Пакеты (Packages): Новый стандарт модульности

    XSLT 3.0 вводит концепцию Пакетов. Пакет — это единица компиляции. Это означает, что вы можете скомпилировать библиотеку один раз, сохранить её в бинарном или промежуточном формате (например, .ef в Saxon) и подключать к тысячам трансформаций без накладных расходов на парсинг исходного кода.

    !Визуализация принципа инкапсуляции: публичные компоненты доступны извне, приватные — скрыты внутри пакета.

    Объявление пакета

    Вместо корневого элемента xsl:stylesheet, мы используем xsl:package:

    Ключевые атрибуты: * name: Уникальный URI, идентифицирующий пакет. * package-version: Версия вашей библиотеки (полезно для управления зависимостями).

    Управление видимостью (Visibility)

    По умолчанию всё, что вы пишете внутри пакета, является приватным. Чтобы сделать функцию или шаблон доступным для внешнего мира, нужно явно объявить их через xsl:expose.

    Это позволяет разработчикам библиотек менять внутреннюю реализацию (my:internal-calc), не ломая код пользователей, которые используют my:public-api.

    Подключение пакета

    В основном файле мы используем xsl:use-package вместо xsl:import:

    Абстракция и Переопределение (Override)

    Пакеты привносят в XSLT элементы объектно-ориентированного программирования. Вы можете создавать абстрактные компоненты — шаблоны или функции, которые объявлены в библиотеке, но не имеют реализации. Пакет, использующий библиотеку, обязан предоставить реализацию.

    Это идеально подходит для создания фреймворков. Например, вы пишете логику обхода сложного документа, но рендеринг конкретных узлов оставляете на усмотрение пользователя пакета.

    В использующем коде мы переопределяем этот компонент:

    Математика эффективности компиляции

    Почему пакеты так важны для производительности? Рассмотрим упрощенную модель времени компиляции.

    В XSLT 2.0 при использовании монолитного подхода или xsl:import, время компиляции для каждого запроса можно выразить как:

    Где: * — общее время, затрачиваемое процессором на подготовку к запуску. * — время компиляции основного файла. * — количество подключаемых библиотек. * — время компиляции -й библиотеки.

    Даже если библиотеки не менялись, процессор тратит ресурсы на их разбор.

    В XSLT 3.0 с использованием прекомпилированных пакетов формула меняется:

    Где — время линковки (связывания) уже готового бинарного кода пакета. Обычно (время линковки много меньше времени компиляции). Это обеспечивает мгновенный старт приложений даже с огромной кодовой базой.

    Динамическое выполнение: xsl:evaluate

    Второй герой нашей лекции — инструкция xsl:evaluate.

    В XSLT 2.0, если вам нужно было выполнить XPath-выражение, которое приходит в виде строки (например, из конфигурационного файла или пользовательского ввода), вам приходилось использовать проприетарные расширения (например, saxon:evaluate). В XSLT 3.0 это стало стандартом.

    Синтаксис и применение

    В блоке xsl:catch доступны специальные переменные (в пространстве имен http://www.w3.org/2005/xqt-errors): * err:description — текстовое описание. * $err:value — значение, связанное с ошибкой (если есть).

    Заключение курса

    Коллеги, мы завершаем наш курс «XSLT 3.0: Современная обработка данных».

    Давайте оглянемся назад. Мы начали с того, что XSLT 3.0 — это не просто обновление, а смена парадигмы. Мы научились:

  • Использовать Streaming для работы с данными любого объема.
  • Применять Maps, Arrays и JSON для интеграции с современным вебом.
  • Писать чистый код с функциями высшего порядка.
  • Строить модульные приложения с помощью Packages.
  • XSLT 3.0 сегодня — это мощный, функциональный язык программирования, способный решать задачи Enterprise-уровня. Я надеюсь, что инструменты, которые вы получили на этом курсе, помогут вам создавать эффективные и элегантные решения.

    Спасибо за внимание, и удачи в коде!