String functions missing in Xalan 2.7, java.lang.String used instead?
Asked Answered
B

4

5

I am using Xalan 2.7.0 (as bundled with Apache FOP 1.0) and have problems when using string functions.

The line <xsl:value-of select="fn:replace('test', 't', '*')"/> results in this exception:

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')"/> results in:

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)

Now this is weird! Why does Xalan look for a stringLength function on java.lang.String? I tested <xsl:value-of select="fn:substring('foobar', 2, 3)"/>, and indeed: the result is o, so the arguments were used as startIndex, endIndex (like java.lang.String.substring()) instead of XPath's fn:substring(string, start, length) funcion.

So I think that Xalan is somehow missing its XPath function library and using the regular String class instead. I confirmed this by calling the non-existing function fn:index-of('foobar', 'bar') which works fine and maps to java.lang.String.indexOf(str).

Why does Xalan do that? And how can I fix it?

System info: Xalan uses the standard Mac OS X 10.6.4 Java version, 1.6.0_20.

Update

Okay, leave aside the replace() function for a moment. Shouldn't Xalan, being an XSLT 1.0 processor, implement the XPath 1.0 function substring (string, startIndex, length) and not the (string, startIndex, endIndex) function I see in my expirements? Is it coincidence that this startIndex, endIndex function looks like the substring method of java.lang.String?

And why do I get a NoSuchMethodError when I use the fn:string-length function?

Something's wrong here, and it clearly isn`t about XPath 1.0 vs 2.0...

Binnings answered 5/9, 2010 at 8:44 Comment(7)
Good question (+1). See my answer for the explanation.Exert
What namespace are you using for the prefix fn:? When you use <xsl:value-of select="string-length('foobar')"/> (i.e. no namespace prefix on string-length()), does it still give a NoSuchMethodException?Politicize
LarsH: The namespace is w3.org/2005/02/xpath-functions, but as Alejandro writes below, I have to leave out the fn: prefix. Thanks!Binnings
@Jens-Bannmann, @LarsH, @Alejandro, @Mads-Hansen: Someonehas downvoted @Mads-Hansen's and my answers -- which are both correct ?!? Let's at least explain the reason vor downvoting. If the OP has overnight added new questions to his initial question, should we wake to find our correct answers downvoted?Exert
@Dimitre: +1 for wake up comment! Strange things happen in SO... At least we got keeping XSL tag as XSLT tag synonymous.Slaver
@Alejandro: Thanks. Did you forget the +1 or was my answer downvoted again in the meantime? :)Exert
@Dimitre: No, I forget to vote ;)Slaver
S
3

The result from substring('foobar', 2, 3) (Do note: without namespace) should be oob.

In XSLT 1.0 any function call with prefix will be interpreted as an extension call. From http://www.w3.org/TR/xslt#section-Extension-Functions

If a FunctionName in a FunctionCall expression is not an NCName (i.e. if it contains a colon), then it is treated as a call to an extension function. The FunctionName is expanded to a name using the namespace declarations from the evaluation context.

Slaver answered 5/9, 2010 at 21:32 Comment(0)
O
8

replace() is an XSLT 2.0 function. Xalan is an XSLT 1.0 processor.

You can simulate the replace() function with a template like this from @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>

Keep in mind that this XSLT 1.0 solution is a very simple find/replace. The XSLT 2.0 function replace() can use REGEX patterns for the "find" expression.

Olathe answered 5/9, 2010 at 12:57 Comment(0)
C
4

When old Xalan is the only option, this one works for me:

<xsl:value-of 
   select="java:replaceAll(java:java.lang.String.new(ContactInfo/telephone/text()),'[^0-9]','')"/>
Cluff answered 10/5, 2012 at 19:14 Comment(0)
S
3

The result from substring('foobar', 2, 3) (Do note: without namespace) should be oob.

In XSLT 1.0 any function call with prefix will be interpreted as an extension call. From http://www.w3.org/TR/xslt#section-Extension-Functions

If a FunctionName in a FunctionCall expression is not an NCName (i.e. if it contains a colon), then it is treated as a call to an extension function. The FunctionName is expanded to a name using the namespace declarations from the evaluation context.

Slaver answered 5/9, 2010 at 21:32 Comment(0)
E
1

Now this is weird! Why does Xalan look for a stringLength function on java.lang.String? I tested , and indeed: the result is o, so the arguments were used as startIndex, endIndex (like java.lang.String.substring()) instead of XPath's fn:substring(string, start, length) funcion.

So I think that Xalan is somehow missing its XPath function library and using the regular String class instead. I confirmed this by calling the non-existing function fn:index-of('foobar', 'bar') which works fine and maps to java.lang.String.indexOf(str).

Why does Xalan do that? And how can I fix it?

  1. Why does Xalan do that? Because Xalan is XSLT 1.0 processor and any compliant XSLT 1.0 processor only supports XPath 1.0. replace() is a standard function of XPath 2.0 and must be implemented in any compliant XSLT 2.0 processor.

  2. And how can I fix it? By using an XSLT 2.0 processor like Saxon 9.x or AltovaXML2010. Or write a named, recursive <xsl:template> to do simple replacements in XSLT 1.0.

Exert answered 6/9, 2010 at 16:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.