Строковые функции отсутствуют в Xalan 2.7, вместо них используется java.lang.String?

Я использую Xalan 2.7.0 (в комплекте с Apache FOP 1.0), и у меня возникают проблемы при использовании строковых функций.

Строка <xsl:value-of select="fn:replace('test', 't', '*')"/> приводит к этому исключению:

javax.xml.transform.TransformerException: java.lang.IllegalArgumentException: argument type mismatch
    at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:302)

<xsl:value-of select="fn:string-length('foobar')"/> приводит к:

javax.xml.transform.TransformerException: java.lang.NoSuchMethodException: For extension function, could not find method java.lang.String.stringLength([ExpressionContext,] ).
    at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:302)

Теперь это странно! Почему Xalan ищет функцию stringLength на java.lang.String? Я протестировал <xsl:value-of select="fn:substring('foobar', 2, 3)"/>, и действительно: результат o, поэтому аргументы использовались как startIndex, endIndex (например, java.lang.String.substring()) вместо функции fn:substring(string, start, length) XPath.

Поэтому я думаю, что Xalan почему-то не хватает своей библиотеки функций XPath и вместо этого использует обычный класс String. Я подтвердил это, вызвав несуществующую функцию fn:index-of('foobar', 'bar'), которая отлично работает и сопоставляется с java.lang.String.indexOf(str).

Почему Ксалан делает это? И как я могу это исправить?

Информация о системе: Xalan использует стандартную версию Mac OS X 10.6.4 Java, 1.6.0_20.

Обновить

Хорошо, оставим пока функцию replace(). Не должен ли Xalan, будучи процессором XSLT 1.0, реализовать подстроку функции XPath 1.0 (string, startIndex, length), а не функцию (string, startIndex, endIndex), которую я вижу в своих экспериментах? Это совпадение, что эта функция startIndex, endIndex выглядит как метод подстроки java.lang.String?

И почему я получаю NoSuchMethodError, когда использую функцию fn:string-length?

Что-то тут не так, и дело явно не в XPath 1.0 vs 2.0...


person Jens Bannmann    schedule 05.09.2010    source источник
comment
Хороший вопрос (+1). Смотрите мой ответ для объяснения.   -  person Dimitre Novatchev    schedule 05.09.2010
comment
Какое пространство имен вы используете для префикса fn:? Когда вы используете <xsl:value-of select="string-length('foobar')"/> (т. е. без префикса пространства имен в string-length()), выдает ли он исключение NoSuchMethodException?   -  person LarsH    schedule 06.09.2010
comment
LarsH: Пространство имен — w3.org/2005/02/xpath-functions. , но, как пишет Алехандро ниже, я должен опустить префикс fn:. Спасибо!   -  person Jens Bannmann    schedule 06.09.2010
comment
@Jens-Bannmann, @LarsH, @Alejandro, @Mads-Hansen: Кто-то проголосовал за @Mads-Hansen и за мой ответ — оба правильные?!? Давайте хотя бы объясним причину отрицательного голосования. Если ОП за ночь добавил новые вопросы к своему первоначальному вопросу, должны ли мы проснуться и обнаружить, что наши правильные ответы были отклонены?   -  person Dimitre Novatchev    schedule 06.09.2010
comment
@Dimitre: +1 за комментарий для пробуждения! В SO происходят странные вещи... По крайней мере, мы сохранили тег XSL как синоним тега XSLT.   -  person    schedule 06.09.2010
comment
@Алехандро: Спасибо. Вы забыли +1 или за мой ответ снова проголосовали? :)   -  person Dimitre Novatchev    schedule 06.09.2010
comment
@Dimitre: Нет, я забыл проголосовать ;)   -  person    schedule 06.09.2010


Ответы (4)


Результат substring('foobar', 2, 3) (Обратите внимание: без пространства имен) должен быть oob.

В XSLT 1.0 любой вызов функции с префиксом будет интерпретироваться как вызов расширения. Из http://www.w3.org/TR/xslt#section-Extension-Functions

Если FunctionName в выражении FunctionCall не является NCName (т. е. если оно содержит двоеточие), то оно обрабатывается как вызов функции расширения. FunctionName расширяется до имени с использованием объявлений пространства имен из контекста оценки.

person Community    schedule 05.09.2010

replace() — это функция XSLT 2.0. Xalan — это процессор XSLT 1.0.

Вы можете имитировать функцию replace() с помощью подобного шаблона от @Ektron Doug D. :

<xsl:template name="replace-substring">
<xsl:param name="original"/>
<xsl:param name="substring"/>
<xsl:param name="replacement" select="''"/>
<xsl:choose>
    <xsl:when test="contains($original, $substring)">
        <xsl:value-of select="substring-before($original, $substring)"/>
        <xsl:copy-of select="$replacement"/>
        <xsl:call-template name="replace-substring">
            <xsl:with-param name="original" select="substring-after($original, $substring)"/>
            <xsl:with-param name="substring" select="$substring"/>
            <xsl:with-param name="replacement" select="$replacement"/>
        </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="$original"/>
    </xsl:otherwise>
</xsl:choose>
</xsl:template>

Имейте в виду, что это решение XSLT 1.0 представляет собой очень простую функцию поиска/замены. Функция replace() XSLT 2.0 может использовать шаблоны REGEX для выражения «найти».

person Mads Hansen    schedule 05.09.2010

Когда старый Ксалан — единственный вариант, мне подходит этот:

<xsl:value-of 
   select="java:replaceAll(java:java.lang.String.new(ContactInfo/telephone/text()),'[^0-9]','')"/>
person Vladimir Dyuzhev    schedule 10.05.2012

Теперь это странно! Почему Xalan ищет функцию stringLength в java.lang.String? Я проверил, и действительно: результат o, поэтому аргументы использовались как startIndex, endIndex (например, java.lang.String.substring()) вместо функции XPath fn:substring(string, start, length).

Поэтому я думаю, что Xalan почему-то не хватает своей библиотеки функций XPath и вместо этого использует обычный класс String. Я подтвердил это, вызвав несуществующую функцию fn:index-of('foobar', 'bar'), которая отлично работает и сопоставляется с java.lang.String.indexOf(str).

Почему Ксалан делает это? И как я могу это исправить?

  1. Почему Ксалан это делает? Поскольку Xalan — это процессор XSLT 1.0, а любой совместимый процессор XSLT 1.0 поддерживает только XPath 1.0. replace() — это стандартная функция XPath 2.0 и должен быть реализован в любом процессоре, совместимом с XSLT 2.0.

  2. И как это исправить? С помощью процессора XSLT 2.0, такого как Saxon 9.x или AltovaXML2010. Или напишите именованный рекурсивный <xsl:template> для выполнения простых замен в XSLT 1.0.

person Dimitre Novatchev    schedule 06.09.2010