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

</xsclass="underline" stylesheet>

Результатом этого преобразования будет документ вида:

<p>This page was generated at 11:56.</p>

Функциональность предложенного выше элемента расширения может быть легко расширена. Например, мы можем создать элемент ext:date, который будет выводить текущую дату или время в формате, зависящем от значения его атрибута pattern.

Листинг 10.20. Класс ext.java реализация элемента ext:date

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 date(XSLProcessorContext context, ElemExtensionCall elem) {

  SimpleDateFormat df;

  // Получаем значение атрибута pattern элемента расширения

  String pattern = elem.getAttribute("pattern");

  // Если атрибут pattern не определен,

  // используем образец форматирования, определенный по умолчанию

  if (pattern == null)

   df = new SimpleDateFormat();

  // Если атрибут pattern определен, используем его значение

  // в качестве образца форматирования

  else

   df = new SimpleDateFormat(pattern);

  return df.format(new Date());

 }

}

В преобразовании этот элемент мы можем использовать как:

<p>This page was generated at <ext:date pattern="HH:mm"/> on

<ext:date pattern="dd/MM/yyyy"/>.</p>

или:

<p>This page was generated on <ext:date/>.</p>

В первом случае результатом будет:

<p>This page was generated at 12:11 on 08/10/2001.</p>

Во втором:

<p>This page was generated on 08.10.01 12:11.</p>

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

Функция element-available

boolean element-available(string)

Функция element-available совершенно аналогична функции function-available: она служит для проверки доступности в преобразовании того или иного элемента. Строковый параметр element-available задает расширенное имя элемента; функция возвращает true, если элемент с таким именем доступен, false — если нет.

Пример

Предположим, что преобразование, созданное нами для процессора Xalan с использованием элемента расширения ext:date, будет выполняться на каком-либо другом процессоре. В этом случае велика вероятность того, что вследствие несовместимости механизмов расширений это преобразование завершится ошибкой — "чужой" процессор просто не сможет выполнить элемент ext:date.

Во избежание этого, мы можем использовать функцию element-available для проверки доступности элемента ext:date до его вызова.

Листинг 10.21. Преобразование, использующее функцию element-available

<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="/">

  <result>

   <xsclass="underline" if test="element-available('ext:date')">

    <p>This page was generated at <ext:date pattern="HH:mm"/> on <ext:date pattern="dd/MM/yyyy"/>.</p>

   </xsclass="underline" if>

  </result>

 </xsclass="underline" template>

</xsclass="underline" stylesheet>

Элемент xsclass="underline" fallback

Другим способом обработки исключительных ситуаций, связанных с невозможностью выполнить тот или иной элемент преобразования, является использование элемента xsclass="underline" fallback. Синтаксическая конструкция этого элемента следующая:

<xsclass="underline" fallback>

 <!-- Содержимое: шаблон -->

</xsclass="underline" fallback>

Элемент xsclass="underline" fallback включается в "критическую" инструкцию, то есть в элемент, который может быть неизвестен процессору. В случае, если критическая инструкция отрабатывается нормально, содержимое xsclass="underline" fallback попросту игнорируется. Иначе, если процессор в силу некоторых причин не может выполнить критическую инструкцию, вместо нее он будет выполнять содержимое дочернего элемента xsclass="underline" fallback.

Пример

На тот случай, если процессор не сможет выполнить наш элемент расширения ext:date, мы можем "подстраховать" его следующим образом:

<ext:date pattern="HH:mm">

 <xsclass="underline" fallback>unknown time</xsclass="underline" fallback>

</ext:date>

В этом случае шаблон

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

 <!-- ... -->

 <p>This page was generated at <ext:date pattern="HH:yy">

  <xsclass="underline" fallback>unknown time</xsclass="underline" fallback>

 </ext:date>.</p>

</xsclass="underline" template>

в случае невозможности выполнить ext:date выведет

<p>This page was generated at unknown time.</p>

Заметим, что xsclass="underline" fallback применим не только для обработки исключительных ситуаций, связанных с элементами расширения. Наборы доступных процессору элементов XSLT будут также меняться от версии к версии, и xsclass="underline" fallback вполне пригодится для обеспечения обратной совместимости. Например, если в версии XSLT 2.0 будет определен элемент xsclass="underline" for-each-group, то xsclass="underline" fallback можно использовать при создании альтернативного варианта для процессоров, которые еще не поддерживают новую версию:

<xsclass="underline" for-each-group select="item" group-by="@number">

 <!-- ... -->

 <xsclass="underline" fallback>

  <xsclass="underline" for-each select="item[generate-id(.)=

   generate-id(key('item', @number))]">

   <!-- ... -->

  </xsclass="underline" for-each>

 </xsclass="underline" fallback>

</xsclass="underline" for-each>

Инициатива EXSLT

Функции и элементы расширения с лихвой восполняют ограниченность языков XSLT и XPath, предоставляя возможности обычных императивных языков там, где они необходимы. Между тем, как показывает практика, задачи, которые приходится решать при помощи расширений, как правило, совершенно стандартны — например, разобранная выше функция nodeset, так или иначе реализована почти во всех XSLT-процессорах.