Разное

Язык трансформации XSL. Условные операторы XSL и вызов параметризованного шаблона

Язык трансформации XSL. Условные операторы XSL и вызов параметризованного шаблона

Альтернативное введение в использование XSL Transformations в PHP при помощи Sablotron.

Данный материал следует воспринимать как альтернативное введение в использование XSLT с Sablotron в PHP.

Термины XSL и XSLT близки друг к другу, и новичкам их можно считать синонимами. Подробности, в чём же различия, описаны в спецификации XSL Transformations W3C.

Все, кто интересовался возможностями XSLT, читал стандартный пример из мануала, либо примеры, приводимые в статьях, посвящённых XSLT, на разных сайтах. Работающий пример из этой же серии:

Railroad Tycoon II Platinum экономическая стратегия PopTop software G.O.D. games 2001 Grand Prix 4 автосимулятор Geoff Crammond & Simergy Infogrames Entertainment 2002 "; $xslData = " Игры

Игры

Название жанр год разработчик издатель
"; $xh = xslt_create(); $arguments = array("/_xml" => $xmlData, "/_xsl" => $xslData); $result = @xslt_process($xh, "arg:/_xml", "arg:/_xsl", NULL, $arguments); if ($result) print ($result); else { print ("There was an error that occurred in the XSL transformation...n"); print ("tError number: " . xslt_errno($xh) . "n"); print ("tError string: " . xslt_error($xh) . "n"); exit; } ?>

Подобных примеров в Сети полно. Все они хорошо показывают, что XSL-трансформация в php работает, но после их прочтения остаётся неясным, зачем XSL нужен, скорее даже наоборот - почему XSL не нужен.

"Действительно", - подумает читатель, - "если данные лежат в базе, зачем городить огород, формируя сперва XML, а затем ещё преобразовывать через XSL? С тем же успехом это сделает класс HTML-шаблона."

После этого разочарованный программист напрочь теряет интерес к XSL и вешает на технологию ярлык "ненужная заумь".

Вам, уважаемые читатели, повезло найти такой замечательный сайт, как "php в деталях". Здесь вы прочитаете о том, что XSL может не только преобразовывать XML в HTML, но и то, как можно при помощи XSL облегчить работу с php-скриптами.

Начало работы

Приведённый выше пример, хоть и слишком прост, хорошо иллюстрирует, каким образом делается XSL-преобразование в php.

Чтобы этот код работал, нужно установить XSLT-процессор Sablotron. На виндовой машине это делается так:

1. положить iconv(-1.3).dll, expat.dll и sablot.dll в C:windowsSystem (все файлы есть в стандартном дистрибутиве php)
2. открыть C:windowsphp.ini и в нём найти параметр extension_dir. Если значение параметра - "." или нечто вроде "./", исправить на, скажем, "f:usrlocalphpextension" (или адрес директории, в которой у вас лежат/будут лежать расширения php). Теперь это будет директория расширений php.
3. положить в директорию расширений файл php_xslt.dll (это для php версии 4.2.x), либо php_sablot.dll (для версии 4.0.x)
4. в php.ini раскомментируйте строчку extension=php_xslt.dll (4.2.x) или extension=php_sablot.dll (4.0.x)

Теория

Использование XSLT позволяет отделить от php-скриптов работу по форматированию и представлению данных. Это не только уменьшение объёма кода, но и вынос большого количества логических конструкций (if, else, switch), а следовательно, облегчение работы по написанию и отладке программ. Смею утверждать, что тот, кто не пробовал работать с XSLT, не представляет себе, насколько php-кодирование облегчится.

Впрочем, не надо обольщаться: если у вас было несколько конструкций if … else в php-скрипте, они, скорее всего, появятся в том же количестве в XSL-файле.

Теперь к примерам.

Вывод списков

Все усложнения, происходящие от необходимости выводить список в удобочитаемом виде, переносятся на плечи XSL. Пример #2. Список статей на сайте с подсветкой статьи, которую читают сейчас, чередование цвета в строках и нумерация списка.

2002-05-30 Ловля ошибок в PHP Живой проект и мёртвый журнал Работа с MySQL. Часть 7. Деревья Ручная сортировка в веб-интерфейсе Как поладить дизайнеру с программистом Relax this is PHP

...

... #cccccc <

Произвольная разметка

Переводя на XML сайт с текстами (как этот), естественно хотеть сделать собственную разметку статей. Например, в контейнером important выделять очень важные места и иметь возможность выделять их не обязательно жирным шрифтом, но, может быть, цветом, CSS-стилем. Или писать цитаты как текст цитаты и иметь возможность менять стиль их оформления вместе с дизайном сайта.

Медленно продвигаясь от самого простого первого примера, многие натыкаются на эту проблему и не могут найти решения. Ведь если выделить абзац в тег И делать для него шаблон, на первый взгляд, существуют три способа вывода содержимого:

1. тег xsl:value-of выводит текст, но удаляет все теги в абзаце
2 .тег xsl:copy-of выводит копию всего содержимого (без возможности применять шаблоны к детям - внутренним тегам) и самого контейнера (что не очень красиво в HTML).
3. наконец, xsl:apply-templates применит шаблоны к детям, но пропустит текст

Проблема кажется безвыходной, но решение есть. Я использую "магические" шаблоны, которые выводят и текст и теги в нём со всеми атрибутами и без изменений. Пример #3:

Данный пример использует магические шаблоны для разбора произвольной разметки. Это позволяет избежать таких жалоб: Люди, памажите сами мы не местные! Не могу вывести теги в тексте при помощи value-of!


Запомните эти шаблоны раз и навсегда! Тогда вы сможете обрабатывать любой текст Почти любой.

Первым делом XSLT-процессор при вызове инструкции apply-templates ищет шаблон для каждого элемента. Для элемента strong шаблон есть, и именно в соответствии с ним такие элементы будут обработаны. Для гиперссылки шаблона нет, поэтому она будет выведена, как есть. Можно добавить в XSL шаблон и для ссылки, который бы выводил рядом с каждой текстовой ссылкой картинку для открытия её в новом окне:

* в шаблоне использован параметр match="a[@href]" - этот шаблон будет применён только к тем тегам ссылок, в которых есть поле href и пропустит якоря ().

Невалидный код и

Кажущаяся необходимость писать валидный XML-код так же отпугивает многих неофитов XSLT. Хорошо, с завтрашнего дня будем писать статьи только валидно, благо дома можно проверить, нет ли в тексте XML-ошибки - mismatched tag или invalid token, - с этим как-нибудь справимся. Но ведь, по-хорошему, нужно и весь архив перевести в валидный код! И я так тоже думал, когда появилась возможность переделывать сайт на XML.

Решение проблемы довольно простое: не хочешь - не пиши валидно. Пиши, как привык, - без кавычек в атрибутах тегов, используй простой
и прочее. Достаточно заключить текст в контейнер (пример ниже).

Что касается, то здесь дела такие: элемента nbsp в XML нет. Есть lt, gt, quot, но не nbsp (вполне логично - это ведь non-braking space, который относится к форматированию и придуман для HTML). Поэтому его нужно объявить в документе, либо использовать только внутри .

Пример #4:

Люди, памажите, сами мы не местные!


Запомните и эти шаблоны тоже!

Очень удобно! Большие изменения в архив вносить не придётся. Можно начать писать валидно, а продолжать как попало. А можно комбинировать эти два подхода. Чтобы не писать в архивные файлы тег CDATA, я сделал простое преобразование при помощи регулярных выражений (важно так же помнить, что один тег CDATA не должен содержать в себе другой).

$doc = preg_replace("~<(p|h|pre)>(.*?)~", "<\1>\2", $doc);

Циклы

Допустим, нам нужно сделать форму для редактирования статьи, в том числе её даты. Для удобства пользования надо сделать три раскрывающихся списка (далее - "крутилки") - дата от 1 до 31, месяц, год. Первое решение, которое приходит в голову - сделать HTML-код крутилок в php, вставить в XML в контейнере CDATA, а затем вывести в XSL с параметром disable-output-escaping="yes".

На самом деле, XSLT может и это. Достаточно вставить в данные XML число, номер месяца и год. Крутилки можно нарисовать сразу в XSLT.

Напишем шаблон, не предназначенный ни для какого элемента документа. Он будет вызываться командой xsl:call-template и получать два параметра: значение счётчика и максимум. Сперва он будет выводить нужные нам данные со значением счётчика, затем вызывать самого себя с параметрами максимум и счётчик, увеличенный на 1. Пример #5:

Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь

... 7 10 2002

... ...

Оставляю вам в качестве домашнего задания шаблон для вывода крутилки с годом.

Аннотация: Рассматривается генерация кода преобразованиями XSLT. Изучается синтаксис XSLT, особенности применения преобразований, а также выполнение таких операций, как фильтрация, сортировка, выборка по условию в шаблонах. Выполнение трансформации программным путем в C#. Преимущества и недостатки технологии.

Язык преобразований XSLT

Во второй лекции мы уже рассматривали пример с использованием XSLT . В этой лекции мы рассмотрим эту технологию более подробно. XSL (eXtensible Stylesheet Language) переводится как Расширяемый Язык Стилей, и представляет собой язык для создания стилей XML документов. XSLT(XSL Transformations) - это язык преобразований XSL и является его частью. Стиль XSLT предназначен для преобразования иерархической структуры и формата документа XML . Результатами преобразования могут стать XML - файл , текстовый файл , программный код, HTML - файл , файл в формате PDF , и так далее. Этот язык предоставляет мощные возможности для манипуляции данными, информацией, текстом в иерархическом виде.

А это как раз то, что нужно для генерации кода. Применение XSLT может существенно помочь в генерации кода. Кроме того, он предоставляет удобную альтернативу технологии шаблонов Т4.

XSLT был разработан консорциумом W3C (World Wide Web Consortium) . Первая версия языка XSLT 1.0 стала рекомендацией 16 ноября 1999 года, а версия XSLT 2.0 стала рекомендацией 23 января 2007 года. Обе версии используются достаточно активно, и в этой лекции мы рассмотрим ту базовую функциональность, которая является для них общей. А это значит, что рассматривать будем в основном первую версию. Также упомянем некоторые команды из второй версии.

Как работает XSLT

Модель XSLT включает в себя такие части как:

  • документы XML,
  • стили XSLT ,
  • процессор XSLT ,
  • выходные документы.

Документы XML являются входными данными, которые нужно преобразовать в другие документы. Документ стиля XSLT является корректным (well formed) документом XML и содержит набор правил для выполнения преобразования. Иными словами, документ стиля является шаблоном.

Процессор XSLT является приложением, которое принимает в качестве входных данных документы XML и стили XSLT . Он выполняет трансформацию, то есть применение набора правил в стилях XSLT к документам XML . Результатом этой работы являются выходные документы .

Процессоры XSLT имеют множество реализаций и встроены во многие браузеры вроде Internet Explorer, Firefox, Mozilla, Opera и другие. В Internet Explorer используется инструмент MSXML, разработанный Microsoft. XSLT - процессор встроен в Internet Explorer, начиная с версии 4.5. Сгенерированный результат примеров данной лекции можно просматривать путем открытия XML -файлов в одном из браузеров. В конце лекции мы рассмотрим возможности запуска трансформации программным путем, используя соответствующие классы языка программирования.

XPath

Другой частью технологии XSL является язык XPath , предназначенный для доступа к узлам документа XML путем задания путей и выражений. Язык Xpath используется в файлах стилей для навигации внутри XML -документов, определения частей исходного XML -документа, которые совпадают с одним или более заранее заданными шаблонами. При нахождении совпадения процессор XSLT применит к нему соответствующие правила из файла стиля и преобразует его в часть результирующего документа. В файлах стилей XSLT выражения XPath используются весьма интенсивно.

Применение XSLT

Язык XSLT состоит из множества инструкций, записанных в виде тегов. Имя каждой инструкции обычно начинается с символов xsl . Для выполнения трансформации документ стиля XSLT должен являться корректным документом XML .

Для преобразования документа XML необходимо добавить в начало документа инструкцию, подобную следующей:

XSL - файл стилей обычно содержит множество элементов, самым главным из которых является элемент xsl :stylesheet . Именно он указывает, что данный XML - файл является файлом стилей. Кроме него могут содержаться другие элементы, например xsl :template , xsl :value-of . Документ XML и файл стиля передается в XSLT - процессор , который обрабатывает данные файлы, выполняет преобразование и выводит результат трансформации.

Ниже представлен документ XML , содержащий список языков программирования.

C# Visual Basic Delphi Prolog Пример 5.1. Файл languages.xml

Необходимо вывести этот список в формате HTML . Для этой цели используем инструкцию xsl :for-each , которая будет применять часть шаблона к секциям документа, наименование которых указано в атрибуте select . В нашем случае укажем select="languages/language" .

Файл стилей будет применяться следующий:

Мои любимые языки:

-

Пример 5.2. Файл languages.xsl

Шаблон внутри xsl :for-each выводит содержимое каждого элемента language из languages . Для этой цели используется инструкция xsl :value-of и задаваемый атрибут select="." . Это означает, что процессор должен выбирать текст содержимого текущего элемента в документе. Кроме отражения содержимого можно задавать имена конкретных тегов, а также атрибутов для выборки значений, хранящихся в них. Примеры будут рассмотрены далее.

Откроем XML файл через Internet Explorer или другой браузер . Будет выведен такой текст:

Мои любимые языки:

  • Visual Basic
  • Delphi
  • Prolog

Одним из самых главных элементов в стиле является xsl :template . Служит для определения повторно используемого шаблона и содержит правила, по которым будет преобразован документ XML . В атрибуте match содержится выражение для отбора узлов, к которым будет применен шаблон . Также может присутствовать атрибут name . В этом случае есть возможность вызывать шаблон по имени инструкцией xsl :apply-templates .

Для повторения вывода шаблона для каждого элемента документа применяется инструкция xsl :for-each . Шаблон выполняется для каждого элемента, соответствующего условию, указанному в атрибуте select .

Инструкция xsl :value-of служит для вычисления выражения, записанного в атрибуте select с последующим выводом результата в том месте, где расположен сам элемент.

Фильтрация

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

Один из них - это применение атрибута select инструкции xsl :for-each , а второй - применение атрибута match элемента xsl :template . Применение match мы рассмотрим позже, а сейчас рассмотрим select .

Изменим немного файл с данными: добавим атрибут high , обозначающий, является ли язык из нашего списка языком высокого уровня. Также расширим сам список языков.

C# Visual Basic Delphi Prolog Assembler Java Perl Пример 5.3. Файл languages4.xml

Заметим, что значение false для атрибута high стоит только для значения "Assembler" . Изменим немного файл таблицы стилей:

Языки высокого уровня:

-
Пример 5.4. Файл languages4.xsl

В секции [@ high ="true"] мы указываем, что выбирать следует только те узлы документа, у которых атрибут high имеет значение "true" . Знак @ является символом, указывающим на то, что после него стоит имя атрибута.

Посмотрим на результат:

Языки высокого уровня:

  • Visual Basic
  • Delphi
  • Prolog

Как видим, значение "Assembler" не отображается в списке языков, то есть процессор XSLT отфильтровал данные согласно заданным условиям.

Сортировка

Кроме фильтрации другой часто применяемой операцией при генерации кода является сортировка . Атрибут order-by инструкции xsl :for-each служит для сортировки результата, для обозначения порядка прохода узлов документа при выполнении трансформации. Сортируемые поля перечисляются через точку с запятой, а также имеют перед своим названием знаки "+" или "-" , означающие сортировку по возрастанию или убыванию.

Рассмотрим немного измененный вариант документа - вместо атрибута high будем использовать элемент level , принимающий значения high или low . А имя языка запишем в элемент name .

C# high Visual Basic high Delphi high Prolog high Assembler low Java high Perl high Пример 5.5. Файл languages6.xml

В следующей таблице стилей для инструкции xsl :for-each применим атрибут order-by со значением +name , где знак плюса означает, что надо отсортировать по возрастанию.

Языки высокого уровня:

-
Пример 5.6. Файл languages6.xsl

В атрибуте select мы фильтруем по значению элемента level . Также в атрибуте select инструкции

Преобразования из XML в XML

Преобразования XML-XML иногда рассматриваются как SQL для Интернета, поскольку они позволяют оперировать запросами к базе данных в XML-документах. Ниже приведен пример. Используемый нами файл planets.xml содержит достаточно много данных о каждой планете:

Mercury

.0553

58.65

1516

.983

43.4

Venus

.815

116.75

3716

.943

66.8

Что, если нам нужно только подмножество этих данных - например, имя и масса каждой планеты? В терминах баз данных planets.xml представляет собой таблицу, и мы хотим создать новую таблицу, содержащую подмножество данных из первой. В базах данных для этого служит язык SQL, а для документов XML мы можем использовать XSLT.

В листинге 1.6 приведена новая версия файла planets.xsl , осуществляющая требуемое преобразование: выбираются только имя и масса каждой планеты, которые отправляются в выходной документ. В особенности обратите внимание на то, что мы осуществляем преобразование XML-XML, поэтому я использую элемент , атрибут method которого установлен в «xml» (фактически тип выходных данных обычно и есть XML, но если процессор XSLT видит тег , он обычно по умолчанию генерирует HTML).

Листинг 1.6. Выбор только имени и массы

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

C:planets>java org.apache.xalan.xslt.Process -IN planets.xml -XSL planets.xsl -OUT new.xml

Вот как выглядит результирующий документ XML, new.xml:

Mercury

.0553(Earth = 1)

Venus

.815(Earth = 1)

Earth

1(Earth = 1)

Отметьте, что этот файл выглядит во многом похоже на исходный файл planets.xml , за тем исключением, что каждый элемент Содержит только элементы и . Таким образом, мы смогли получить подмножество данных первоначального документа XML.

Конечно, можно проводить любое число такого рода преобразований XML-XML. Можно обрабатывать данные в документе XML для создания совершенно новых XML-документов. Например, можно взять XML-документ с именами студентов и их отметками и создать новый документ, отображающий средние оценки. В XSLT есть много встроенных функций, позволяющих работать с данными подобным образом, - мы познакомимся с ними в главе 8.

В дополнение следует сказать, что многие программы используют XML для обмена данными в Интернете, и, так как обычно они форматируют свои документы XML по-разному, еще одним популярным способом использования преобразований XML-XML в Интернете является преобразование XML из формата, используемого одной программой, в формат другой программы.

Из книги C++ автора Хилл Мюррей

8.5.6 Преобразования Конструктор, получающий один параметр, определяет преоразование из типа своего параметра в тип своего класса. Такие преобразования неявно применяются дополнительно к стандартным пробразованиям (#6.6-7). Поэтому присваивание объекту из класса X

Из книги Справочное руководство по C++ автора Страустрап Бьярн

R.4.7 Преобразования ссылок Всюду, где ссылки (§R.8.2.2) инициализируются (включая передачу параметров (§R.5.2.2) и возврат значения функции (§R.6.6.3)) или используются иным образом, возможны следующие преобразования:Ссылка на данный класс может быть преобразована в ссылку на

Из книги Советы по Delphi. Версия 1.0.6 автора Озеров Валентин

R.12.3 Преобразования Преобразования объектов класса можно задать с помощью конструкторов или функций преобразования.Такие преобразования, обычно называемые пользовательскими, используются неявно в совокупности со стандартными преобразованиями (§R.4). Например, функцию

автора Реймонд Эрик Стивен

R.12.3.2 Функции преобразования Функция-член класса X, имя которой имеет вид,имя-функции-преобразования: operator имя-типа-преобразованияимя-типа-преобразования: список-спецификаций-типа opt операция-ptr optзадает преобразование из типа X в тип, определяемый конструкцией

Из книги Искусство программирования для Unix автора Реймонд Эрик Стивен

Из книги HTML 5, CSS 3 и Web 2.0. Разработка современных Web-сайтов. автора Дронов Владимир

Из книги XSLT автора Хольцнер Стивен

18.5.4. Средства преобразования Вторая крупнейшая проблема, связанная с DocBook, состоит в необходимости преобразования старой разметки уровня представления в разметку DocBook. Человек обычно может автоматически преобразовать представление документа в логическую структуру,

Из книги Технология XSLT автора Валиков Алексей Николаевич

Преобразования CSS В главе 22, ведя разговор о канве и программном рисовании на ней, мы узнали о преобразованиях системы координат. С помощью особых расширений CSS мы можем проделать аналогичные действия над любым элементом Web-страницы: сместить его, повернуть, растянуть или

Из книги Язык программирования Си для персонального компьютера автора Бочков C. О.

Преобразования из XML в XML Преобразования XML-XML иногда рассматриваются как SQL для Интернета, поскольку они позволяют оперировать запросами к базе данных в XML-документах. Ниже приведен пример. Используемый нами файл planets.xml содержит достаточно много данных о каждой

Из книги Macromedia Flash Professional 8. Графика и анимация автора Дронов В. А.

Модель преобразования Во вводной главе мы говорили, что преобразования в XSLT являются наборами шаблонных правил, каждое из которых обрабатывает определенный фрагмент входящего документа с тем, чтобы сгенерировать фрагмент выходящего

Из книги автора

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

Из книги автора

Выполнение преобразования Несмотря на полную свободу в порядке выполнения шаблонов, правила изменения контекста и компоновки результирующего дерева, спецификация XSLT оговаривает очень четко - это делает XSLT весьма гибким языком, программы на котором при этом

Из книги автора

Упрощенные преобразования Многие простые преобразования состоят из единственного правила, которое обрабатывает корневой узел входящего документа. Общий вид такого рода преобразований показан в следующем листинге.Листинг 4.2. Простое

Из книги автора

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

Из книги автора

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

Из книги автора

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

После того как вы загрузили, выполнили синтаксический разбор или каким_то другим способом получили объект Document, представляющий XML_документ, одно из самых интереснейших действий, которые можно с ним выполнить, – это преобразовать документ с помощью таблицы XSLT_стилей. Аббревиатура XSLT происходит от XSL Transformations (XSL_преобразования), а XSL – от Extensible Stylesheet Language (расширяемый язык таблиц стилей). Таблицы XSL_стилей – это XML_документы, которые могут быть загружены и разобраны, как и любые другие XML_документы. Изучение XSL далеко выходит за рамки темы этой кни_ ги, тем не менее в примере 21.8 демонстрируется таблица стилей, которая может использоваться для преобразования в HTML_таблицу XML_документа, подобно_ го представленному в примере 21.6.

Пример 21.8. Простейшая таблица XSL"стилей


21.3. Преобразование XML*документа с помощью XSLT

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

ИмяЭлектронная почта

... __>

Когда встретится элемент , вывести его содержимое в другую ячейку __>

Правила в таблицах XSL_стилей используются для XSLT_преобразований XML_ документов. В контексте клиентского JavaScript_кода это обычно означает пре_ образование XML_документов в HTML_документы. Многие архитектуры разра_ ботки веб_приложений используют XSLT на стороне сервера, но броузеры на ба_ зе Mozilla и броузеры линейки IE поддерживают XSLT_преобразования на сторо_ не клиента, что может помочь снизить нагрузку на сервер и объем трафика, пе_ редаваемого по сети (потому что формат XML, как правило, более компактный, чем HTML).

Многие современные броузеры позволяют определять XML_стили с помощью таблиц CSS_ или XSL_стилей. Если определить таблицу стилей в исполняемой инструкции xml_stylesheet, тогда можно загрузить XML_документ непосредст_ венно в броузер, а броузер преобразует и отобразит его. Например, исполняемая инструкция могла бы выглядеть примерно так:

Обратите внимание: броузеры выполняют такого рода XSLT_преобразования ав_ томатически, когда XML_документ, содержащий соответствующую исполняе_ мую инструкцию, загружается в окно броузера. Это очень важно и очень удобно, но не это является темой данного раздела. Дальше я расскажу о том, как с помо_ щью JavaScript выполнить динамическое XSLT_преобразование.

Консорциум W3C не определяет стандартного прикладного интерфейса для XSLT_ преобразований DOM_объектов Document и Element. В броузерах на базе Mozilla прикладной интерфейс для XSLT_преобразований в JavaScript представляет объект XSLTProcessor. В IE XML_объекты Document и Element имеют метод transform_


530 Глава 21. JavaScript и XML

Node(), выполняющий преобразования. В примере 21.9 демонстрируется исполь_ зование обоих прикладных интерфейсов. В нем определяется класс XML.Trans_ former, который инкапсулирует таблицу XSL_стилей и позволяет использовать ее для преобразования более одного XML_документа. Метод transform() объекта XML.Transformer с помощью инкапсулированной таблицы стилей выполняет пре_ образование указанного XML_документа, а затем замещает содержимое заданно_ го DOM_элемента результатом преобразования.

Пример 21.9. XSLT в Mozilla и Internet Explorer

* Этот класс XML.Transformer инкапсулирует таблицу XSL_стилей.

* Если параметр stylesheet представляет собой URL_адрес, выполняется

* на соответствующий DOM_объект Document.

XML.Transformer = function(stylesheet) {

// Загрузить таблицу стилей, если это необходимо.

if (typeof stylesheet == "string") stylesheet = XML.load(stylesheet); this.stylesheet = stylesheet;

// В броузерах на базе Mozilla создать объект XSLTProcessor

// и передать ему таблицу стилей.

if (typeof XSLTProcessor != "undefined") { this.processor = new XSLTProcessor(); this.processor.importStylesheet(this.stylesheet);

* Это метод transform() класса XML.Transformer.

* Выполняет преобразование указанного xml_узла с использованием

* инкапсулированной таблицы стилей.

* Предполагается, что в результате преобразования получается HTML_код,

* которым следует заменить содержимое указанного элемента.

XML.Transformer.prototype.transform = function(node, element) { // Если элемент указан по id, отыскать его.

if (typeof element == "string") element = document.getElementById(element);

if (this.processor) {

// Если был создан объект XSLTProcessor (в броузерах на базе Mozilla),

// использовать его.

// Преобразовать узел в DOM_объект DocumentFragment.

var fragment = this.processor.transformToFragment(node, document);

// Стереть существующее содержимое элемента. element.innerHTML = "";

// И вставить преобразованные узлы. element.appendChild(fragment);

else if ("transformNode" in node) {

// Если узел имеет метод transformNode() (в IE), использовать его.

// Обратите внимание: transformNode() возвращает строку. element.innerHTML = node.transformNode(this.stylesheet);


// В противном случае удача отвернулась от нас.

throw "XSLT не поддерживается в этом броузере";

* Эта вспомогательная функция, выполняющая XSLT_преобразование,

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

XML.transform = function(xmldoc, stylesheet, element) {

var transformer = new XML.Transformer(stylesheet);

transformer.transform(xmldoc, element);

К моменту написания этих строк IE и броузеры на базе Mozilla были единствен_ ными из основных броузеров, предоставляющих API для XSLT_преобразований. Если для вас важно иметь поддержку и в других броузерах, вас наверняка заин_ тересует проект AJAXSLT – свободно распространяемая JavaScript_реализация XSLT_преобразований. Разработка проекта AJAXSLT была начата компанией Google, ознакомиться с ним можно на сайте проекта по адресу http://goog" ajaxslt.sourceforge.net .

Рассмотрим типичный пример рендеринга HTML.

Дан список музыкальных композиций в виде XML-документа.

Рихард Вагнер Полёт валькирии Эдвард Григ В пещере горного короля Иоган Бах Токката и фуга ре-минор Антонио Вивальди Времена года. Лето. Шторм Джузеппе Верди Триумфальный марш (Аида)

Отобразим данный документ в виде HTML ul/li списка, как это показано ниже:

Для этого используем следующее XSLT-преобразование:

]>

  • Данное преобразование вернёт нам следующий HTML:

    • Рихард Вагнер - Полёт валькирии
    • Эдвард Григ - В пещере горного короля
    • ...

    XSLT-преобразование состоит из трёх шаблонов ( xsl:template). Каждый шаблон обслуживает свою сущность, что даёт нам возможность легко вносить изменения и делает код понятным.

    Если нам надо поменять отображение списка (например, добавить атрибут class), то мы редактируем шаблон match="PlayList" .

    Если же мы хотим изменить отображение элементов списка, то тут, совершенно очевидно, что стоить менять шаблон match="Track" .

    Фактически, XSLT не только даёт нам возможность разделить данные и представление (это задача любого шаблонизатора), но и позволяет разделять представления различных сущностей.

    Конечно, в более сложных случаях разделения добиться такого разделения бывает сложно. Очень легко прийти к ситуации, когда возникает «божественный шаблон», который делает всё, так же стоит бояться скатиться к «стрельбе дробью» кучей мелких шаблонов.

    Отладка XSLT

    Что мне очень нравится в XSLT, так это возможность отладки. Отладка помогает наглядно увидеть логику работы XSTL, структуру документа, значения переменных.

    Например, отладка поможет увидеть, что за сущность обрабатывает шаблон match="/" .

    В Visual Studio отладка XSLT запускается сочетанием клавиш ALT+F5 .

    Добавив в окно Watch XPath выражение " . " (точка), мы увидим, что текущий элемент шаблона - это корень (Root) документа. Здесь можно разместить контейнер div , или что-то относящееся ко всему XML-документу.

    Работа с сущностями XML

    Можно заметить, что в приведенных примерах присутствует сущность — Мы можем ее использовать, потому что определили ее в начале XSLT-документа

    ]>

    Таким образом, — выводится, как символ с кодом — .

    Если нужно вывести строку «как есть», то стоит использовать CDATA следующим образом:

    Элемент xsl:text

    Хочу заострить внимание на элементе xsl:text . Он позволяет контролировать, что именно будет содержать TEXT-элемент. Значимость xsl:text очевидна на практике:

    XSLT-шаблон:

  • Полученный HTML:

  • Антонио Вивальди - Времена года. Лето. Шторм
  • Как видно из примера выше, отсутствие элемента xsl:text привело к появлению в HTML лишних переводов строк и пробелов.

    Безусловно, можно писать XSLT и без xsl:text , следующим образом:

  • Такой шаблон трудночитаем и есть большая вероятность, что при сопровождении в нём будут появлятся ошибки.

    Нужно стараться, чтобы форматирование XSLT-шаблона не влияло на результат трансформации. Именно поэтому я считаю, что использовать xsl:text - это хорошая практика.

    Ветвления

    Для ветвлений в XSLT есть специальные элементы: xsl:if и xsl:choose . Но я считаю, что этими инструментами сильно злоупотребляют. Более интересен приём, позволяющий не загромождать шаблон ветвлениями.

    Рассмотрим пример реализации ветвлений:

    Дополним предыдущий пример возможностью выводить сообщение «Список пуст» в случае, если PlayList не содержит элементов Track .

    Решение с использованием xsl:choose будет таким:

    ]>

  • Решение с использованием дополнительного шаблона будет следующим:

    ]>

  • Второе решение, на мой взгляд, выглядит красивее: новая функциональность не добавила нового кода в старые шаблоны, новый шаблон максимально изолирован.

    Если понадобится добавить картинку к сообщению о пустом списке, то в первом случае скорее всего разбухнет элемент xsl:when в шаблоне match="PlayList" . А вот во втором случае изменения будут только в специализированном шаблоне.

    В предыдущем примере мы разделили две абсолютно разные ветки рендеринга элемента списка. Но что если ветки различаются незначительно? Здесь использование xsl:if и xsl:choose вполне оправдано. Но мне бы хотелось показать другой подход: использование параметра mode у элемента xsl:template .

    В следующем примере навесим разные стили на чётные и нечётные элементы списка.

    ]>

  • even odd

    Циклы и сортировка в XSLT

    Для циклов в XSLT есть элемент xsl:for-each , но схожий эффект можно получить, используя обычный xsl:apply-templates .

    Выведем список композиций, отсортированный по длительности.

    • Рихард Вагнер - Полёт валькирии - 280
    • Антонио Вивальди - Времена года. Лето. Шторм - 203
    • Иоган Бах - Токката и фуга ре-минор - 187
    • Эдвард Григ - В пещере горного короля - 163
    • Джузеппе Верди - Триумфальный марш (Аида) - 103

    ]>

    ]>

  • Как видно из кода, первый вариант короче и проще, но он нарушил принцип разделения ответственности для шаблонов. Теперь шаблон match="PlayList" стал содержать логику отображения элемента Track .

    Казалось бы, ничего страшного, но представим задачу, когда в списке встречаются композиции с Id и без. Для композиции с Id нужно отрендерить ссылку, а для остальных вывести только текст.

    Вариант с использованием xsl:for-each:

    ]>

    Вариант с использованием xsl:apply-templates:

    ]>

  • В случае xsl:for-each нам потребовалось добавлять ветвление, а в случае xsl:apply-templates - новый шаблон.

    Если бы шаблон match="PlayList" уже содержал ветвления и логику, то нам понадобилось некоторое время, чтобы разобраться, куда именно нам нужно вставить ветку. Вариант с xsl:apply-templates лишён этого недостатка, поскольку мы лишь декларируем новый шаблон, а не пытаемся внедриться в старые.

    Использование xsl:for-each имеет ещё одну большую опасность. Если вы видите произвольный участок кода внутри шаблона match="PlayList" , то предполагаете, что текущий элемент это PlayList , однако xsl:for-each меняет контекст. Увидев следующий код код:

    Вам потребуется внимательно присмотреться к контексту, чтобы понять, что select="." на самом деле выбирает текущий Track .

    Шаблон mode="TrackName" match="Track" был добавлен для избежания дублирования кода, отображаюшего название. Я не сделал этого раньше, потому что в этом не было необходимости. Как только я заметил дублирование, я провёл рефакторинг и вынес общую логику отображения в новый шаблон.

    xsl:for-each - это способ не плодить сущности. Вы просто добавляете логику отображения внутрь xsl:for-each и всё прекрасно работает. Проблемы начинаются потом, когда тело цикла разрастается, а проводить рефакторинг xsl:for-each намного сложнее, чем выносить дублированный код.

    Заключение

    XSLT - это достаточно гибкий инструмент, он даёт возможность решить вашу задачу разными путями. Однако, при написании XSLT стоит уделять особое внимание сопровождаемости шаблонов.

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