Эта глава полностью посвящена созданию шаблонов и работе с ними как с основой таблиц стилей XSLT. Каждый шаблон образует правило, которое процессор XSLT пытается применить к исходному документу.
В главе 2 мы кратко рассмотрели таблицы стилей и основные шаблоны, при помощи которых наши примеры таблиц стилей в действительности могли что-то сделать. В этой главе мы собираемся подробно изучить шаблоны, а в следующей мы увидим, какие виды выражений можно применять для создания образцов выбора в шаблонах, позволяющих находить требуемые узлы. Образцы выбора (match pattern) являются подмножеством всего языка XPath и достаточно сложны для того, чтобы посвятить им отдельную главу.
В этой главе мы сначала рассмотрим, как работают основные шаблоны, и затем перейдем к таким темам, как правила шаблонов по умолчанию, выбор шаблона для работы, обработка атрибутов, создание мелких и глубоких копий элементов, завершение обработки шаблона и многое другое.
В главе 2 для выбора узлов в
planets.xml
и преобразования этого документа в HTML я создал основной шаблон. Шаблоны в таблицах стилей создаются при помощи элементов
, задающих правила для требуемых преобразований. Мы создали шаблон, находивший корневой элемент
по образцу "/PLANETS
", которому соответствуют все элементы
, дочерние для корневого узла:
xmlns:xsl="http.//www.w3.org/1999/XSL/Transform">
.
.
.
.
.
.
Когда процессор XSLT находит узел, удовлетворяющий образцу вашего шаблона, этот узел становится контекстным узлом шаблона, то есть все операции производятся над этим узлом. На текущий узел можно ссылаться при помощи выражения XPath «.». Другие выражения XPath мы рассмотрим в этой главе и в главе 7.
УСОВЕРШЕНСТВОВАНИЯ В XSLT 2.0
В XSLT 1.0 возникали трудности при выборе элементов или атрибутов с нулевыми значениями, что должно быть исправлено в XSLT 2.0.
Внутри шаблона создайте разметку HTML, начинающую требуемую таблицу, — такая прямая вставка разметки называется элементом буквального (literal) результата. Когда процессор встречает литерал, он копирует его в результирующее дерево:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
.
.
.
Однако это правило обрабатывает только элемент
, но не его дочерние элементы
, содержащие сами данные. В соответствии с правилами шаблона по умолчанию, элементы
будут обрабатываться, если установить шаблон для их выбора. Это, кстати, нежелательно, поскольку я хочу вставить результат обработки элементов
в определенное место в создаваемом файле HTML. Для этого мне потребуется применить элемент
.
Элемент
дает указание процессору XSLT обрабатывать все совпадающие шаблоны для дочерних узлов контекстного узла. Элемент
дает возможность явно указать, когда следует закончить обработку дочерних узлов, а это имеет решающее значение при вставке их данных в нужное место в HTML-таблице.
Один важный момент часто вызывает затруднения: элемент
по умолчанию применяет шаблоны только к дочерним узлам контекстного или выбранного узла или набора узлов. Это выглядит довольно безобидно, но многие люди забывают о том, что атрибуты не считаются дочерними узлами элементов и также ими не являются объявления пространств имен. Это значит, что для обработки как элементов, так и атрибутов следует осуществить еще один или два дополнительных шага, что мы увидим далее в этой главе.
В следующем примере мы поместим элемент
туда, куда нам требуется вставить данные из элементов
в таблицу HTML. Я также добавил новый шаблон для обработки элементов
:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
.
.
.
В новом шаблоне, обрабатывающем элементы
, я должен извлечь данные из каждого элемента
, то есть восстановить значения в дочерних элементах элемента
, таких как
,
и т.д.:
Mercury
.0553
58.65
1516
.983
43.4
.
.
.
Это можно сделать при помощи элемента
.
Элемент
записывает в результирующий документ строковое значение выражения; в частности, с его помощью можно возвратить значение узла, которым для элемента будет заключенный в элемент текст. Атрибуту выбора элемента
можно присвоить выражение XPath, задающее узел или набор узлов. В шаблоне, задающем элементы
, обратиться к дочернему элементу
можно при помощи выражения XPath "child::MASS
". Как мы увидим в главе 4, выражения XPath можно писать разными способами: например, вместо "child::MASS
" можно просто написать "MASS
". Таким образом, получить данные дочерних элементов, таких как
,
и т.д., можно следующим способом (листинг 3.1).
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
<Н1>
The Planets Table
Н1>
Name
Mass
Radius
Day
Как вы могли ожидать, исходя из того, что "
child::MASS
" можно представить в виде "MASS
" и применения шаблонов, таких как "/
", "/PLANETS
" и т.д., вплотную познакомиться с созданием образцов выбора не так-то просто — этому посвящена вся глава 4.
Образцы выбора (match pattern) являются подмножеством полного языка XPath, их можно использовать в элементах
>,
и
. В частности, в образец можно установить атрибут match у
и
, и атрибуты count
и from
элемента
. В следующем списке приведен ряд примеров образцов выбора, много других примеров будет показано в главе 4 при подробном обсуждении использования XPath для выбора узлов и атрибутов:
• "
/
" выбирает корневой узел;
• "
*
" выбирает элементы узлов (но не всех узлов, как зачастую ошибочно полагают);
• "
PLANET
" выбирает элементы
;
• "
PLANET/MASS
" выбирает все элементы
, дочерние для элемента
;
• "
//PLANET
" выбирает все элементы
, производные от корневого узла;
• "
.
" выбирает текущий узел (технически это не образец выбора, а выражение XPath, как мы увидим в главе 7).
Образцы можно также использовать в атрибуте
select
элементов
,
,
,
и
; фактически атрибут select
этих элементов может содержать полные выражения XPath, а не только образцы выбора. Атрибут select
элемента
определяет дочерний узел, значение которого нужно получить:
Теперь пора воспользоваться атрибутом
select
элемента
, поскольку это даст нам возможность указать, какой шаблон использовать и когда.
Вплоть до нынешнего момента я использовал только версию элемента
по умолчанию, как, например:
Name
Mass
Radius
Day
Простое использование только
указывает процессору XSLT осуществлять поиск всех шаблонов, выбирающих дочерние узлы контекстного узла, — это использование по умолчанию. Однако иногда это не лучший вариант, поскольку может потребоваться применять шаблоны в определенном порядке или иным образом выбрать применяемые шаблоны (последнее можно сделать при помощи атрибута select
элемента
).
Например, до сих пор мы только получали значение каждого элемента
,
и
при помощи
:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Н1>
Name
Mass
Radius
Day
Здесь только извлекается «сырое» строковое значение каждого узла, которое помещается в HTML-таблицу. Однако может потребоваться дополнительная обработка каждого элемента — например, получить также значения атрибутов UNITS каждого элемента и отобразить их:
Mercury .0553
58.65
1516
.983
43.4
.
.
.
Для этого нельзя просто применить элемент
, поскольку он вернет значение узла только как текст, а не как значения атрибута. Вместо этого нужно создать новый набор шаблонов, по одному для каждого интересующего нас элемента:
,
и
. У элемента
нет никаких атрибутов, поэтому для него не нужны шаблоны — нужно только значение узла. Каждому из этих новых шаблонов требуется получить значение элемента, а также значение атрибута UNITS
.
Чтобы быть уверенным в том, что эти новые шаблоны применяются в правильном порядке, соответствующем заголовкам HTML-таблицы, я явно перечислю все новые шаблоны, выбирая их один за другим при помощи атрибута
select
:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
ИСПОЛЬЗОВАНИЕ ИМЕНОВАННЫХ ШАБЛОНОВ
К шаблонам можно также обращаться по имени. Этот вопрос будет рассмотрен в главе 9.
Теперь к каждому элементу
,
и
применяется новый шаблон: мы не просто получаем строковое значение узла при помощи
, мы можем дополнительно обработать каждый элемент — например, прочитать значения атрибута UNITS
. Сначала я получу строковые значения каждого из элементов
,
и
. Теперь, когда у нас есть шаблон для каждого из этих узлов-элементов и каждый узел является контекстным узлом в своем шаблоне, вместо того, чтобы ссылаться на узел элемента по имени, мы можем сослаться на него как на контекстный узел при помощи выражения XPath "." (листинг 3.2):
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
Этот код только воспроизводит то, что мы уже делали ранее в предыдущей версии
planets.xsl
, использующей
,
и т.д., то есть читающей и отображающей данные каждого элемента
,
и
. Теперь же, когда у нас есть отдельный шаблон для каждого из этих элементов, можно осуществить дополнительную обработку — например чтение значений атрибутов.
Чтобы получить доступ к значению атрибута при помощи XPath, нужно добавить к имени атрибута префикс @, например: "
@src
", "@height
", "@width
" и т.д.
Для выбора любого атрибута можно применить выражение "
@*
". Чтобы сослаться на атрибут UNITS
в каждом элементе
,
и
, следует использовать выражение "@UNITS
". Следовательно, получить значения и отобразить единицы (unit) каждого измерения в planets.xml
можно так (листинг 3.3).
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
Результаты работы показаны на рис. 3.1, Как видите, теперь мы извлекли строковое значение атрибута UNITS и отобразили его.
Рис. 3.1. Вывод значений атрибутов, первый вариант
Рисунок 3.1 не совсем точен: обратите внимание на то, что между значением и соответствующей единицей измерения в таблице нет пробела. Процессор XSLT просто поместил в результирующее дерево текст без каких-либо разделителей между текстовыми узлами. Хотя это в точности соответствует требованиям рекомендации XSLT, нам бы хотелось, чтобы элементы таблицы выглядели как «1516 miles», а не «1516miles». Как нам добавить этот дополнительный пробел?
Работа с пробелами всегда обсуждается при рассмотрении XSLT, и в данной главе я уделю этой теме некоторое время. Вставить единственный пробел несложно при помощи элемента
, который используется для вставки символьного текста непосредственно в дерево вывода. У этого элемента только один атрибут:
•
disable-output-escaping
. Устанавливается в yes
для того, чтобы такие символы, как < и >, выводились буквально, а не как <
и >
. По умолчанию установлен в no
.
Этот элемент может содержать только текстовый узел.
Текстовые узлы создаются при помощи элемента
, позволяющего по ходу дела замещать элементы целиком на текст. Одна из целей применения
— сохранить символы-разделители, как в следующем примере (листинг 3.4), в котором элемент
используется для вставки пробелов.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
Новый результат виден на рис. 3.2, на котором между числовыми значениями и их единицами измерения вставлены пробелы.
Рис. 3.2. Вывод значений атрибутов, второй вариант
Как видите, элемент
весьма удобен. Тем не менее вам следует знать вот что: по умолчанию элементы
заменяют символы, которые могут входить в разметку, на эскейп-последовательности. Например, Here is а greater-than sign: >
будет выведено как «Here is a greater-than sign: >,», а не как «Herе is a greater-than sign: >». А если попытаться использовать < внутри элемента
, процессор XSLT посчитает, что вы пытаетесь открыть элемент внутри элемента
, что неверно. Как же вывести значащие символы, такие как < и >, если есть необходимость? Это можно сделать путем отключения вывода ESC-последовательностей (disabling output escaping).
УСОВЕРШЕНСТВОВАНИЯ В XSLT 2.0
Один из вопросов, которые призван решить XSLT 2.0, это упрощение импорта подобного текста без разбора из других файлов.
При помощи
можно включать в выходной документ непосредственно символы < и &, а не последовательности <
и &
. Для этого следует установить атрибут disable-output-escaping
элемента
в yes («да», по умолчанию он установлен в no
, «нет»). В приведенном ниже примере я при помощи
непосредственно пишу текст "
" в выходной документ:
version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Planets
<PLANET/>
Результат следующий:
Planets
Разумеется, не обязательно выводить
при помощи
: этот элемент можно было поместить непосредственно в элемент буквального результата. Но что делать в тех случаях, когда процессор XSLT не сможет распознать нужный нам в выходном документе элемент как фактический элемент? Например, в преобразованных документах XHTML вам потребуется
, но процессор XSLT сочтет, что это не хорошо сформированный XML. Как поместить этот элемент в выходные данные?
Можно попробовать поместить этот элемент в раздел
, как мы увидим в главе 6, и попытаться трактовать его как простые символьные данные, но процессоры XSLT все равно заменят < на <
, а > на >
.
Правильный способ добавить в вывод элемент
— использовать атрибут doctype-public
элемента
, как мы увидим в главе 6, но в качестве демонстрации для этих целей здесь я отключу вывод ESC-последовательностей в элементе
(хотя этот способ не рекомендован для создания элементов
). Вот как это выглядит:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
А вот результат:
The Planets Table
The Planets Table
.
.
.
Далее в книге будут приведены другие примеры использования
, в том числе — при обсуждении символов-разделителей далее в этой главе.
В XSLT есть несколько способов написать значения атрибутов в выходные документы, и наиболее мощный — это создать атрибуты с нуля при помощи элемента
, как мы увидим в главе 6.
Однако можно также во многих случаях использовать шаблоны значений атрибутов, с которыми мы познакомимся в этой главе.
Предположим, например, что нам требуется преобразовать текст в таких элементах, как
,
и
, в атрибуты элементов
, преобразуя planets.xml
в следующий вид:
MASS=".0553 (Earth = 1)" NAME="Mercury"/>
MASS=".815 (Earth = 1)" NAME="Venus"/>
MASS="1 (Earth = 1)" NAME="Earth"/>
Чтобы создать преобразование, нельзя просто использовать следующее выражение, в котором я взял значения элементов
,
и
и попытался сделать их значениями атрибутов:
"
MASS=" "
DAY=" "
/>
Это не будет работать, поскольку нельзя использовать < внутри значений атрибутов, как я сделал в предыдущем примере. В XSLT для этого есть несколько способов. Один из них — использовать шаблоны значений атрибутов.
Шаблон имени значения атрибута не имеет ничего общего с теми шаблонами, с которыми мы до сих пор работали, — то есть с шаблонами для создания правил таблицы стилей. Напротив, применение шаблона значения атрибута (attribute value template) означает лишь, что значение атрибута может быть установлено во время выполнения.
В этом случае атрибут можно установить в значение выражения XPath (более подробно эта тема изучается в главе 4), если заключить выражение в фигурные скобки. Например, чтобы установить атрибут
NAME
в строковое значение элемента
, дочернего элемента контекстного узла, это значение можно присвоить следующим образом: NAME={DESCRIPTION}
.
В листинге 3.5 приведен правильный код XSLT, в котором значения элементов
,
,
и
присваиваются атрибутам элемента
с теми же именами.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Вот как это делается; посмотрите теперь на результирующий документ, в котором значения в различных элементах были преобразованы в атрибуты:
Предположим теперь, что нам также нужно включить все единицы измерения. Каждый элемент
,
и
содержит атрибут UNITS
, задающий единицы измерения, и можно извлечь эти значения. Контекстным узлом является элемент
, поскольку шаблон установлен для выбора этого элемента, поэтому на дочерние элементы
,
и
можно ссылаться как "MASS
", "NAME
" и "RADIUS
". Для обращения к атрибуту UNITS
этих элементов можно использовать синтаксис "MASS/@UNITS
", "NAME/@UNITS
", и "RADIUS/@UNITS
":
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
MASS="{MASS} {MASS/@UNITS}"
RADIUS="{RADIUS} {RADIUS/@UNITS}"
DAY="{DAY} {DAY/@UNITS}"/>
И вот результат, включающий единицы измерения:
MASS=".0553 (Earth = 1)" NAME="Mercury"/>
MASS=".815 (Earth = 1)" NAME="Venus"/>
MASS="1 (Earth = 1)" NAME="Earth"/>
Заметьте, что в шаблонах значений атрибутов нельзя использовать вложенные фигурные скобки, и в выражении, использующем фигурные скобки, — таком как
function printHello {cout << 'Hello';}
— фигурные скобки необходимо удваивать, для того чтобы процессор XSLT их игнорировал: function printHello {{cout<<'Hello';}}
.
Шаблоны значений атрибутов всегда работают с контекстным узлом. Тем не менее, нельзя использовать шаблоны значений атрибутов в произвольном месте таблицы стилей, что зачастую и вызывает затруднения у XSLT-разработчиков. Шаблоны значений атрибутов можно использовать только в следующих местах:
• элементы буквального результата;
• элементы расширения (см. главу 5);
•
. Здесь можно использовать атрибуты name
и namespace
(см. главу 6);
•
. Здесь можно использовать атрибуты name
и namespace
(см. главу 6);
•
. Здесь можно использовать атрибуты format
, lang
, letter-value
, grouping-separator
и grouping-size
(см. главу 4);
•
. Здесь можно использовать атрибут name
(см. главу 6);
•
. Здесь можно использовать атрибуты lang
, data-type
, order
и case-order
(см. главу 5).
В главе 6 эта тема рассмотрена более подробно: мы узнаем, как создавать атрибуты (и новые элементы) с нуля. Дополнительная информация об использовании выражений XPath в шаблонах значений атрибутов приведена в главе 7.
Поначалу символы-разделители (whitespace) доставляют авторам XSLT много хлопот. В главе 2 объяснялось, что «чистые» узлы-разделители — это текстовые узлы, содержащие только символы-разделители (пробелы, возвраты каретки, переводы строки и символы табуляции). Эти узлы по умолчанию копируются из исходного документа.
Заметьте, что в таблице стилей также могут быть узлы-разделители:
В нашем случае пробелы используются для выравнивания элементов таблицы стилей, а возвраты каретки — для разрежения кода. Чистые узлы-разделители, такие, как этот, не копируются из таблицы стилей в выходной документ. Заметьте, однако, что разделитель из следующего элемента
копируется в выходной документ, так как это не чистый узел-разделитель (он также содержит текст «The Planets Table»):
The Planets Table
.
.
.
Если вы хотите убрать этот разделитель и сохранить выравнивание, можно использовать пустые элементы
, так чтобы символы-разделители стали чистыми узлами-разделителями:
The Planets Table
.
.
.
Чистые узлы-разделители не копируются из таблицы стилей в выходной документ, если только они не находятся внутри элемента
, или у элемента, в который они вложены, атрибут xml:space
не установлен в «preserve» (сохранить).
С другой стороны, по умолчанию XSLT сохраняет текстовые узлы разделители в исходном документе и копирует их в результирующий документ. Возьмите уже рассмотренную нами копирующую таблицу стилей, которая копирует все элементы из исходного документа в результирующий:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
и примените ее к
planets.xml
; все символы-разделители будут также скопированы в результирующий документ:
Mercury
.0553
58.65
1516
43.4
.
.
.
Тем не менее, иногда требуется удалить разделители, используемые при форматировании входных документов — это можно сделать при помощи элемента
.
Элемент
дает указание процессору XSLT убрать все чистые узлы-разделители (также называемые «потребляемыми», expendable, узлами-разделителями) из. выходного документа. Чистый узел-разделитель состоит только из символов-разделителей и не содержит текст какого-либо другого вида. У этого элемента только один атрибут:
•
elements
(обязательный). Задает элементы, из которых нужно убрать символы-разделители. Представляет, собой список разделённых символами-разделителями NameTest
(именами или обобщёнными именами с символами подстановок).
Элемент не включает содержимого. Например, чтобы удалить все узлы-разделители из
planets.xml
, можно применить
следующим образом:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Вот результирующий документ, полученный после применения этой таблицы стилей к
planets.xml
. Обратите внимание на то, что убраны все символы-разделители, в том числе все символы новой строки:
Mercury .0553 58.65 1516 .983 43.4 Venus .815 116.75 3716 .943 66.8 Earth 1 1 2107 1 128.4
Заметьте, что таким образом удаляются только чистые узлы-разделители. Например, текст элемента
Volcanoes for Dinner
не содержит чистых текстовых узлов-разделителей, поэтому текст «Volcanoes for Dinner» будет сохранен в выходном документе вместе с пробелами. Так будет даже тогда, когда текст будет содержать несколько пробелов подряд, как в «Volcanoes for Dinner».
В некоторых ситуациях может потребоваться не удалять все узлы-разделители из всего документа; задать элементы, в которых следует сохранить узлы-разделители, можно при помощи элемента
. У этого элемента такой же атрибут, что и у
:
•
elements
(обязательный). Задает элементы, в которых нужно сохранить символы-разделители. Представляет собой список разделенных символами-разделителями NameTest
(именами или обобщенными именами с символами подстановок).
Фактически элемент
является элементом по умолчанию для всех элементов в XSLT. Если вы использовали элемент
, все равно можно указать, в каком элементе или элементах нужно сохранить узлы-разделители, установив атрибут elements
элемента
в список этих элементов:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Обсужденные средства удаления и сохранения разделителей могут показаться слишком сложными для форматирования выходных документов выравнивающими пробелами, но, к счастью, существует простой способ: атрибут
indent
элемента
позволяет автоматически выровнять выходной документ.
Элемент
поддерживает атрибут indent
который устанавливается в «yes» или «no», и указывает процессору XSLT, нужно ли выравнивать результирующий документ. Как правило, выравнивание результирующего документа не имеет большого значения, поскольку с ним работает приложение, которому все равно, выровнен документ или нет, как мы видели в примерах преобразований XML- XML и XML-HTML. Однако иногда требуется представить результирующий документ в виде простого текста, и в таких случаях выравнивание документа для отображения иерархической структуры может оказаться удобным.
Способ работы процессора XSLT с переменной выравнивания не регламентируется W3C и зависит от процессора, поэтому для получения требуемого результата нужно экспериментировать. Пусть, например, у нас есть версия
planets.xml
без какого-либо выравнивания:
Mercury
.0553
58.65
1516
.983
43.4
Venus
.815
116.75
3716
.943
66.8
Earth
1
1
2107
1
128.4
При помощи элемента
можно указать процессору XSLT осуществлять выравнивание документа при преобразовании его в HTML (листинг 3.6).
The Planets Table
The Planets Table
Name
Mass
Radius
Day>/TD>
Результат применения таблицы с использованием процессора Saxon (в котором особенно хорошо реализовано выравнивание) с требуемым выравниванием:
The Planets Table
The Planets Table
Name
Mass
Radius
Day
Mercury
.0553
1516
58.65
Venus
.815
3716
116.75
Earth
1
2107
1
Как видите, в XSLT обработке символов-разделителей приходится уделять достаточное внимание, но процедура упрощается, если вы знаете, что происходит.
ВЫРАВНИВАНИЕ ДОКУМЕНТОВ В ЭТОЙ КНИГЕ
Способ выравнивания документов зависит от конкретного процессора XSLT. В этой книге документы выровнены для удобочитаемости, даже если в действительности документы не были выровнены процессором XSLT.
Взгляните на следующую таблицу стилей XSLT — в ней заданы правила для выбора корневого узла, узлов
и узлов
:
xmlns:xsl="http.//www.w3.org/1999/XSL/Transform">
Обратите внимание на правило для элемента
: в нем просто используется элемент
для применения шаблонов ко всем дочерним узлам. Однако при обработке шаблона существует правило по умолчанию: если для элемента не задано правило, автоматически вызывается
. Таким образом, следующая таблица стилей, в которой опущено правило для
, делает в точности то же, что и предыдущая:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
В этом случае я воспользовался преимуществом правил по умолчанию для шаблона. Ниже приведены правила для каждого вида узлов, которые будут применены, если не задать правило для узла явно:
• Корневой узел. По умолчанию вызывается
;
• Узлы элементов. По умолчанию вызывается
;
• Узлы атрибутов. Копирует в результирующий документ значение атрибута, однако копирует его как текст, но не как атрибут;
• Текстовые узлы. Копирует в результирующий документ текст;
• Узлы комментариев. Нет обработки XSLT, ничего не копируется;
• Узлы инструкций обработки. Нет обработки XSLT, ничего не копируется;
• Узлы пространств имен. Нет обработки XSLT, ничего не копируется.
Наиболее важное правило по умолчанию применяется к элементам и может быть выражено следующим образом:
Это правило приведено здесь только для гарантии того, что каждый элемент, от корня и ниже, будет обрабатываться при помощи
Правило по умолчанию для текстовых узлов можно выразить следующим образом: функция XSLT
text
выбирает текст узла, так что текст текстового узла добавляется в выходной документ:
Правило по умолчанию того же вида применяется к атрибутам, которые добавляются в выходной документ при помощи следующего правила, где выражение "@*" выбирает любой атрибут:
По умолчанию инструкции обработки не вставляются в выходной документ, поэтому их правило по умолчанию можно выразить просто при помощи следующей функции-инструкции обработки XSLT, которая выбирает инструкции обработки (как мы увидим в главе 8):
То же верно для комментариев — их правило по умолчанию может быть выражено при помощи функции XSLT
comment
, которая также будет рассмотрена в главе 8:
Подведем итоги рассмотрения правил по умолчанию: если вообще не задать никаких правил, все разбираемые символьные данные входного документа будут вставлены в выходной документ. Вот как выглядит таблица стилей, в которой не задано никаких явных правил:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
А вот результат применения этой таблицы стилей к
planets.xml
. Заметьте, что правило по умолчанию для атрибутов не применялось, потому что они не являются дочерними по отношению к другим узлам:
Mercury
.0553
58.65
1516
.983
43.4
Venus
.815
116.75
3716
.943
66.8
Earth
1
1
2107
1
128.4
ПРАВИЛА ПО УМОЛЧАНИЮ И INTERNET EXPLORER
Одна из проблем при работе с XSLT в Internet Explorer 5.5 или младше состоит в том, что браузер не предоставляет никаких правил по умолчанию. Необходимо задавать все правила самостоятельно, если только не установлен процессор MSXML3 в режиме замены (подробнее см. главу 2) или вы не обновили браузер до Internet Explorer 6.0.
Кроме того, узлы-разделители исходного документа сохраняются, поэтому можно считать, что следующее правило также является правилом по умолчанию:
.
Если ваше правило для узла не работает, то есть оно пусто, содержимое выбранного узла не будет скопировано в выходной документ. Таким способом при создании выходного документа можно выборочно удалять содержимое из исходного документа.
Предположим, нам нужно удалить из
planets.xml
все данные о планетах, за исключением их названий и данных о массе. Следующая таблица стилей выполняет данную задачу.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
А вот результирующий документ (отметьте, что я сохранил только элементы
и
):
Mercury
.0553(Earth = 1)
Venus
.815(Earth = 1)
Earth
1(Earth = 1)
Таким способом можно фильтровать XML-документы, создавая новые XML-документы только с требуемыми данными.
Еще одним важным аспектом работы с шаблонами является разрешение конфликтов. Если двум шаблонам удовлетворяют один и тот же узел или набор узлов, для определения применяемого шаблона XSLT учитывает их приоритет.
У каждого шаблона есть приоритет по умолчанию, основанный на значении атрибута
select
. Как правило, чем более сужающим является правило выбора или выражение (например, "PLANET
" и "*
"), тем выше его приоритет. В главе 4 мы рассмотрим, как процессор определяет приоритеты и как он работает с шаблонами, имеющими одинаковый приоритет.
Приоритет шаблона можно установить при помощи атрибута
priority
. В приведенном ниже листинге 3.8 правило, созданное элементом
, имеет меньший приоритет, чем правило, созданное элементом
.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
(Very heavy)
Процессор XSLT выбирает шаблон с наивысшим приоритетом, который добавляет текст "
(Very heavy)
" после каждого значения массы. В следующем примере использован шаблон с наивысшим приоритетом:
The Planets Table
The Planets Table
Н1>
Name
Mass
Radius
Day
Mercury
.0553(Very heavy)
1516 miles
58.65 days
Venus
.815(Very heavy)
3716 miles
116.75 days
Earth
1(Very heavy)
2107 miles
1 days
УСОВЕРШЕНСТВОВАНИЯ В XSLT 2.0
Вопрос приоритета шаблонов должен быть учтен в XSLT 2.0. В частности, W3C рассматривает возможность добавления нового элемента с предварительным названием
О приоритетах полезно знать еще одно: если двум шаблонам удовлетворяет один и тот же узел, и этим шаблонам не были присвоены приоритеты, процессор XSLT выберет шаблон с более узким правилом выбора. Например, условию "
PLANET
" будет отдано предпочтение перед обобщенным условием "*
".
Элемент
позволяет скопировать узел из исходного дерева в выходное. Заметьте, однако, что это поверхностное (shallow) копирование, при котором не копируются потомки и атрибуты узла. У элемента есть один атрибут:
•
use-attribute-sets
. Задает названия наборов атрибутов, которые нужно применить к создаваемому элементу. Принимает значение списка QName
, разделенных символами-разделителями. Этот атрибут можно использовать только в том случае, когда контекстный узел является элементом. Дополнительная информация о наборах атрибутов приведена в главе 6.
Этот элемент может содержать тело шаблона, которое используется только когда копируется корневой узел или элемент. Заметьте, что при применении к корневому узлу элемент
не задействован, поскольку узел выходного документа создается автоматически.
Приведенная в листинге 3.9 таблица стилей впервые появилась в главе 2; все, что она делает, — копирует все элементы из исходного документа в результирующий.
version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Однако
не копирует атрибуты — вот результат применения этой таблицы стилей к planets.xml
:
Mercury
.0553
58.65
1516
.983
43.4
Venus
.815
116.75
3716
.943
66.8
Earth
1
1
2107
1
128.4
Копирование атрибутов несколько сложнее, потому что нужно найти какой-либо способ применить
к каждому атрибуту элемента. Это можно сделать, например, при помощи элемента
, о котором пойдет речь в главе 5.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
А вот результат — заметьте, что на этот раз атрибуты не затронуты:
Mercury
.0553
58.65
1516
.983
43.4
Venus
.815
116.75
3716
.943
66.8
Earth
1
1
2107
1
128.4
Но есть более простой путь проверить, что копируются все дочерние узлы, атрибуты и другие потомки узлов: вместо элемента
можно применить
.
ГЛУБОКОЕ КОПИРОВАНИЕ
Пример использования
Элемент
позволяет осуществлять глубокое копирование узлов, при котором копируется не только узел, но и все его атрибуты и потомки. У этого элемента единственный атрибут:
•
select
(обязательный). Узел или набор копируемых узлов. Этот элемент пуст и не имеет содержимого.
Ниже приведен пример работы этого элемента; в этом случае я заменил в листинге 3.10 элемент
элементом
, который явно выбирает для копирования все атрибуты контекстного элемента.
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Этот код работает так же, как и предыдущий пример, копируя все элементы и атрибуты. С другой стороны, можно вообще обойтись без каких-либо изменений в листинге 3.10, — я могу просто использовать
для того, чтобы скопировать весь документ, выбрав корневой узел и скопировав всех его потомков:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
При помощи
можно также копировать конкретные узлы и их потомков вместо того, чтобы задавать подстановку *. Например, следующее правило копирует все элементы
и их потомков:
По этой причине я могу заменить элемент
на элемент
:
При помощи элемента
можно дать указание процессору XSLT отобразить сообщение и, по выбору, прекратить обработку таблицы стилей. У элемента
один атрибут:
•
terminate
(необязательный). Значение «yes» прекращает обработку. По умолчанию установлено «no».
Куда на самом деле будет отправлено сообщение, зависит от процессора XSLT. Для процессоров, основанных на Java, сообщение обычно отправляется в выходной поток ошибок Java, которому соответствует экран компьютера, если процессор XSLT был вызван из командной строки. Другие процессоры XSLT могут выводить сообщения во всплывающие окна или в web-страницы, отправляемые в браузеры.
В приведенном ниже листинге 3.12 я прекращаю обработку XSLT, когда процессор XSLT пытается преобразовать элемент
в planets.xml
, выводя сообщение "Sorry, DAY information is classified.
" (Извините, информация о параметре «ДЕНЬ» засекречена.).
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
The Planets Table
The Planets Table
Name
Mass
Radius
Day
Sorry. DAY information is classified.
Вот результаты применения этой таблицы стилей в Xalan:
C:\planets>java org.apache.xalan xslt.Process -IN planets.xml -XSL message.xsl -OUT planets.html
file:///C:/XSL/messages/message.xsl: Line 49; Column 38;
Sorry. DAY information is classified.
XSLT Error (javax.xml.transform.TransformerException):
Stylesheet directed termination
При помощи элемента
можно выводить информацию о том, что происходит при обработке таблицы стилей, что может пригодиться не только для вывода ошибок и предупреждений, но и для отладки таблиц стилей.
Далее в книге будут рассмотрены и другие посвященные шаблонам темы — такие, как вызов именованных шаблонов и использование параметров. В следующей главе мы перейдем к большой и важной теме — созданию образцов выбора, при помощи которых в XSLT можно выбирать, какие узел или узлы вам нужны для работы. Мы уже затрагивали тему работы с образцами выбора, теперь же пора перейти к их систематическому рассмотрению.