Поясним, что это преобразование выполняет не просто копирование документа (для этого было бы достаточно элемента
xsl:copy-of
). Идентичное преобразование переопределяет встроенные шаблоны; теперь, если для обработки какого-либо узла в преобразовании не определено подходящего шаблона, он вместе со всеми своими потомками будет скопирован в выходящий документ без изменений.
Идентичное преобразование очень полезно в тех случаях, когда требуется изменить только некоторые части документа, оставив остальное в неприкосновенности. Например, в предыдущем примере нам нужно было только переименовать все документы
bold
. Искомое преобразование, импортирующее
идентичное преобразование из файла
identity.xsl
, будет записано следующим образом.
Листинг 5.12
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="#"/>
<xsl:template match="bold">
<b>
<xsl:apply-templates/>
</b>
</xsl:template>
</xsl:stylesheet>
Результат будет иметь вид:
<a>
text a
<b>
text b
<b/>
</b>
<c>
text c
</c>
</a>
Другим примером использования идентичного преобразования может послужить случай, когда нужно просто удалить из документа некоторые узлы. Например, нам необходимо избавиться от комментариев (быстро и без шума).
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="#"/>
<xsl:template match="comment"/>
</xsl:stylesheet>
Разрешение конфликтов в шаблонах
Как правило, каждое преобразование в XSLT определяет, включает или импортирует множество шаблонов, которые обрабатывают указанные части документов. При этом один и тот же узел документа может соответствовать нескольким шаблонным правилам. К примеру, элемент
content
может быть обработан любым из следующих трех шаблонов.
Листинг 5.14. Конфликтующие шаблоны
<xsl:template match="*">
<element/>
</xsl:template>
<xsl:template match="node">
<node/>
</xsl:template>
<xsl:template match="content">
<content/>
</xsl:template>
Ситуация, когда для обработки узла может быть применено несколько правил, называется конфликтом шаблонов. Конфликты такого рода неизбежны практически в любом преобразовании, к примеру, большинство шаблонов будет вступать в конфликт со встроенными правилами преобразования.
Для того чтобы в конфликтной ситуации решить, какой именно из
шаблонов должен быть применен к данному узлу, процессоры используют два простых правила.
□ Шаблоны, имеющие младший порядок импорта, исключаются из рассмотрения. Иными словами, из множества правил, подходящих для обработки текущего узла, остаются только правила, имеющие самый старший порядок импорта.
□ Из оставшегося множества выбирается шаблон с наивысшим приоритетом. Если таких шаблонов несколько, процессор может либо выдать ошибку, либо применить тот, который описан в преобразовании последним.
Во втором из этих двух правил, мы встретились с понятием приоритета шаблона. Приоритет шаблона это не что иное, как численное значение, которое может быть указано в атрибуте
priority
элемента
xsl:template
. В том случае, если значение этого атрибута не определено, приоритет шаблонного правила вычисляется следующим образом.
□ Прежде всего, шаблон, который обрабатывает несколько альтернатив, перечисленных через знак "
|
", будет рассматриваться как множество шаблонов, обрабатывающих каждую из возможностей. Например, шаблон с атрибутом
match="b|bold|B"
будет рассматриваться как три одинаковых шаблона с атрибутами
match="b"
,
match="bold"
и
match="B"
соответственно.
□ Если паттерн состоит из имени (
QName
) или конструкции
processing-instruction(литерал)
, которым предшествует дескриптор оси дочернего узла или атрибута (
ChildOrAttributeAxisSpecifier
), приоритет шаблона равен
0
. Такие паттерны могут иметь следующий вид:
•
QName
или
child::QName
— выбор дочерних элементов;
•
@QName
или
attribute::QName
— выбор атрибутов;
•
processing-instruction(литерал)
или
child::processing-instruction(литерал)
— именной выбор дочерних инструкций по обработке.
Примеры паттернов с приоритетом, равным
0
:
•
content
— выбор дочернего элемента
content
;
•
fo:content
— выбор дочернего элемента
content
с префиксом пространств имен
fo
;
•
child::processing-instruction('арр')
— выбор дочерних инструкций по обработке, которые имеют вид
<?app содержимое?>
;
•
@xsd:name
— выбор атрибута
xsd:name
текущего узла;
•
@select
— выбор атрибута
select
текущего узла.
□ Если паттерн состоит из конструкции
NCName:*
, которой предшествует
ChildOrAxisSpecifier
, приоритет шаблона будет равен
– 0.25
. Такие паттерны могут иметь следующий вид:
•
префикс:*
или
child::префикс:*
— выбор всех дочерних элементов в определенном пространстве имен;