Алексей Валиков - Технология XSLT
...
extension-element-prefixes="ext">
...
</xsl:stylesheet>
В итоге наше преобразование будет иметь следующий вид.
Листинг 10.19. Преобразование, использующее элемент расширения<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="xalan://de.fzi.xslt.ext"
extension-element-prefixes="ext">
<xsl:template match="/">
<!-- ... -->
This page was generated at <ext:time/>.
</xsl:template>
</xsl:stylesheet>
Результатом этого преобразования будет документ вида:
This page was generated at 11:56.
Функциональность предложенного выше элемента расширения может быть легко расширена. Например, мы можем создать элемент ext:date, который будет выводить текущую дату или время в формате, зависящем от значения его атрибута pattern.
Листинг 10.20. Класс ext.java реализация элемента ext:datepackage 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());
}
}
В преобразовании этот элемент мы можем использовать как:
This page was generated at <ext:date pattern="HH:mm"/> on
<ext:date pattern="dd/MM/yyyy"/>.
или:
This page was generated on <ext:date/>.
В первом случае результатом будет:
This page was generated at 12:11 on 08/10/2001.
Во втором:
This page was generated on 08.10.01 12:11.
Естественно, семантика элементов расширения не ограничивается простым копированием в выходящий документ заданных значений. Элементы расширения могут выполнять гораздо более сложные функции, ограниченные, пожалуй, лишь только воображением разработчика. При этом элементы расширения на удивление удачно вписываются в структуру самого преобразования, ведь принцип их использования не сильно отличается от принципа использования самих элементов 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<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="xalan://de.fzi.xslt.ext"
extension-element-prefixes="ext">
<xsl:template match="/">
<result>
<xsl:if test="element-available('ext:date')">
This page was generated at <ext:date pattern="HH:mm"/> on <ext:date pattern="dd/MM/yyyy"/>.
</xsl:if>
</result>
</xsl:template>
</xsl:stylesheet>
Элемент xsl:fallback
Другим способом обработки исключительных ситуаций, связанных с невозможностью выполнить тот или иной элемент преобразования, является использование элемента xsl:fallback. Синтаксическая конструкция этого элемента следующая:
<xsl:fallback>
<!-- Содержимое: шаблон -->
</xsl:fallback>
Элемент xsl:fallback включается в "критическую" инструкцию, то есть в элемент, который может быть неизвестен процессору. В случае, если критическая инструкция отрабатывается нормально, содержимое xsl:fallback попросту игнорируется. Иначе, если процессор в силу некоторых причин не может выполнить критическую инструкцию, вместо нее он будет выполнять содержимое дочернего элемента xsl:fallback.
ПримерНа тот случай, если процессор не сможет выполнить наш элемент расширения ext:date, мы можем "подстраховать" его следующим образом:
<ext:date pattern="HH:mm">
<xsl:fallback>unknown time</xsl:fallback>
</ext:date>
В этом случае шаблон
<xsl:template match="/">
<!-- ... -->
This page was generated at <ext:date pattern="HH:yy">
<xsl:fallback>unknown time</xsl:fallback>
</ext:date>.
</xsl:template>
в случае невозможности выполнить ext:date выведет
This page was generated at unknown time.
Заметим, что xsl:fallback применим не только для обработки исключительных ситуаций, связанных с элементами расширения. Наборы доступных процессору элементов XSLT будут также меняться от версии к версии, и xsl:fallback вполне пригодится для обеспечения обратной совместимости. Например, если в версии XSLT 2.0 будет определен элемент xsl:for-each-group, то xsl:fallback можно использовать при создании альтернативного варианта для процессоров, которые еще не поддерживают новую версию:
<xsl:for-each-group select="item" group-by="@number">
<!-- ... -->
<xsl:fallback>
<xsl:for-each select="item[generate-id(.)=
generate-id(key('item', @number))]">
<!-- ... -->
</xsl:for-each>
</xsl:fallback>
</xsl:for-each>
Инициатива EXSLT
Функции и элементы расширения с лихвой восполняют ограниченность языков XSLT и XPath, предоставляя возможности обычных императивных языков там, где они необходимы. Между тем, как показывает практика, задачи, которые приходится решать при помощи расширений, как правило, совершенно стандартны — например, разобранная выше функция nodeset, так или иначе реализована почти во всех XSLT-процессорах.
Инициатива EXSLT была порождена естественным желанием разработчиков иметь в своих XSLT-преобразованиях стандартные расширения и не дублировать усилия по решению общих проблем. В рамках EXSLT создаются стандартные библиотеки расширений XSLT для различных процессоров. Кроме того, EXSLT активно поддерживается многими разработчиками XSLT-процессоров с тем, чтобы обеспечить переносимость преобразований, использующих EXSLT-расширения.
Для конечного пользователя EXSLT — это множество библиотек расширений, которые можно загрузить с сайта http://www.exslt.org. Помимо этого, EXSLT-расширения уже являются встроенными для некоторых процессоров. Например, в процессоре Saxon реализовано большинство элементов и функций расширения EXSLT.
На данном этапе разработанные в рамках EXSLT библиотеки включают в себя следующие модули.
□ Common — общие функции и элементы расширения. Включает функции exslt:node-set и exslt:object-type и элемент exslt:document.
□ Math — математические функции.
□ Sets — функции для работы с множествами узлов (как-то: пересечение, разность и так далее).
□ Functions — элементы для определения пользовательских функций.
□ Dates and Times — элементы и функции для работы с временными параметрами.
□ Strings — модуль для работы со строками.
□ Regular Expressions — функции для работы с регулярными выражениями.
EXSLT покрывает большинство стандартных задач расширений — поэтому, прежде, чем браться за разработку собственных модулей расширения, следует проверить — нет ли уже реализованных аналогов. Кроме того, библиотеки EXSLT могут послужить хорошим примером программирования расширений.
Глава 11
Готовые решения
Группировка
Мы уже рассматривали задачу группировки, когда разбирали устройство и функционирование ключей — это была та самая задача, в которой из документа вида.