KnigaRead.com/

Алексей Валиков - Технология XSLT

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Алексей Валиков, "Технология XSLT" бесплатно, без регистрации.
Перейти на страницу:

Представим себе два простых преобразования, first.xsl и second.xsl, первое из которых заменяет во входящем документе элементы а на элементы b, а второе — элементы b на элементы с.

Листинг 10.13. Преобразование first.xsl

<xsl:stylesheet

 version="1.0"

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


 <xsl:template match="a">

  <b>

   <xsl:apply-templates select="@*|node()"/>

  </b>

 </xsl:template>


 <xsl:template match="@*|node()">

  <xsl:copy>

   <xsl:apply-templates select="@*|node()"/>

  </xsl:copy>

 </xsl:template>


</xsl:stylesheet>

Листинг 10.14. Преобразование second.xsl

<xsl:stylesheet

 version="1.0"

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


 <xsl:template match="b">

  <c>

   <xsl:apply-templates select="@*|node()"/>

  </c>

 </xsl:template>


 <xsl:template match="@*|node()">

  <xsl:copy>

   <xsl:apply-templates select="@*|node()"/>

   </xsl:copy>

  </xsl:template>


</xsl:stylesheet>

Для того чтобы последовательно применить два этих преобразования к некоторому входящему документу a.xml, мы можем, например, дважды вызвать процессор:

java org.apache.xalan.xslt.Process -IN a.xml -XSL first.xsl -OUT b.xml

java org.apache.xalan.xslt.Process -IN b.xml -XSL second.xsl -OUT c.xml

В результате этих вызовов XSLT-процессор Xalan сначала применит преобразование first.xsl к документу a.xml и сохранит результат в файле b.xml, а затем обработает полученный документ b.xml при помощи преобразования second.xml и сохранит результат в файле c.xml.

В качестве альтернативы, например, для тех случаев, когда пакетная обработка невозможна, мы можем создать преобразование, последовательно применяющее шаблоны преобразований first.xsl и second.xsl к входящему документу. Для этого:

□ назначим шаблонам преобразования first.xsl режим first, а шаблонам преобразования second.xsl — режим second;

□ в основном шаблоне применим шаблоны режима first к узлам входящего документа, сохранив результат в переменной b;

□ приведем результирующее дерево, содержащееся в переменной b ко множеству узлов;

□ обработаем полученное множество узлов шаблонами режима second.

Следующий листинг демонстрирует предложенный подход.

Листинг 10.5. Преобразование first-then-second.xsl

<xsl:stylesheet

 version="1.0"

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

 xmlns:xalan="http://xml.apache.org/xalan"

 exclude-result-prefixes="xalan">


 <!-- Шаблоны преобразования first -->

 <xsl:template match="a" mode="first">

  <b>

   <xsl:apply-templates select="@*|node()" mode="first"/>

  </b>

 </xsl:template>


 <xsl:template match="@*|node()" mode="first">

  <xsl:copy>

   <xsl:apply-templates select="@*|node()" mode="first"/>

  </xsl:copy>

 </xsl:template>


 <!-- Шаблоны преобразования second -->

 <xsl:template match="@*|node()" mode="second">

  <xsl:copy>

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

  </xsl:copy>

 </xsl:template>


 <xsl:template match="b" mode="second">

  <c>

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

  </c>

 </xsl:template>


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

 <xsl:template match="/">

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

  <xsl:variable name="a" select="/"/>

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

  <xsl:comment> a: </xsl:comment>

  <xsl:copy-of select="$a"/>

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

  <xsl:variable name="b">

   <xsl:apply-templates select="$a" mode="first"/>

  </xsl:variable>

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

  <xsl:comment> b: </xsl:comment>

  <xsl:copy-of select="$b"/>

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

  <xsl:variable name="c">

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

  </xsl:variable>

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

  <xsl:comment> c: </xsl:comment>

  <xsl:copy-of select="$c"/>

 </xsl:template>


</xsl: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-классов.

Пример

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

This page was generated at 10:23.

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

<xsl:template match="/">

 <!-- ... -->

 

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

</xsl: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 элемента xsl:stylesheet:

<xsl:stylesheet

 ...

 extension-element-prefixes="ext">

 ...

</xsl:stylesheet>

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

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

<xsl:stylesheet

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*