version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns='http://www.w3.org/2000/svg'
xmlns:math='java:java.lang.Math'
exclude-result-prefixes='math'>
...
Поскольку мы все равно используем в этом преобразовании расширения, мы можем написать свой собственный класс, который будет выполнять вычисление новых координат точки, исключив таким образом из преобразования все математические операции.
package de.fzi.xslt;
public class rot {
public static double X(double x, double y, double degree) {
double radian = Math.PI * degree / 180;
return x * Math.cos(radian) - y * Math.sin(radian);
}
public static double Y(double x, double y, double degree) {
double radian = Math.PI * degree / 180;
return x * Math.sin(radian) + y * Math.cos(radian);
}
}
Для того чтобы использовать методы этого класса в качестве функций расширения, немного изменим объявления в элементе xsl:stylesheet
:
<xsl:stylesheet
version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns='http://www.w3.org/2000/svg'
xmlns:rot='java:de.fzi.xslt.rot'
exclude-result-prefixes='rot'>
Создание элемента line
теперь может быть записано в виде:
<line
x1='{rot:X($x1, $y1, $alpha) + 100}'
y1='{rot:Y($x1, $y1, $alpha) + 100}'
x2='{rot:X($x2, $y2, $alpha) + 100}'
y2='{rot:Y($x2, $y2, $alpha) + 100}'/>
Как мы отмечали выше, интерфейсы использования функций расширения весьма различаются между разными процессорами даже в случае такого переносимого языка, как Java. Отличия могут быть и в форме вызовов функций, и в форме объявлений пространств имен. Например, в процессоре Saxon пространство имен для класса de.fzi.xslt.rot
может быть объявлено как:
xmlns:rot='java:de.fzi.xslt.rot'
в Xalan — как:
xmlns:rot='xalan://de.fzi.xslt.rot'
в Oracle XSLT Processor — как:
xmlns:rot='http://www.oracle.com/XSL/Transform/java/de.fzi.xslt.rot'
При этом сами вызовы во всех трех случаях будут одинаковыми:
rot:X($x, $y, $angle)
для метода X или
rot:Y($x, $y, $angle)
для метода Y.
Функция
При использовании функций расширения всегда есть вероятность того, что это расширение в силу каких-либо причин поддерживаться данным процессором не будет. Чаще всего это случается, во-первых, когда процессор просто физически не в состоянии вызвать эту функцию (например, процессор, написанный на C++, вряд ли будет содержать средства для выполнения Java-кода), во-вторых, когда расширение недоступно (например, процессор не в состоянии найти указанный Java-класс или динамическую библиотеку), и в-третьих, когда пространство имен объявлено неверно (например, с URI java:de.fzi.xslt.rot
вместо xalan://de.fzi.xslt.rot
). Результатом обращения к неподдерживаемому расширению будет, естественно, ошибка.
XSLT позволяет избежать подобного рода ошибок путем предварительной проверки наличия заданной функции расширения. Для этой цели служит стандартная функция function-available
(от англ. function is available — функция доступна)
Функция function-available
принимает на вход строку, представляющую имя функции и возвращает true
, если эта функция может быть вызвана и false
— если нет.
Строковый аргумент этой функции представляет расширенное имя функции, он должен соответствовать продукции QName
, то есть иметь вид
или
. В первом случае function-available
проверяет, реализована ли в данном процессоре стандартная функция с таким именем, например function-available('concat')
скорее всего, возвратит true
.
В случае, если аргумент function-available
имеет вид
, функция function- available
проверяет доступность указанной функции расширения. Например, для того, чтобы проверить, может ли в данном контексте быть вызвана функция rot:X
, необходимо вычислить выражение
function-available('rot:X')
В данном случае true
будет означать, что функция rot:X
может быть вызвана, false
— что функция в силу каких-то причин недоступна.
Функция function-available
может помочь в создании преобразований, которые используют расширения, но при этом в некоторой степени сохраняют переносимость между различными процессорами. Достаточно написать несколько вариантов вызова функции расширения для каждого из процессоров, на которых преобразование должно работать, а затем использовать вариант с доступной данному процессору функцией расширения.
Для того чтобы обеспечить работоспособность расширения, реализованного классом de.fzi.xslt.rot
в наиболее распространенных XSLT-процессорах, написанных на Java (как-то: Saxon, Xalan и Oracle XSLT Processor), прежде всего необходимо объявить соответствующие пространства имен:
<xsl:stylesheet
version='1.0'