Что такое расширения?

Что такое расширения?

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

Вместе с тем в XSLT-преобразованиях может оказаться очень полезной функциональность традиционных языков программирования. Например, математических функций и операторов, имеющихся в XPath, явно недостаточно для выполнения сложных вычислений, которые могут потребоваться в преобразованиях. XSLT не имеет встроенных функций для обращения к базам данных, оставляют желать лучшего средства для работы с множествами, текстовыми данными, датами и временными параметрами, словом задачи, не представляющие никакой сложности в традиционных языках программирования, могут быть чрезвычайно трудоемкими в XSLT. Скажем, тригонометрические функции можно реализовать в XSLT рекурсивными вычислениями последовательностей Тейлора, но насколько проще было бы использовать функции sin и cos.

Таким образом, перед разработчиками языка стояла следующая дилемма: либо дублировать функциональность традиционных языков программирования в XSLT или XPath, либо изыскивать другие средства достижения тех же результатов.

Решение этой проблемы было довольно простым: вместо того, чтобы заново реализовывать все множество функций, которые только могут понадобиться при обработке документов, спецификация XSLT позволяет процессорам предоставлять интерфейсы для расширения XSLT и XPath за счет использования других языков программирования, например, Java, JavaScript или Python.

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

Рассмотрим примеры.

В языке XPath нет функции, которая генерировала бы псевдослучайное значение. Следующее преобразование приводит пример решения этой задачи с помощью стандартного класса Math языка Java.

Листинг 10.1. Преобразование, использующее класс java.lang.Math

<xsl:stylesheet version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transfоrm"

 xmlns:math="java:java.lang.Math"

 exclude-result-prefixes="math">

 <xsl:template match="/">

  <random><xsl:value-of select="math:random()"/></random>

 </xsl:template>

</xsl:stylesheet>

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

<random>0.0538608432986305</random>

Значение 0.0538608432986305 было получено посредством вызова метода random класса java.lang.Math и представляет собой некоторое псевдослучайное значение.

В качестве примера элемента расширения можно привести элемент saxon:entity-ref, определенный в XSLT-процессоре Saxon. Этот элемент создает в выходящем документе сущность с указанным именем.

Листинг 10.2. Использование элемента расширения saxon:entity-ref

<xsl:stylesheet

 version="1.0"

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

 xmlns:saxon="http://icl.com/saxon"

 extension-element-prefixes="saxon">

 <xsl:template match="/">

  <xsl:text>Everybody</xsl:text>

  <saxon:entity-ref name="nbsp"/>

  <xsl:text>needs</xsl:text>

  <saxon:entity-ref name="nbsp"/>

  <xsl:text>space</xsl:text>

</xsl:template>

</xsl:stylesheet>

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

Everybody&nbsp;needs&nbsp;space

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

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

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

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

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

Итак, вопрос, использовать расширения или нет — это вопрос "функциональность против переносимости", и, хотя его решение будет всегда зависеть от конкретной задачи, существуют также и довольно общие критерии оценки, которые мы приведем в следующей таблице (табл. 10.1).

Таблица 10.1. Использование расширений: критерии за и против

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

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

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

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