Выбрать главу
Листинг 5.11. Идентичное преобразование

<xsclass="underline" stylesheet version="1.0"

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

 <xsclass="underline" template match="@*|node()">

  <xsclass="underline" copy>

   <xsclass="underline" apply-templates select="@*|node()"/>

  </xsclass="underline" copy>

 </xsclass="underline" template>

</xsclass="underline" stylesheet>

Единственный шаблон этого преобразования при помощи элемента xsclass="underline" copy рекурсивно создает в выходящем документе копии узлов и атрибутов. На практике идентичное преобразование используется очень часто, и потому мы настоятельно рекомендуем сохранить его в отдельном файле и импортировать при потребности.

Поясним, что это преобразование выполняет не просто копирование документа (для этого было бы достаточно элемента xsclass="underline" copy-of). Идентичное преобразование переопределяет встроенные шаблоны; теперь, если для обработки какого-либо узла в преобразовании не определено подходящего шаблона, он вместе со всеми своими потомками будет скопирован в выходящий документ без изменений.

Идентичное преобразование очень полезно в тех случаях, когда требуется изменить только некоторые части документа, оставив остальное в неприкосновенности. Например, в предыдущем примере нам нужно было только переименовать все документы bold. Искомое преобразование, импортирующее идентичное преобразование из файла identity.xsl, будет записано следующим образом.

Листинг 5.12

<xsclass="underline" stylesheet

 version="1.0"

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

 <xsclass="underline" import href="identity.xsl"/>

 <xsclass="underline" template match="bold">

  <b>

   <xsclass="underline" apply-templates/>

  </b>

 </xsclass="underline" template>

</xsclass="underline" stylesheet>

Результат будет иметь вид:

<a>

 text a

 <b>

  text b

  <b/>

 </b>

 <c>

  text c

 </c>

</a>

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

<xsclass="underline" stylesheet

 version="1.0"

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

 <xsclass="underline" import href="identity.xsl"/>

 <xsclass="underline" template match="comment()"/>

</xsclass="underline" stylesheet>

Разрешение конфликтов в шаблонах

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

Листинг 5.14. Конфликтующие шаблоны

<xsclass="underline" template match="*">

 <element/>

</xsclass="underline" template>

<xsclass="underline" template match="node()">

 <node/>

</xsclass="underline" template>

<xsclass="underline" template match="content">

 <content/>

</xsclass="underline" template>

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

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

□ Шаблоны, имеющие младший порядок импорта, исключаются из рассмотрения. Иными словами, из множества правил, подходящих для обработки текущего узла, остаются только правила, имеющие самый старший порядок импорта.

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

Во втором из этих двух правил, мы встретились с понятием приоритета шаблона. Приоритет шаблона это не что иное, как численное значение, которое может быть указано в атрибуте priority элемента xsclass="underline" 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::префикс:* — выбор всех дочерних элементов в определенном пространстве имен;

 • @префикс:* или attribute::префикс:* — выбор всех атрибутов в определенном пространстве имен.

Примеры паттернов с приоритетом, равным -0.25:

 • fo:* — выбор всех дочерних элементов в пространстве имен с префиксом fo;