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'
