Выбрать главу

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

  <xsclass="underline" copy>

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

  </xsclass="underline" copy>

 </xsclass="underline" template>

 <xsclass="underline" template match="b" mode="second">

  <c>

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

  </c>

 </xsclass="underline" template>

 <!-- Основное преобразование -->

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

  <!-- Присваиваем переменной а корень входящего документа -->

  <xsclass="underline" variable name="a" select="/"/>

  <!-- Выводим переменную a -->

  <xsclass="underline" comment> a: </xsclass="underline" comment>

  <xsclass="underline" copy-of select="$a"/>

  <!-- Присваиваем переменной b результат обработки переменной a -->

  <xsclass="underline" variable name="b">

   <xsclass="underline" apply-templates select="$a" mode="first"/>

  </xsclass="underline" variable>

  <!-- Выводим переменную b -->

  <xsclass="underline" comment> b: </xsclass="underline" comment>

  <xsclass="underline" copy-of select="$b"/>

  <!-- Присваиваем переменной с результат обработки переменной b -->

  <xsclass="underline" variable name="c">

   <xsclass="underline" apply-templates select="xalan:nodeset($b)" mode="second"/>

  </xsclass="underline" variable>

  <!-- Выводим переменную c -->

  <xsclass="underline" comment> c: </xsclass="underline" comment>

  <xsclass="underline" copy-of select="$c"/>

 </xsclass="underline" template>

</xsclass="underline" stylesheet>

Ход этого преобразования лучше всего прокомментирует полученный результат.

Листинг 10.16. Входящий документ

<а>

 <a>1</a>

 <a>2</a>

</а>

Листинг 10.17. Выходящий документ

<!-- а: -->

<а>

 <a>1</a>

 <a>2</a>

</а>

<!-- b:-->

<b>

 <b>1</b>

 <b>2</b>

</b>

<!-- с: -->

<с>

 <c>1</c>

 <c>2</c>

</с>

Элементы расширения

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

Пример

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

<p>This page was generated at 10:23.</p>

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

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

 <!-- ... -->

 <p>This page was generated at <ext:time/>.</p>

</xsclass="underline" template>

элемент расширения ext:time должен быть заменен текущим временем. Ниже мы приведем пример реализации этого элемента для процессора Xalan.

Интерфейс программирования расширений в Xalan требует, чтобы для каждого элемента расширения был определен метод вида:

тип элемент(org.apache.xalan.extensions.XSLProcessorContext context,

            org.apache.xalan.templates.ElemExtensionCall elem)

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

public String time(XSLProcessorContext context,

                   ElemExtensionCall elem)

Два аргумента, которые передаются методу элемента расширения, описывают контекст преобразования (XSLProcessorContext) и параметры вызова элемента расширения (ElemExtensionCall). Чуть позже мы покажем, как можно использовать эти объекты для создания более функциональных элементов расширения; пока же продолжим с элементом ext:time.

Следующим шагом мы создадим класс расширения ext.java, в котором реализуем описанный выше метод time.

Листинг 10.18 Класс ext.java

package de.fzi.xslt;

import java.util.Date;

import java.text.SimpleDateFormat;

import org.apache.xalan.extensions.XSLProcessorContext;

import org.apache.xalan.templates.ElemExtensionCall;

public class ext {

 public String time(XSLProcessorContext context,

  ElemExtensionCall elem) {

  SimpleDateFormat df = new SimpleDateFormat("HH:mm");

  return df.format(new Date());

 }

}

Равно как и в случае с функциями расширения, связующим звеном между элементами и Java-имплементацией их семантики служат пространства имен. В нашем случае класс de.fzi.xslt.ext может быть связан с префиксом пространства имен ext следующим объявлением:

xmlns:ext="xalan://de.fzi.xslt.ext"

Однако это еще не все. Для того чтобы элементы определенного пространства имен воспринимались процессором как элементы расширения, необходимо также явно указать префиксы этих пространств в атрибуте extension-element-prefixes элемента xsclass="underline" stylesheet:

<xsclass="underline" stylesheet

 ...

 extension-element-prefixes="ext">

 ...

</xsclass="underline" stylesheet>

В итоге наше преобразование будет иметь следующий вид.

Листинг 10.19. Преобразование, использующее элемент расширения

<xsclass="underline" stylesheet

 version="1.0"

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

 xmlns:ext="xalan://de.fzi.xslt.ext"

 extension-element-prefixes="ext">

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

  <!-- ... -->

  <p>This page was generated at <ext:time/>.</p>

 </xsclass="underline" template>