Для всех примеров ниже использован стандарт языка XSL. Широко применяется также более современная модификация этого стандарта - язык XSLT , детальнее про который можно прочитать в \xml\XSLTutorial или MSDN.
Рассмотрим простой пример XML-файла (ex01.xml). Этот и остальные примеры можно найти в папке \xml\ XSLTForBeginers на диске.
Если мы откроем этот файл в браузере Internet Explorer, то увидим тот же самый текст, который приведен выше, вместе со всеми тегами и служебной информацией. Но нам не нужны теги и служебная информация! Мы хотим видеть только ту информацию, которая относится к делу, а при помощи тегов - управлять внешним видом этой информации. Эта задача решается легко и просто: необходимо к XML-файлу добавить шаблон преобразования - XSL-файл.
Перепишем наш XML-файл в следующем виде (ex01-1.xml).
И создадим XSL-файл ex01-1.xsl. Текст файла приведен ниже.
Если мы теперь откроем файл ex01-1.xsl в браузере Internet Explorer, то мы увидим, что наша задача решена, - на экране осталась только необходимая нам информация, все теги исчезли. Результат, который вы получите на экране браузера, приведен ниже.
"Заметки об XSL"
Легко также увидеть, что порядок вывода строк у нас определяется только содержанием шаблона преобразования - XSL-файла. При необходимости шаблон можно легко поменять, абсолютно не меняя наш основной XML-файл.
Перепишем XML-файл. Информационную часть изменять не будем, а шаблон укажем другой ex01-2.xml.
Создадим XSL-файл ex01-2.xsl. Текст файла приведен ниже.
Если мы теперь откроем файл ex01-2.xsl в браузере Internet Explorer, то результат будет другим.
"Заметки об XSL"
Отметим теперь момент, который является ключевым для разработчиков баз данных. Информация в XML-странице появляется, как правило, в результате запроса к базе данных. Запрос к базе данных в многопользовательской среде - это весьма дорогостоящая операция. Предположим теперь, что у нас нет XML и мы формируем стандартные статические HTML-страницы. В этом случае для решения задачи простого преобразования внешнего представления информации, например, для изменения сортировки, у нас есть два способа решения проблемы: выполнить запрос и сохранить результаты в каком-либо временном буфере на сервере или каждый раз при изменении внешнего представления выполнять новый запрос и формировать HTML-страницу заново.
Первый способ требует трудоемкого программирования, второй способ значительно увеличивает нагрузку на сервер базы данных, производительность которого часто является узким местом системы, - пользователю всегда хочется получать результаты быстрее.
XML и XSL - это исчерпывающее решение описанной выше проблемы. Фактически XML-страница - это и есть временный буфер для результатов запросов. Только вместо нестандартного и трудоемкого программирования мы теперь используем стандартный механизм XSL.
Есть и еще одно соображение, которое может быть существенным для разработчиков баз данных. Большинство современных СУБД могут форматировать результаты запроса к базе данных в виде XML-файла. То есть при построении интерфейса пользователя в рамках технологии XML и XSL мы добиваемся определенной независимости от поставщика СУБД. В части организации вывода - практически полной независимости. А эта часть весьма велика в большинстве прикладных систем, ориентированных на работу с базами данных. Конечно, помимо вывода есть еще ввод и серверная обработка бизнес-логики, но здесь вам придется искать какие-то иные решения.
Первые шаги
Разберем теперь более подробно первый пример. Напомним его текст.
Первая строка информирует браузер о том, что файл имеет формат XML. Атрибут version является обязательным. Атрибут encoding не является обязательным, но если у вас в тексте есть русские буквы, то необходимо вставить этот атрибут, в противном случае XML-файл просто не будет обрабатываться, - вы получите сообщение об ошибке.
Следующие строки - это тело XML-файла. Оно состоит из элементов, которые в совокупности образуют древовидную структуру. Элементы идентифицируются тегами и могут быть вложены друг в друга.
Элементы могут иметь атрибуты, значения которых тоже могут обрабатываться в соответствии с шаблоном.
На верхнем уровне XML-файла всегда находится один элемент. То есть файл вида
не будет обрабатываться браузером. Для преобразования в корректный XML-файл нужно добавить теги элемента верхнего уровня, например
Отметим, что имена тегов чувствительны к регистру символов. Подробнее об этом можно прочесть в любой книге по XML - элементам и атрибутам в этих книгах уделяется достаточно большое внимание.
Перейдем теперь к шаблону преобразования - к XSL-файлу. Задача XSL-файла - преобразовать дерево XML-файла в другое дерево, которое, например, будет соответствовать формату HTML и может быть изображено на экране браузера с учетом форматирования, выбора шрифтов и т. п.
Для того, чтобы браузер выполнил необходимое преобразование, нужно в XML-файле указать ссылку на XSL-файл
Рассмотрим теперь текст XSL-файла
Первая строка файла содержит тег элемента xsl:stylesheet. Атрибуты элемента - номер версии и ссылка на пространство имен. Эти атрибуты элемента xsl:stylesheet являются обязательными. В нашем случае пространство имен - это все имена элементов и их атрибутов, которые могут использоваться в XSL-файле. Для XSL-файлов ссылка на пространство имен является стандартной.
Заметим, что XSL-файл является одной из разновидностей XML-файлов. Он не содержит пользовательских данных, но формат его тот же самый. Файл содержит элемент верхнего уровня xsl:stylesheet, а далее идет дерево правил преобразования.
В настоящем документе мы не будем подробно пояснять, что означает каждый элемент XSL-файла. Мы будем приводить различные примеры и показывать результат в каждом примере, что даст возможность самостоятельно сопоставить различные элементы XSL-файла и инициируемые этими элементами преобразования исходного XML-файла с пользовательской информацией. Заметьте также, что значение атрибута select и подобных со смыслом «выбрать» записывается на специальном языке XPath , о котором можно прочитать в кратце на диске \xml\XPathTutorial, а подробнее в MSDN.
В дальнейшем тексты XML - и XSL-файлов мы будем приводить в черно-белом варианте. Вы всегда сможете открыть реальный файл и посмотреть все в цвете. При необходимости закомментируйте ссылку на XSL-файл. Синтаксис комментария следующий - . В текст комментария нельзя вставлять символы --.
В первом примере мы посмотрели, как с помощью элемента xsl:value-of можно вывести в HTML-формате содержание элемента (текст, заключенный между тегами). Теперь мы посмотрим, как при помощи того же самого элемента можно вывести значение атрибута элемента.
Рассмотрим следующий XML-файл ex02-1.xml
XSLT-преобразования
XSLT обладает большими возможностями для оперирования данными в документах XML. Например, при помощи таблицы стилей (stylesheet) XSLT я мог бы отформатировать данные из planets.xml в таблицу HTML. Таблицы стилей содержат правила, установленные для преобразования XML-документа, и большая часть книги посвящена созданию таблиц стилей и объяснению того, как они работают. Вот как выглядит таблица стилей XSLT planets.xsl (листинг 1.2), преобразующая данные из planets.xml в таблицу HTML (мы проанализируем ее в главе 2).
Листинг 1.2. planets.xsl
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> The Planets Table The Planets Table Как видите, эта таблица стилей XSLT выглядит как XML-документ - и для этого есть основания, потому что она им и является. Все таблицы стилей XSLT являются также и документами XML, а раз так, то они должны быть хорошо форматированными документами XML С этими двумя документами - planets.xml (листингом 1.1) и связанной с ним таблицей стилей, planets.xsl (листинг 1.2) - мы будем работать на протяжении всей книги, рассматривая различные возможные преобразования XSLT. Как вы свяжете эту таблицу стилей с XML-документом planets.xml ? Как мы увидим в следующей главе, одним из способов это сделать является инструкция обработки XML , использующая два атрибута. Первый атрибут - type , который следует установить в «text/xml», чтобы указать, что используется таблица стилей XSLT. (Чтобы использовать таблицы стилей другого типа - каскадирующие таблицы стилей (CSS, cascading stylesheets), обычно использующиеся с HTML - следует задать «text/css».) Второй атрибут - href , которому следует присвоить значение URI (вспомните, что XML использует не адреса URL, а идентификаторы URI, Uniform Resource Identifier) таблицы стилей:
Теперь при помощи процессора
(processor) XSLT можно применить таблицу planets.xsl к planets.xml и создать новый документ, planets.html . Процессор XSLT создает новый файл planets.html , который вы можете увидеть на рис. 1.2. Рис. 1.2.
HTML-документ, созданный процессором XSLT Как можно видеть на рис. 1.2, процессор XSLT считывает данные из planets.xml , применяет к ним правила из planets.xsl и создает HTML-таблицу в planets.html. Это наш первый пример XSLT-преобразования. Что здесь на самом деле происходит? У нас были XML-документ, planets.xml , и таблица стилей XSLT, planets.xsl . Но каким образом они объединились для создания planets.html ? XSL = XSLT + XSL-FO
Сам XSLT в действительности является частью более крупной спецификации - расширенного языка таблиц стилей, Extensible Stylesheet Language, или XSL. XSL предназначен для задания точного, до миллиметра, формата документов. Форматирующая часть XSL, представляющая гораздо более Преобразования XSLT-XSL
XSLT позволяет работать непосредственно с содержимым документов XML. Например, у вас может быть огромный документ XML, содержащий всю бейсбольную статистику за последний сезон, однако вас может интересовать только статистика для питчеров. Чтобы извлечь Версии XSLT
Спецификации XSLT разрабатывались значительно активнее, чем спецификации для всего XSL. Рекомендация XSLT 1.0 была окончательно принята 16 ноября 1999 г., и эта версия является сегодня основной версией XSLT.Затем появился рабочий проект XSLT 1.1 и, хотя первоначально он Что нужно для XSLT-преобразования
Для осуществления XSLT-преобразования, такого как преобразование planets.xml в planets.html, необходим XSLT-процессор. Для преобразований документов XML можно использовать XSLT тремя способами: используя отдельные программы, называемые процессорами XSLT. XSLT-преобразования на web-серверах
Можно осуществлять XSLT-преобразования на web-сервере - так чтобы XML-документ был преобразован до того, как web-сервер отправит его браузеру. Здесь самое распространенное преобразование - это преобразование документа XML в HTML, но Ресурсы XSLT
В Интернете можно найти огромное количество нужных нам сведений. Имейте в виду, что все приведенные далее адреса URL легко могут измениться; списки будут актуальны столь долго, сколько этого будут хотеть люди, занимающиеся поддержкой перечисленных Утилиты XSLT
В Интернете существует также много утилит XSLT - в следующем списке перечислены наиболее известные: Microsoft XSL API Extension, http://msdn.microsoft.com/downloads/webtechnology/xml/xslisapi.asp. Упрощает задачу выполнения XSLT-преобразований на стороне сервера; Microsoft XSL-to-XSLT Converter, Инструкции XSLT
В теле шаблона может присутствовать ряд элементов XSLT, называемых инструкциями: Расширяемость XSLT
Несмотря на кажущуюся сложность XSLT, он во многих отношениях ограничен по сравнению с языками программирования, и в процессорах XSLT сразу же начали появляться расширения XSLT. Например, Saxon представил элемент Отличия XSLT 1.1 от XSLT 1.0
Отсутствие result tree fragment
Главное и наиболее существенное отличие XSLT 1.1 от XSLT 1.0 состоит в том, что тип данных, известный в XSLT 1.0 как result tree fragment (результирующий фрагмент дерева) в XSLT 1.1. отсутствует. Вместо него в версии 1.1 используется множество узлов, Отличия XSLT 2.0 от XSLT 1.1
Прежде чем приступить к описанию отличий второй версии XSLT от версии 1.1 (и, соответственно, 1.0), следует сделать одно существенное замечание. Лицензионные соглашения Консорциума W3 не позволяют раскрывать широкой общественности внутренние материалы Преобразование формата XML-данных посредством преобразований расширяемого языка таблиц стилей (XSLT) Данное руководство создано для разработчиков, которые хотят использовать XSLT для преобразования XML-данных в другие формы без необходимости программирования на Java™ или других языках. В данном руководстве подразумевается, что вы знакомы с XML, однако автор не вдается в какие-то тайные особенности этого языка, поэтому базового понимания вполне достаточно. За исключением небольшого раздела про расширения, вам не нужно иметь за плечами никакого особенного языка программирования. И даже в этом разделе идеи очень просты и применимы к любому языку программирования, который поддерживается процессором. Это руководство - о преобразованиях расширяемого языка таблиц стилей (XSLT). XSLT - это одна из базовых спецификаций, связанных с XML, позволяющая легко переводить XML-данные из одной формы в другую. В данном руководстве вы изучите: Представьте на минуту, что у вас есть набор данных в XML. Возможно, вы предпочли хранить их таким образом из-за гибкости XML. Вы знаете, что сможете использовать их на разных платформах и практически с любым языком программирования. Но иногда вам придется менять форму вашего XML. Например, вам может понадобиться перевести данные в другой XML-формат, чтобы хранить их в другой системе, или в другую форму для представления, или еще для чего-нибудь. Например, у вас могут быть данные в XML, которые вы хотите опубликовать в Интернете, что означает перевод их в HTML. Конечно, вы могли бы вручную просмотреть документ и сделать в нем необходимые изменения, или может быть, вы подумали о том, чтобы загрузить XML в DOM, а затем вручную создать документ вывода. Преобразования расширяемого языка таблиц стилей (XSLT) предоставляют способ для автоматического перевода XML-данных из одной формы в другую. Целевая форма - это обычно другой XML-документ, но не обязательно; вы можете преобразовать XML практически во что угодно, просто создав таблицу стилей XSLT и обработав данные. Если вы хотите изменить результаты, вы просто меняете таблицу стилей и обрабатываете XML заново. Здесь есть дополнительное преимущество, расширяющее возможности непрограммистов, например, дизайнеров, которые могут изменять таблицу стилей и влиять на результаты. Давайте посмотрим пример. В данном руководстве мы возьмем XML-документ и преобразуем его в XHTML-документ, который можно отобразить как Web-страницу. Входные данные - это просто файл с рецептами (см. листинг 1). Замечание редактора
: Эти рецепты –приведены просто для примера, так, как их представляет себе автор. Правильный рецепт для Gush"gosh (полученный от его жены, которая и готовит это блюдо) состоит из 1 фунта (0,454 кг) рубленой говядины, 1 фунта рожков, 1/2 стакана желтого сахара, 1 небольшого пакета (около 300 грамм) мелко нарезанного лука, 1 чайной ложки сушеного укропа и 1 небольшой банки томатной пасты, в которую добавляется желтый сахар. Конечно, это очень простой пример, поэтому вы не увязнете в деталях самих данных, однако в виде XML-данных можно представить что угодно - от процесса журналирования до финансов. Наша цель - преобразовать эти данные в XHTML-страницу, которая будет отображать рецепты по отдельности и форматировать их ингредиенты и инструкции по приготовлению (см. листинг 2). 1 pound hamburger 1 cup cereal Вы можете отобразить этот результат в браузере, как показано на рисунке 1. Как уже упоминалось, конечной целью может быть любой формат, не только XHTML, и даже не обязательно XML. Давайте начнем с простых преобразований. Самая простая таблица стилей - это просто XML документ, включающий XSLT-вывод (см. листинг 3). Обратите внимание на использование пространства имен xsl . Добавление этого пространства имен говорит процессору, какие элементы связаны с обработкой, а какие должны быть просто выведены. Элементы value-of говорят процессору вставить определенные данные в это место. Какие именно данные вставлять определяется содержимым атрибута select . Атрибут select состоит из выражения XPath. Подробнее XPath будет обсуждаться в разделе , однако здесь вы можете видеть, что доступ к элементам "название", "ингредиенты" и "инструкция по приготовлению" происходит через иерархию документа. Мы начинаем с корневого элемента, /recipes , и от него движемся вниз. Простейший способ выполнить XML-преобразование - это добавить указание на таблицу стилей в XML и отобразить его в браузере (см. листинг 4). Эта инструкция по обработке говорит браузеру извлечь таблицу стилей, расположенную в basicstylesheet.xsl, и использовать ее для преобразования XML-данных и вывода результатов. Если вы откроете наш XML-документ в браузере Microsoft® Internet Explorer®, то увидите результат, похожий на рисунок 2. Однако это не совсем то, что мы хотели получить. Если вы выберете в браузере Вид>Просмотр HTML-кода, то увидите изначальный XML. Чтобы увидеть результат преобразования, необходимо произвести это преобразование и создать выходной файл. Это можно сделать через командную строку, используя Java-код со следующей командой (см. листинг 5): Если вы получите исключение ClassNotFoundException , возможно, вам нужно загрузить Apache Xalan (см. "Получить продукты и технологии" в разделе ) и добавить включенные в него JAR-файлы в путь к классам. Выполнив преобразование, показанное в листинге 5, вы увидите, что файл result.html содержит следующий код (см. листинг 6). 1poundhamburger
1poundelbow macaroni
2cupsbrown sugar
1bagchopped onions
1teaspoondried dill
Brown the hamburger.
Add onions and cook until transparent.
Add brown sugar and dill.
Cook and drain pasta.
Combine meat and pasta.
Я добавил несколько интервалов для удобства чтения, однако здесь следует отметить пару моментов. Во-первых, отображает информацию только для одного рецепта. Во-вторых, ингредиенты слеплены вместе без каких-либо пробелов. Это тоже не тот результат, который мы хотели получить. К счастью, можно создать более точные шаблоны для отображения данных именно в той форме, в какой вы хотите. От преобразования нет никакой пользы, если оно не приводит данные именно к той форме, которая нам нужна. Чтобы это сделать, нужно уметь использовать шаблоны, чему и посвящен данный раздел. Большинство таблиц стилей не имеют такой простой формы, какую вы только что видели в предыдущем разделе. Вместо этого они разбиваются на группу шаблонов, каждый из которых применяется к определенному типу данных. Давайте переведем нашу таблицу стилей в эту форму (см. листинг 7). Здесь информация не изменилась, за исключением того, что процессор смотрит на таблицу стилей и начинает с шаблона, совпадающего с корневым элементом документа, как указано в атрибуте match . Затем он выводит этот шаблон, включая все значения, так же как и раньше. Если вы выполните сейчас преобразование, то должны увидеть точно такие же результаты, как и в . Но это не то, что мы хотим. Мы хотим иметь возможность форматировать ингредиенты и инструкции. Для этого мы можем создать отдельные шаблоны для каждого из этих элементов и включить их в таблицу стилей (см. листинг 8). Обратите внимание, что вместо того, чтобы просто вывести элемент value-of , мы теперь указываем таблице стилей применять соответствующие шаблоны к элементам ingredients и instructions. Затем мы создали отдельные шаблоны для этих элементов, задав их в атрибуте match . Добравшись до элемента apply-templates , процессор выбирает все элементы ingredients в документе. Затем он ищет шаблон для ингредиентов, а, найдя его, выводит этот шаблон. То же самое он делает с элементом instructions . Результат должен быть похож на изображенный на рисунке 3. Так, это уже немного ближе, хотя бы понятно, что здесь два рецепта, однако вы вряд ли захотите объединять ингредиенты и инструкции для всех рецептов. К счастью, эту проблему можно решить лучшей организацией шаблонов. Чтобы лучше организовать данные, обратим внимание на то, как мы разделяем и публикуем шаблоны. XSLT позволяет обрабатывать информацию итеративным образом. Например, можно поделить информацию на отдельные рецепты, а затем отформатировать инструкции и ингредиенты (см. листинг 9). В данном случае таблица стилей выводит основную страницу (HTML), а затем просматривает каждый рецепт, выводя название, ингредиенты и инструкции для каждого рецепта. Опять-таки XPath мы будем изучать в разделе , но в данном случае элемент recipe становится контекстным узлом, поэтому атрибуты select относятся к этому узлу так же как файлы к конкретному каталогу в файловой системе. Результат должен быть похож на рисунок 4. Отлично, формат приблизился к желаемому, однако нам все еще нужно отобразить фактическую информацию. Для этого надо изменить шаблоны ingredients и instructions (см. листинг 10). Важный момент при публикации шаблонов: вы указали процессору применять подходящие шаблоны к элементу ingredients , однако у нас нет специального шаблона для этого элемента. Если вы примените шаблон к элементу, а самого шаблона не будет, то данные просто не появятся. Но это не наш случай. Наоборот, мы воспользовались тем, что когда указали процессору применять подходящие шаблоны к элементу ingredients , он ищет не только элемент ingredients , но и дочерние элементы элемента ingredients . Таким образом, он находит шаблон для ингредиентов, в котором вы выводите количество, единицы измерения, название продукта и разрыв строки. То же самое мы сделали для инструкций, когда отформатировали их как элементы списка. Заметьте, что мы создали фактически упорядоченный список в основном шаблоне для рецепта, а затем отправили элементы для индивидуальной обработки. Результат должен быть похож на рисунок 5. Определенно формат приближается к желаемому. Однако если вы посмотрите на вывод, то увидите, что проблема с пробелами все еще существует (см. листинг 11). 1poundhamburger Почему это случилось, если мы включали пробелы в таблицу стилей? Должны они были появиться в выводе? Разумеется, необязательно. Есть способы указать таблице стилей оставлять пробелы - они будут изучены в разделе Организация циклов и импорт - однако в некоторых случаях проще явно добавить текст в вывод (см. листинг 12). Тем самым мы позаботились о недостающих пробелах. Точно так же с помощью элемента text , можно добавить в шаблон любой произвольный текст. (Помните, что только текст, а не элементы типа разрыва страницы.) Результатом будет такой вывод, какой нам нужен (см. листинг 13). 1 pound hamburger 1 cup cereal Результат показан на рисунке 6. Возможность преобразовывать данные в форму, в какой вы желаете их видеть, требует понимания языка маршрутов XML, или XPath, который позволяет контролировать, какие именно данные публикуются и/или отображаются. Данный раздел объясняет основные понятия XPath и показывает, как создавать простые выражения. Вы должны были заметить, что важной частью функционирования таблицы стилей является возможность выбрать конкретную часть документа. Например, если вы хотите отобразить инструкции, то нужно знать, как на них ссылаться. В XSLT мы ссылаемся на информацию, используя выражения XPath. Выражение XPath может выбрать единственный узел или набор узлов, либо вернуть единственное значение, основанное на одном или более узлов в документе. До сих пор мы имели дело с очень простыми выражениями XPath, которые выбирают узел или узлы, спускаясь вниз по иерархической структуре. XPath предоставляет несколько способов для задания групп узлов на основании отношений, таких как родитель-потомок или предок-потомок. В данном руководстве мы изучим все эти отношения, называемые осями
. Вы также узнаете о некоторых более мощных функциях XPath и о предикатах
- это в основном условные утверждения, которые можно добавлять в выражения. Например, в разделе Настройка контекста вы увидите, как выбирать все элементы recipe в документе; предикаты позволяют выбрать только конкретный элемент на основании конкретных критериев. Наконец, вы узнаете о еще более мощных функциях, которые позволяют использовать многие типы логики, которые используются в процедурных программах. Давайте начнем с изучения контекста выражения. Первым шагом в понимании XPath является понимание того, что полученные результаты в большой степени определяются текущим контекстным узлом. Контекстный узел можно считать своеобразным знаком "ты находишься здесь", от которого можно двигаться в различных направлениях согласно выражению XPath. Например, рассмотрим простую таблицу стилей в листинге 14. Здесь есть новый элемент - copy-of . Там, где value-of выводит содержимое элемента, copy-of делает именно то, о чем говорит его название, и выводит фактический узел, на который ссылается атрибут select . В данном случае в атрибуте select содержится одно из простейших возможных выражений XPath. Одиночная точка (.) – это ссылка на данный контекстный узел, как в файловой системе, когда вы хотите сослаться на "текущую директорию, вне зависимости от того, что это за директория." Поэтому если вы выполните это преобразование, то получите результат, как в листинге 15. Вы видите, что это просто повторение того же документа; это потому, что контекстный узел, как указано атрибутом шаблона match, - это корень документа, или /. Если вы измените контекстный узел, вывод изменится. Например, вы можете установить контекстный узел на первый рецепт (см. листинг 16). Теперь, запустив преобразование, вы увидите разницу (см. листинг 17). Так как мы переместили контекстный узел, вывод изменился. Это важно, когда вы хотите выбрать узел относительно контекстного узла. Например, вы можете выбрать только заголовок рецепта (см. листинг 18). Здесь вы выбираете элемент name , расположенный на один уровень ниже, чем текущий контекстный узел, поэтому результат будет как в листинге 19. Мы изучим задание узлов по номеру позже, а пока отметим, что мы можем переместить контекстный узел во второй рецепт (см. листинг 20). (Не обращайте внимания на еще один шаблон, он нужен, чтобы не появлялся текст другого рецепта.) Мы можем видеть, что результирующее преобразование показывает это изменение контекста (см. листинг 21). Теперь, когда мы знаем, откуда мы начинаем, было бы полезно узнать, куда можно двигаться. До сих пор мы использовали очень простые выражения XPath, похожие на иерархию в файловой системе, однако XPath предоставляет гораздо больше возможностей. Например, до сих пор вы выбирали только дочерние элементы, однако вы можете также искать родителей конкретного узла, а также его потомков или предков. Для начала давайте поговорим о системе обозначений. Мы использовали упрощенную, укороченную форму запроса потомков. В "длинной форме" выражения задаются как child::name вместо./name В обоих случаях вы задаете любой узел, который является потомком контекстного узла, а также является элементом name . Вы также можете связать их вместе, как в предыдущем случае, используя /child::recipes/child::recipe вместо /recipes/recipe . Потомки
Возможно, вы недоумеваете, зачем мучаться с длинной формой, если короткая настолько проще. Это не было бы нужно, если бы единственное, что вы могли бы делать - это выбор потомков. Однако эту нотацию также можно использовать для выбора других отношений. Например, выражение XPath descendant::instruction выбирает все элементы instruction, которые являются потомками контекстного узла, а не только дочерние элементы. Кроме того, можно комбинировать инструкции. Например, вы можете выбрать все инструкции второго рецепта: /recipes/recipe/descendant::instruction . Одной из разновидностей оси потомков является ось потомок-или-сам-элемент, которая выбирает заданный узел из всех потомков, а также ищет в самом контекстном узле. Например, выражение descendant-or-self::instructions выбирает все узлы instruction в контекстном узле и ниже его. Обычным сокращением для этой оси является двойная косая черта, //. Это означает, что выражения: /recipes/recipe//instructions и //instructions выбирают все инструкции для второго рецепта и все инструкции в документе, соответственно. Этот второй пример очень широко применяется, он удобен, когда вы хотите просто выбрать все элементы определенного типа в документе. Атрибуты
Еще одна общая задача, с которой вы столкнетесь - это необходимость выбрать атрибут для конкретного элемента. Например, вы, возможно, захотите выбрать recipeId для конкретного рецепта. Выражение /recipes/recipe/attribute::recipeId выбирает атрибут recipeId для всех элементов recipe . Эта ось также имеет сокращенную форму: это же выражение можно записать так: /recipes/recipe/@recipeId . Родители
Все, что мы видели до этого, переносило нас вниз
по дереву иерархии, но также существует возможность пойти вверх
, выбрав предка конкретного узла. Предположим, что контекстным узлом была одна из инструкций, а вы хотите вывести recipeId для текущего рецепта. Вы можете сделать это следующим образом: ./parent::node()/parent::node()/@recipeId . Это выражение начинается в текущем узле - instruction -, а затем двигается к предку этого узла - элементу instructions - а затем к предку ТОГО элемента - recipe -, а затем к соответствующему атрибуту. Возможно, вам лучше знакома сокращенная форма: ./../../@recipeId . Теперь давайте посмотрим, как задаются некоторые условия. В большинстве случаев уже рассмотренных приемов достаточно. Однако нередко встречаются ситуации, требующие большей избирательности. Данный раздел показывает, как использовать предикаты для выбора узлов, основанных на конкретных критериях, и дает представление о некоторых функциях, встроенных в XPath. Зачастую требуется не просто любой узел, а конкретный узел, выбранный на основе конкретных условий. Вы ранее уже видели пример, когда использовали выражение /recipes/recipe//instructions . Это на самом деле сокращенная версия выражения /recipes/recipe//instructions , которое означает, что процессор XPath должен пройти через каждый элемент recipes (конечно, такой элемент только один) и для каждого элемента recipes пройти через каждый элемент recipe. Для каждого элемента recipe проверить истинность выражения position() = 2 . (Другими словами, есть ли в списке этот второй рецепт?) Если это предложение, называемое предикатом, истинно, то процессор использует этот узел и продолжает, возвращая любые инструкции. С помощью предикатов можно сделать множество вещей. Например, можно вернуть только рецепты, в которых есть название: /recipes/recipe . Это выражение просто проверяет, существует ли элемент name - потомок элемента recipe . Также можно поискать конкретные значения. Например, можно возвращать только элементы, которые называются "A balanced breakfast": //recipe . Имейте в виду, что предикат просто говорит процессору, возвращать ли текущий узел, поэтому в данном случае возвращается элемент recipe, а не имя. С другой стороны, можно указать процессору возвратить только название первого рецепта при помощи любого и этих двух выражений (см. листинг 22). В первом выражении сначала мы выбираем все элементы recipe , а затем возвращаем только тот, у которого есть атрибут элемента recipeId , равный 1. Найдя этот узел, мы двигаемся к его дочернему узлу, который называется name, и возвращаем его. Во втором выражении сначала отыскиваются все элементы name , а затем выбирается только тот, у чьего родителя имеется атрибут 1. В любом случае, вы получите один и тот же вывод (см. листинг 23). XPath также предоставляет ряд функций. Некоторые из них относятся собственно к узлам, - например, те, которые ищут конкретную позицию, - некоторые обрабатывают строки, некоторые, - такие как суммирование, - с числами, некоторые с булевскими значениями. Функции, связанные с узлами
Функции, связанные с узлами, помогают, например, выбрать конкретный узел в зависимости от позиции. Например, вы можете специально запросить последний рецепт: //recipe . Данное выражение выбирает все элементы recipe , а затем возвращает только последний. Вы также можете использовать функции отдельно, вместо того чтобы использовать их как часть предиката. Например, вы можете специально запросить посчитать элементы recipe: count(//recipe) . Вы уже видели функцию position() и то, как она работает. Другие функции, связанные с узлами, включают id() , local-name() , namespace-uri() и name() . Строковые функции
Большинство строковых функций предназначено для обработки строк, а не для их проверки, за исключением функции contains() . Функция contains() показывает, является ли данная строка частью большего целого. Это позволит, например, вернуть только узлы, содержащие определенные строки, такие как: //recipe . Это выражение возвращает элемент recipe, который содержит в своем элементе name строку "breakfast". Функция substring() позволяет выбрать конкретный диапазон символов из строки. Например, выражение: substring(//recipe/name, 1, 5) возвращает A bal . Первый аргумент - это полная строка, второй - позиция первого символа, а третий - это длина диапазона. Среди прочих строковых функций имеются: concat() , substring-before() , substring-after() , starts-with() и string-length() . Числовые функции
Числовые функции включают функцию number() , которая переводит значение в числовое, чтобы другие функции могли с ним работать. Числовые функции также включают: sum() , floor() , ceiling() и round() . Например, вы можете найти сумму всех значений recipeId при помощи выражения: sum(//recipe/@recipeId) . Конечно, особого повода проводить подобное вычисление нет, однако это просто числовое значение, приведенное для примера. Функция floor() находит наибольшее целое, которое меньше или равно данному значению, а функция ceiling() находит наименьшее целое, которое больше или равно данному значению. Функция round() работает традиционным образом - округляет (см. листинг 24). Булевы функции
Булевы функции наиболее полезны при работе с условными выражениями, о которых будет рассказано в разделе Условная обработка . Возможно, наиболее полезной функцией является not() , которая может быть использована для определения того, что определенный узел не существует. Например, выражение //recipe возвращает каждый рецепт, содержащий в элементе name строку "breakfast". Но что, если вам нужны все рецепты, кроме завтрака? Можно использовать выражение: //recipe . Другие булевы функции включают true() и false() , которые возвращают константы, и boolean() , которая преобразует значение в булево, чтобы его можно было использовать в качестве проверочного. Рассмотрим еще два важных аспекта использования таблиц стилей XSLT: создание циклов и импортирование внешних таблиц стилей. При работе с XSLT необходимо привыкнуть к тому, что это функциональный язык, а не процедурный. Другими словами, обычно вы явно не контролируете способ, которым он выполняет данные ему инструкции. Однако существуют исключения. Например, существует возможность организовывать циклы и выполнять условные операции. Давайте начнем с циклов. В предшествующем примере мы использовали выражения XSLT, встроенные в шаблон публикации, чтобы применить стиль к конкретным элементам. В некоторых случаях это отлично работает. Однако в ситуации, когда имеются сложные XML файлы или сложные требования, иногда проще обратиться к информации явно (см. листинг 25).
Конструкция цикла очень похожа на структуру for-each , в честь которой она названа. Подобно тезке, каждый экземпляр цикла несет в себе следующее значение списка. В Java-программировании это могло бы быть следующее значение в массиве; здесь это следующий узел в совокупности узлов, возвращенных выражением XPath в атрибуте select . Это означает, что когда вы первый раз выполняете первый цикл, контекстным узлом является первый элемент ingredient . Это позволяет выбрать потомков этого элемента qty, unit и food и добавить их в документ так же, как это было сделано ранее при помощи шаблона. То же самое и с инструкциями, за исключением того, что они просто выводятся напрямую. Результаты идентичны тем, что получаются при публикации через шаблоны - почти. Каждый шаблон добавляется к документу как индивидуальная строка, но так как нам необходимо обрабатывать эту информацию как один шаблон, мы теряем множество пробелов, которые видели раньше (см. рисунок 7). Для некоторых XML-приложений это имеет значение, но здесь мы используем HTML, поэтому это значения не имеет. Однако помните об этом, когда решаете, какой метод использовать. Другая вариация таблиц стилей касается их структуры. До сих пор вся наша информация хранилась в единственной таблице стилей. Однако в некоторых случаях бывает полезно разбить ее на отдельные таблицы стилей. Такая модульность может облегчить поддержку, а также гибкость, позволяя использовать различные таблицы стилей для различных целей. Например, мы можем создать две различные таблицы стилей, одна из которых будет использоваться для ингредиентов (см. листинг 26). Также можно создать отдельную таблицу стилей для инструкций (см. листинг 27). Эти шаблоны идентичны шаблонам из действующей таблицы стилей. Их можно добавить к таблице стилей посредством включения (см. листинг 28). Хотя здесь мы разместили таблицы стилей в той же директории, что и основную таблицу, делать это не обязательно: атрибут href может содержать любой доступный URL. Обратите внимание, что мы отсылаем процессор на поиск шаблонов для элементов ingredients и instructions , которых нет в этом файле. Однако если обработать таблицу стилей, результат получится точно тот же, как если бы шаблоны были включены напрямую, а не через элемент include (см. рисунок 8). Элемент include дает тот же результат, как если бы мы добавили содержимое начиная с данной точки. Семантически они идентичны. С другой стороны, есть еще один способ включения информации - импорт. XSLT позволяет импортировать таблицу стилей в начало файла. Почему в начало? Потому что целью импорта таблицы стилей является возможность корректировки любых шаблонов, являющихся частью импорта. Например, мы можем импортировать шаблон ingredients и откорректировать его (см. листинг 29). Здесь мы фактически заменили один шаблон двумя, которые заменяют шаблоны в импортированной таблице стилей (см. рисунок 9). Обратите внимание, что, так как иерархия зависит от расположения, того же результата можно было бы добиться и с помощью включения. Однако XSLT позволяет использовать атрибут priority , чтобы задать приоритет шаблонов при обработке импорта. Мы увидели, как сделать XSLT более похожим на программирование. Как насчет добавления к нему фактического программирования? Давайте взглянем на добавление функциональности Java к таблице стилей XSLT. Во-первых, следует отметить, что хотя механизм расширения является частью рекомендаций XSLT, рассматриваемая здесь реализация специфична для процессора Xalan XSLT. Основные идеи практически одинаковы для других процессоров, однако для уточнения деталей вам придется сверяться с документацией. Расширение XSLT производится с помощью различных методик. Первая - это использование элементов extension . Элемент extension - это элемент в пространстве имен, который указывает на класс Java. Взгляните, например, на следующий элемент extension (см. листинг 30). Мы создали пространство имен, которое соответствует классу comp.backstop.RecipeScaler , который включает в себя статический метод под названием scaleMessage (см. листинг 31). Добравшись до элемента, процессор видит префикс пространства имен scaler: и знает, что он обозначен как префикс элемента extension, и таким образом понимает, какой класс обозначен в определении пространства имен. Вызываемый им метод отвечает локальному имени элемента - scaleMessage . Сам метод получает два аргумента, из которых мы фактически используем один. Параметр context ссылается на контекст процессора, который позволяет взглянуть на элементы, относящиеся к элементу extension , однако мы просто займемся самим элементом extension . Так как мы получаем этот элемент как параметр метода, мы можем извлечь значения любых атрибутов, добавленных к этому элементу, таких как servings в данном случае. Текст, возвращенный методом, добавляется к выводу на месте элемента extension . Это означает, что если применить таблицу стилей, мы получим результаты, показанные на рисунке 10. Элементы extension могут быть весьма полезны, хотя и несколько сложны в использовании. Еще один способ добавить функциональность при помощи таблиц стилей - это использование функций extension, которые несколько проще реализовывать, чем элементы extension. Например, мы можем создать функцию, которая умножает количество ингредиентов и количество порций (см. листинг 32). Добавление этой функции в таблицу стилей идентично добавлению элемента extension, в котором уже есть карта пространства имен для класса (см. листинг 33). Учтите, что вызов функции включает префикс пространства имен. Как и ранее, процессор видит префикс и знает, что надо выполнить вызов класса RecipeScaler . В результате количество ингредиентов умножается на два (см. рисунок 11). Хотя данный код и работает, поддерживать его сложно. Давайте посмотрим, как упростить поддержку. Прежде, чем закончить изложение, рассмотрим два аспекта XSLT, которые предоставляют некоторые возможности, характерные для обычных языков программирования. Прекрасно, что мы можем выполнить функцию, но дело кончилось константой, запрятанной в глубине таблицы стилей. Не лучше ли было бы задавать переменные в начале страницы? Конечно, да (см. листинг 34). Обратите внимание, что ингредиенты были умножены на количество порций, как и ожидалось. Однако если вы посмотрите внимательнее, то увидите, что элемент extension сработал неверно, приняв переменную за строку, вместо того чтобы использовать значение самой переменной. Это не сбой; спецификация не требует, чтобы процессор что-либо делал со значениями атрибутов перед обработкой элемента extension. Поэтому нам надо как-то избежать этой проблемы. Первое, что мы можем сделать - это использовать условную обработку, чтобы сообщение отображалось, только если оно нужно. Например, см. листинг 35. Содержимое элемента if , заданное атрибутом test, должно быть равно true (истина). Если это не так, что и произошло в данном случае, вывод не появится вовсе (см. рисунок 13). В том виде, в каком оно написано, предложение не имеет особого смысла; если значение больше единицы, элемент extention отобразится со значением "3." Лучше использовать множественный выбор (см. листинг 36). В данном случае у нас имеется комбинация элементов if-then-else и предложения case из традиционных языков программирования. Элемент choose работает как контейнер, однако элемент when отображает его содержимое, только если его атрибут test равен true (истина). Наконец, если ни один из элементов when не равен true (истина), процессор отображает содержимое элемента otherwise . Результат получается такой, какого следует ожидать (см. рисунок 14). Теперь вы можете более гибко задать отображение большего количества порций, или подстроиться под другие условия. Данное руководство позволило продвинуться от начального знакомства с преобразованиями XSLT до составления достаточно сложных таблиц стилей. Сначала вы познакомились с основами таблиц стилей, затем с выражениями XPath - одной из основ XSLT. В последней части данного руководства были рассмотрены некоторые более сложные аспекты таблиц стилей XSLT - переменные, условная обработка и расширения. В результате у вас теперь должно быть достаточно знаний, чтобы делать с таблицами стилей XSLT практически все необходимое - или хотя бы понимать, что еще надо выяснить, если столкнетесь с проблемой. XSLT
(eX
tensible S
tylesheet L
anguage T
ransformations) - язык преобразований xml-документов. Задача генерирования отчетности в системе DIRECTUM является одной из наиболее востребованных. В этой статье описан возможно не самый широко распространенный способ формирования html-отчетов на основе xslt-преобразований. Но несомненно заслуживающий внимания, как один из наиболее удобных и наглядных (если сравнить например с rtf-отчетом). Если очень коротко, то xslt-преобразование заключается в трансформации xml-схемы с данными в отчет на основе предварительно подготовленного шаблона. Для примера отчета описанного в статье будет выводится список контрагентов с их наименованием, ИНН и адресом. Чтобы сформировать отчет понадобятся две составляющие: Xml-данные для отчета Xsl-шаблон отчета Данные в формате xml можно получить прямым sql-запросом: Select Analit, -- ИД записи для генерации ссылки
NameAn, -- Наименование контрагента
EdIzm, -- ИНН
Dop2 -- Адрес
from dbo.MBAnalit
where Vid = %s
and Sost = "Д"
and XRecStat = "+"
for xml path("org"), type -- Получить набор строк Описанный выше запрос вернет данные в таком формате:
Данные нужно обернуть в тег
Вторая строка заголовка xml-файла данных важна, в ней указано, что в файле C:\Temp\template.xsl хранится шаблон отчета в который необходимо передать данные. В итоге получится такой xml-файл:
Если открыть полученный xml-файл, браузер будет использовать указанный в заголовке шаблон и подставит данные в него.
Теперь нужно сотворить немного магии и указать какие именно данные из xml и в каком виде вставить в шаблон отчета. Для работы с данными в xsl-шаблоне используются специальные теги. Чтобы перебрать все узлы из xml-файла данных нужно использовать конструкцию:
Она позволит перебрать все дерево данных. Для того, чтобы выбрать только определенные данные из дерева используется правило выбора select="orgs/org"
. Правила описаны на языке запросов XPath . В текущем примере будет последовательно отобрана каждый узел Если необходимо, чтобы записи отображались не в порядке следования в xml-файле, а сортировались, то нужно указать это в шаблоне:
Теперь записи будут перебираться предварительно отсортированными по наименованию. Но просто перебрать не достаточно, нужно вывести в отчет нужные данные, для этого существует конструкция:
Конструкция отобразит значение тэга Чтобы сделать из наименования контрагента ссылку, по которой можно будет открыть запись справочника, нужно немного модифицировать код: Пусть ИНН контрагента отображается в отчете не просто так. Если ИНН в карточке отсутствует, то будет выводится сообщение об отсутствии ИНН. Для этого необходимо использовать конструкцию:
В конструкции choose
с помощью фильтра test
проводится проверка содержимого тэга С помощью фильтра возможно реализовать еще одну "рюшечку", которая будет помечать контрагентов с ИНН начинающихся например с кода региона "18". Выглядеть это будет так:
Конструкция для всех записей ИНН которых начинается с "18" дополнительно выведет значок . В конечном итоге получится такой код шаблона:
А если открыть xml-файл в браузере, то получится такой отчет: В статье описаны только несколько базовых возможностей xsl, такие как фильтры, сортировка, цикл, case-конструкция. Кроме них существуют еще интересные возможности. Надеюсь, статья подтолкнет изучить и их. Возможно после этого построение отчетов станет более интересным. А если к отчету подключить такой мощный инструмент как javascript, то описанный отчет легко можно сделать интерактивным. Например добавить элемент, позволяющий проводить какую-либо фильтрацию. Или отображать графики по данным отчета. Какие есть плюсы при реализации отчетов описанным способом: Требуется разработка относительно небольшого количества прикладных вычислений; Разработка шаблона наглядна и также относительно нетрудоёмка. Всё описанное в статье легко интегрируется в аналитический отчет, ссылка на который приведена ниже. Не прошло и трёх лет с тех пор, как у меня зародилась мысль о том, что пора изучать XSLT -))). Мысль зародилась, а везде ещё стоял PHP 4 и зверствовал Salbotron , который, мягко говоря, не отличался высокой производительностью. Да и редко какой браузер мог похвастаться поддержкой этого самого XSLT. По этим соображениям изучение столь перспективного направления я отложил до лучших времён. На данный момент можно смело заявить, что эти времена настали, поскольку вышел PHP 5 с поддержкой XSLT и сносной объектной моделью, а все топовые браузеры уже сами уверенно держат преобразования, только подавай XML. :) Переводы на русский язык: Для лучшего понимания всего происходящего я рекомендую читать спецификации в следующем порядке: Особо пытливые могут также уделить внимание расширенному языку стилей XSL
. Что такое валидный XHTML? В первую очередь, это XML-документ, который должен соответствовать спецификации XML. Во-вторую, почти обычная HTML-страница, к которой все привыкли. Почему нужен именно XHTML? Исключительно из соображений совместимости и кросс-браузерности. Страница в XHTML будет с большей вероятностью отображаться корректно в популярных браузерах, чем обычный HTML. Для рядового клепателя страниц словосочетание XML-документ должно означать следующее: Также сам XHTML обязывает выполнять следующие условия: Пример простого документа XHTML1.0: И так обо всём по порядку. Объявление XML-документа, в котором указывается его версия и кодировка. Объявление пространства имён и используемого языка. Три версии XHTML1.0 предназначены для лучшей обратной совместимости: XHTML1.1 по сути является тем же XHTML1.0 Strict и призван вытеснить другие версии XHTML1.0. Однако, по сравнению с XHTML1.0 Strict, у него есть ряд отличий : Итак, если вам нужна наибольшая кросс-браузерность и совместимость с рекомендациями W3C, то XHTML1.1 самое оно! Из этих соображений результатом моих преобразований будет именно XHTML1.1. Что такое XSLT? Это язык преобразований XML-документа, который был разработан как часть расширенного языка стилей (XSL). Зачем нужен XSLT? Он позволяет реализовать схему, при которой данные хранятся отдельно, а их представление отдельно. То есть, один XML-документ преобразуется с помощью другого XML-документа (XSL, в котором находятся XSLT-шаблоны) в конечный документ. Результатом может быть XML, HTML или текстовый документ любого формата. Для того, чтобы воспользоваться XSLT-преобразованиями, в первую очередь нужно сформировать правильный стиль XSL и подключить его к XML-файлу. Валидным XSL-документом является XML-документ, у которого задано пространство имён xsl и присутствует корневой элемент stylesheet. В самом простом случае стиль может выглядеть, например, так: Этот стиль не содержит каких-либо явных определений шаблонов или других элементов XSL. Однако, его уже можно использовать. Чтобы посмотреть результат, достаточно сформировать произвольный XML-документ и подключить к нему этот стиль: За подключение стиля отвечает строка: При этом кодировка результата будет UTF-8, несмотря на то, что исходный документ был сформирован в windows-1251. К сожалению, браузеры обычно не позволяют просмотреть код результирующего документа, но модуль XSLT в PHP5 даёт возможность передать результирующий код в переменную, которую можно сохранить в файл. Поэтому, используя PHP, я приведу исходный код результирующего документа: Этот код не является валидным XML-документом и тем более XHTML1.1. Для того, чтобы сформировать нужный код, я усложню исходный XSL-стиль и добавлю туда необходимые шаблоны и преобразования. При этом исходный XML-документ останется без изменений. В качестве примера я приведу XSL-стиль, который при помощи XSLT будет выводить список атрибутов исходного XML-документа с их значениями, при этом будет формироваться валидный XHTML1.1. Итак, стиль: Чтобы понять, как он работает, я распишу каждое действие отдельно: Объявление XML-документа: Обязательным атрибутом является определение пространства имён xsl через атрибут xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
. Следующим шагом в корневом элементе stylesheet объявляется, каким образом нужно формировать результирующий документ: Основные атрибуты: Если метод вывода объявлен html, то значения атрибутов encoding
и media-type
будут подставлены в заголовок страницы ( Объявление основного шаблона: Атрибут xmlns="http://www.w3.org/1999/xhtml"
указывает на пространство имён xhtml, которое будет применено по умолчанию к этому элементу и всем дочерним элементам, у которых оно не задано явно. Атрибут xml:lang="ru"
указывает на язык, в котором сформирована страница (будущая). Эта часть стиля была нужна для формирования атрибутики валидного XHTML1.1 кода. Теперь что касается XSLT-преобразований: Вставка простого текста: Атрибут select
принимает выражение XPath, на основе которого делает выборку. Если выборка вернула список узлов, то начинает работать цикл по каждому элементу. В данном случае выборка вернёт список атрибутов для этого (корневого) и всех дочерних элементов. Проверка условия: В данном случае, если позиция элемента чётная (определяется вышестоящим if), то в стиль элемента Вывод значений элемента: Этот код подставит в вышестоящий элемент строку, собранную из имени текущего элемента и его значения. Содержимое атрибута select
соответствует XPath. Результатом обработки этого стиля (test.xsl) станет такой код: Этот код соответствует стандарту XHTML1.1 и был сформирован на основе исходного XML-документа. Для проверки можно воспользоваться валидатором от W3C, который расположен по адресу http://validator.w3.org/ . В браузере этот код выглядит примерно так: Дополнительную информацию по использованию XSLT в PHP5 можно найти по адресу http://ru2.php.net/manual/ru/book.xslt.php . «Товарищи, мы стоим на краю огромной пропасти! И я предлагаю сделать большой, решительный шаг вперёд!» 2019 Антон Прибора. При копировании материалов с сайта, пожалуйста, указывайте ссылку на источник.Name Mass Radius Day Перед началом работы
О чем это руководство?
Начало работы
Что такое XSLT?
Поставленная задача
Листинг 1. Основные данные
Листинг 2. Результат
Gush"gosh
Ingredients:
1 pound elbow macaroni
2 cups brown sugar
1 bag chopped onions
1 teaspoon dried dill
Directions:
A balanced breakfast
Ingredients:
1 glass orange juice
1 cup milk
2 slices toast
Directions:
Рисунок 1. Результат, отображенный в браузере
Простая таблица стилей
Листинг 3. Самая простая таблица стилей
Ingredients:
Directions:
Как выполнить преобразование
Листинг 4. Добавление в XML инструкции по обработке при помощи таблицы стилей
Рисунок 2. Извлечение таблицы стилей и преобразование XML-данных
Листинг 5. Преобразование документа через командную строку
java org.apache.xalan.xslt.Process -IN recipes.xml -XSL basicstylesheet.xsl -out
result.html
Листинг 6. Результаты
Gush"gosh
Ingredients:
Directions:
Добавление шаблонов
Создание шаблонов
Листинг 7. Переделанная таблица стилей
Ingredients:
Directions:
Листинг 8. Создание дополнительных шаблонов
Ingredients:
Directions:
INGREDIENTS HERE
INSTRUCTIONS HERE
Рисунок 3. Применение соответствующих шаблонов к элементам ingredients и instructions
Публикация шаблонов
Листинг 9. Выделение рецептов
Ingredients:
Directions:
INGREDIENTS HERE
INSTRUCTIONS HERE
Рисунок 4. Элемент recipe становится контекстным узлом
Листинг 10. Работа над шаблонами ingredients и instructions
...
Ingredients:
Directions:
Рисунок 5. Создание упорядоченного списка в основном шаблоне рецепта
Листинг 11. Недоработанный вывод
Gush"gosh
Ingredients:
1poundelbow macaroni
2cupsbrown sugar
1bagchopped onions
1teaspoondried dill
Directions:
Добавление пробелов
Листинг 12. Добавление текста
...
Листинг 13. Окончательный вывод
Gush"gosh
Ingredients:
1 pound elbow macaroni
2 cups brown sugar
1 bag chopped onions
1 teaspoon dried dill
Directions:
A balanced
breakfast
Ingredients:
1 glass orange juice
1 cup milk
2 slices toast
Directions:
Рисунок 6. Проблема отсутствующих пробелов решена
Основы XPath
Что такое XPath?
Настройка контекста
Листинг 14. Демонстрация контекста
Листинг 15. Простейшее преобразование
Листинг 16. Перемещение контекстного узла
Листинг 17. Результаты
Листинг 18. Выбор только заголовка
Листинг 19. Результаты
Листинг 20. Еще одно перемещение контекстного узла
Листинг 21. Результаты
Для чего нужны оси
Более продвинутые возможности XPath
Использование предикатов
Листинг 22. Возвращение только названия первого рецепта
//recipe[@recipeId="1"]/name
//name]
Листинг 23. Вывод
Функции
Листинг 24. Результаты числовых функций
floor(42.7) = 42
ceiling(42.7) = 43
round(42.7) = 43
Организация циклов и импорт
Организация циклов
Листинг 25. Прямое применение стилей с использованием циклов
Ingredients:
Directions:
Рисунок 7. Результаты
Включение и импорт таблиц стилей
Листинг 26. Файл ingredients.xsl
Листинг 27. Файл instructions.xsl
Листинг 28. Включение таблиц стилей
Ingredients:
Directions:
Рисунок 8. Результаты
Листинг 29. Импорт таблицы стилей
Рисунок 9. Результаты
Расширение XSLT
Элементы расширения
Листинг 30. Использование элемента extension
Листинг 31. Класс RecipeScaler
package com.backstop;
public class RecipeScaler {
public static String scaleMessage (org.apache.xalan.extensions.XSLProcessorContext context,
org.w3c.dom.Element thisElement){
return "This recipe has been scaled by a factor of " +
thisElement.getAttribute("servings") + ".";
}
}
Рисунок 10. Результаты элемента extension
Функции extension
Листинг 32. Метод scaleIngredient()
package com.backstop;
public class RecipeScaler {
public static String scaleMessage (org.apache.xalan.extensions.XSLProcessorContext context,
org.w3c.dom.Element thisElement){
return "This recipe has been scaled by a factor of " +
thisElement.getAttribute("servings") + ".";
}
public static int scaleIngredient(int servings, int original){
return (servings * original);
}
}
Листинг 33. Добавление функции extension
Рисунок 11. Использование функции extension
Программирование XSLT
Переменные XSLT
Листинг 34. Задание переменной
Рисунок 12. Использование переменной
Условная обработка
Листинг 35. Использование элемента if
Рисунок 13. Результаты предложения if
Листинг 36. Элемент choose
Рисунок 14. Результат
Заключение
Подведение итогов
Введение
Данные в формате xml
xsl-шаблон
Список контрагентов
Цикл for-each и правила выбора
Сортировка
Отображение значения
Гиперссылки
Сase-оператор и фильтрация
Еще один фильтр
Список контрагентов
Результат
Вывод
2. Валидный XHTML
.
, ).
3. XSLT-преобразования
Файл - test.xsl
xml version=?>
Результат - исходный код
xml version="1.0"
encoding="windows-1251"
?>
"http://www.w3.org/1999/xhtml"
xml:lang="ru"
>
IE 6
FireFox 3
Opera 9.02
// Вывод кода HTML в виде текста
header("Content-Type: text/plain;"
);
// Объект исходного XML-документа
$xml
= new
DOMDocument(null
, "windows-1251"
);
$xml
->load("test.xml"
);
// Объект стиля
$xsl
= new
DOMDocument(null
, "windows-1251"
);
$xsl
->load("test.xsl"
);
// Создание парсера
$proc
= new
XSLTProcessor();
// Подключение стиля к парсеру
$proc
->importStylesheet($xsl
);
// Обработка парсером исходного XML-документа
$parsed
= $proc
->transformToXml($xml
);
// Вывод результирующего кода
echo
$parsed
;
// Запись файла с результирующим кодом
file_put_contents("parsed.html"
, $parsed
);
?>
Мысли вслух