Глава 10 Расширения языка XSLT
Глава 10
Расширения языка XSLT
Что такое расширения?
Предыдущие главы этой книги были посвящены, в основном, тому, что может 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 needs space
Несложно понять, насколько мощным средством являются расширения. Они фактически позволяют реализовать в преобразованиях функциональность традиционных языков программирования. Иными словами, почти все то, что можно сделать в обычных языках программирования, можно сделать и в преобразованиях.
Как это часто бывает, за дополнительные возможности приходится платить. Использование механизма расширений предъявляет определенные требования и накладывает некоторые ограничения.
? Реализация механизма расширений в текущей версии языка целиком и полностью зависит от производителей процессоров. Вследствие этого интерфейсы расширения различных XSLT-процессоров могут отличаться даже для одного языка программирования. Это в итоге ведет к несовместимости расширений и непереносимости XSLT-решений между различными процессорами.
? Возможность использования того или иного языка для написания расширений зависит от наличия интерфейса XSLT-процессора для этого языка. Не следует ожидать, что любой процессор сможет работать с расширениями, написанными на любом языке, то есть, иначе говоря, расширения привязывают преобразования к строго определенному процессору или, в лучшем случае, группе процессоров.
? В то время как сам XSLT не имеет сторонних эффектов, расширения этого принципа придерживаться не обязаны. Вследствие этого преобразования, в которых есть расширения с побочными эффектами могут из-за различных методов обработки входящего документа генерировать на разных процессорах разный результат.
Итак, вопрос, использовать расширения или нет — это вопрос "функциональность против переносимости", и, хотя его решение будет всегда зависеть от конкретной задачи, существуют также и довольно общие критерии оценки, которые мы приведем в следующей таблице (табл. 10.1).
Таблица 10.1. Использование расширений: критерии за и против
Использовать расширения стоит, если: Использовать расширения не стоит, если: преобразования будут выполняться на заранее известном процессоре или группе процессоров; целевой процессор неизвестен. Преобразования должны быть переносимы, насколько это возможно; в XSLT нет средств для выполнения требуемой задачи, либо они очень неэффективны; в XSLT имеются средства для выполнения требуемой задачи; преобразование должно обладать побочными эффектами; преобразование может обойтись без побочных эффектов; целевой процессор предоставляет интерфейс для хорошо известного разработчику языка программирования интерфейс для нужного языка программирования в целевом процессоре отсутствуетПодводя итог, образно выражаясь, скажем, что расширения — это пушка, стрелять из которой по воробьям рекомендуется только, когда не остается ничего другого, или воробьи достаточно велики.
К сожалению, не представляется возможным описать в одной главе интерфейсы расширения даже наиболее распространенных XSLT-процессоров. Вместо этого мы постараемся изложить основные принципы создания расширения, а также приведем несколько общих примеров, которые смогут послужить основой для создания частных решений.
Основным языком реализации расширений, приводимых в этой главе, будет Java. Пожалуй, Java является единственным языком, интерфейсы расширений для которого достаточно стандартизированы, чтобы можно было говорить об общих подходах. Однако, если читатель не знаком с этим языком — ничего страшного, ведь основное внимание в этой главе уделяется использованию расширений в XSLT, а не написанию их в других языках и Java-код приводится только для того, чтобы сделать примеры рабочими.