xsltapache-fop

XSL function calls in Apache FOP are not working


Using the following in our Apache FOP v2.2 server will fail in generating the PDF. I've downloaded the FOP 2.2 binary to debug locally and have the following proof of concept inputs. When I remove the call my:foobar(), there are no issues. FOP 2.9 also fails, although with a little bit different error message.

Why can't I call xsl:function's?

XSLT - transform.xsl

<xsl:stylesheet 
    version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:my="http://example.com/namespace"
    extension-element-prefixes="my">
    <xsl:output method="xml" indent="yes"/>

    <xsl:function name="my:numberFromMm" as="xs:string">
        Foobar
    </xsl:function> 
    
    
    <xsl:template match="/">
        <fo:root>
            <fo:layout-master-set>
                <fo:simple-page-master master-name="A4-portrait" page-height="29.7cm" page-width="21.0cm" margin="2cm">
                    <fo:region-body/>
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="A4-portrait">
                <fo:flow flow-name="xsl-region-body">
                    <fo:block>
                   Hello, <xsl:value-of select="name"/>! My converted: <xsl:value-of select="my:numberFromMm()" />
                  </fo:block>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
</xsl:stylesheet>

XML- source.xml

<?xml version="1.0" encoding="UTF-8"?>
<name>Frank</name>

Command to generate PDF:

fop.bat -xml "C:\PATH\TO\FILES\source.xml" -xsl "C:\PATH\TO\FILES\transform.xslt" -pdf ./output.pdf

Output (FOP2.2):

Oct 16, 2023 2:29:14 PM org.apache.fop.events.LoggingEventListener processEvent
INFO: Rendered page #1.
Oct 16, 2023 2:29:14 PM org.apache.fop.cli.Main startFOP
SEVERE: Exception
org.apache.fop.apps.FOPException: javax.xml.transform.TransformerException: Instance method call to method numberFromMm requires an Object instance as first argument
javax.xml.transform.TransformerException: javax.xml.transform.TransformerException: Instance method call to method numberFromMm requires an Object instance as first argument
        at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:296)
        at org.apache.fop.cli.InputHandler.renderTo(InputHandler.java:116)
        at org.apache.fop.cli.Main.startFOP(Main.java:186)
        at org.apache.fop.cli.Main.main(Main.java:217)
Caused by: javax.xml.transform.TransformerException: javax.xml.transform.TransformerException: Instance method call to method numberFromMm requires an Object instance as first argument
        at org.apache.xalan.extensions.ExtensionHandlerJavaPackage.callFunction(ExtensionHandlerJavaPackage.java:422)
        at org.apache.xalan.extensions.ExtensionHandlerJavaPackage.callFunction(ExtensionHandlerJavaPackage.java:440)
        at org.apache.xalan.extensions.ExtensionsTable.extFunction(ExtensionsTable.java:222)
        at org.apache.xalan.transformer.TransformerImpl.extFunction(TransformerImpl.java:475)
        at org.apache.xpath.functions.FuncExtFunction.execute(FuncExtFunction.java:208)
        at org.apache.xpath.Expression.executeCharsToContentHandler(Expression.java:313)
        at org.apache.xalan.templates.ElemValueOf.execute(ElemValueOf.java:274)
        at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2402)
        at org.apache.xalan.templates.ElemLiteralResult.execute(ElemLiteralResult.java:1376)
        at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2402)
        at org.apache.xalan.templates.ElemLiteralResult.execute(ElemLiteralResult.java:1376)
        at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2402)
        at org.apache.xalan.templates.ElemLiteralResult.execute(ElemLiteralResult.java:1376)
        at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2402)
        at org.apache.xalan.templates.ElemLiteralResult.execute(ElemLiteralResult.java:1376)
        at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2402)
        at org.apache.xalan.transformer.TransformerImpl.applyTemplateToNode(TransformerImpl.java:2272)
        at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1358)
        at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:711)
        at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1275)
        at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1253)
        at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:293)
        ... 3 more
Caused by: javax.xml.transform.TransformerException: Instance method call to method numberFromMm requires an Object instance as first argument
        at org.apache.xalan.extensions.ExtensionHandlerJavaPackage.callFunction(ExtensionHandlerJavaPackage.java:350)
        ... 24 more

Solution

  • You're using an XSLT 2.0 stylesheet, and the default Apache FOP configuration is invoking Xalan which is XSLT 1.0. You need to persuade it to invoke Saxon. I'm pretty sure there's a way to do that but I've forgotten the detail.