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...

7
  • Good question (+1). See my answer for the explanation. Commented Sep 5, 2010 at 14:39
  • 2
    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? Commented Sep 5, 2010 at 20:35
  • LarsH: The namespace is w3.org/2005/02/xpath-functions, but as Alejandro writes below, I have to leave out the fn: prefix. Thanks! Commented Sep 6, 2010 at 16:20
  • 1
    @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? Commented Sep 6, 2010 at 16:39
  • @Dimitre: +1 for wake up comment! Strange things happen in SO... At least we got keeping XSL tag as XSLT tag synonymous. Commented Sep 6, 2010 at 17:16

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

Comments

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]','')"/>

Comments

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.

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.