NPE when running Saxon-HE 11 extension

Here should go questions about transforming XML with XSLT and FOP.
jbriner
Posts: 4
Joined: Fri Apr 30, 2021 8:29 pm

NPE when running Saxon-HE 11 extension

Post by jbriner »

When I run directly with Java, I get the expected transformation. When I run with Oxygen XML Developer 25.1, build 2023070306, I get an NPE (XSLT Internal Error) without much of any clue of where it dies. Here is my extension class:

Code: Select all

package com.pearson.xprt.extension;
import net.sf.saxon.Configuration;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.Logger;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.StringValue;

public class LatexMathML extends  ExtensionFunctionDefinition {

    Logger logger;

    LatexMathML(Configuration conf) {
        super();
        logger = conf.getLogger();
        logger.info("LatexMathML constructor complete");
    }
    
    @Override
    public StructuredQName getFunctionQName() {
        logger.info("LatexMathML: StructuredQName");
        return new StructuredQName("xprtx", "http://extension.xprt.pearson.com", "latex-to-mathml");
    }

    @Override
    public SequenceType[] getArgumentTypes() {
          logger.info("LatexMathML: getArgumentTypes");
        return new SequenceType[]{SequenceType.SINGLE_STRING};
    }

    @Override
    public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
        logger.info("LatexMathML: getResultType");
        return SequenceType.SINGLE_STRING;
    }

    @Override
    public ExtensionFunctionCall makeCallExpression() {
        logger.info("LatexMathML: set the function");

        return new ExtensionFunctionCall() {
            public Sequence call(XPathContext context, Sequence[] arguments)
                    throws XPathException {
                String v0 = ((StringValue)arguments[0]).getStringValue();
                logger.info("LatexMathML: call the function: " + v0);
                String result = v0.toUpperCase();
                return StringValue.makeStringValue(result);
            }
        };
    }
}
Here is the initialize class:

Code: Select all

package com.pearson.xprt.extension;
        import net.sf.saxon.Configuration;
        import net.sf.saxon.s9api.Processor;

        import javax.xml.transform.TransformerException;

public class XPRTInit implements net.sf.saxon.lib.Initializer {
    public void initialize(Configuration config) throws TransformerException {
        Processor processor = (Processor)config.getProcessor();

        config.getLogger().info("XPRTInit: about to register");
        processor.registerExtensionFunction(new LatexMathML(config));
        config.getLogger().info("XPRTInit: registration complete");

    }
}
Here is the xsl:

Code: Select all

<xsl:stylesheet version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:m="http://www.w3.org/1998/Math/MathML"
    xmlns:q3ad="http://www.imsglobal.org/xsd/imsqtiasi_v3p0"
    xmlns:xprtx="http://extension.xprt.pearson.com"
    exclude-result-prefixes="#all">

    <xsl:template match="q3ad:qti-math">
        <xsl:element name="math" namespace="http://www.w3.org/1998/Math/MathML">
            <xsl:attribute name="latex">
                <xsl:sequence select="xprtx:latex-to-mathml(string(@data-latex))"/>
            </xsl:attribute>
        </xsl:element>

    </xsl:template>
</xsl:stylesheet>
And here is the input xml:

Code: Select all

	<qti-math xmlns="http://www.imsglobal.org/xsd/imsqtiasi_v3p0"
		data-latex="\infty\xrightarrow{}\overline{15}"><span/>
	</qti-math>
Here is how I run it from the command line:
$ java -cp 'xmlresolver-5.2.1.jar;xprt-extension-1.0.jar;Saxon-HE-11.6.jar' net.sf.saxon.Transform -init:com.pearson.xprt.extension.XPRTInit extension.xml extension.xsl
I get the transformation that I expect from the command line:
<?xml version="1.0" encoding="UTF-8"?><math xmlns="http://www.w3.org/1998/Math/MathML" latex="\INFTY\XRIGHTARROW{}\OVERLINE{15}"/>
Is there anything obviously wrong with my extension and using the com.pearson.xprt.extension.XPRTInit class to initialize and register the extension?
Where do I find the Oxygen logs?
Any suggestions of how to debug?
Thanks in advance for your help!
Mircea
Posts: 143
Joined: Tue Mar 25, 2003 11:21 am

Re: NPE when running Saxon-HE 11 extension

Post by Mircea »

Hello,

In order to use extensions from the transformation scenarios in Oxygen make sure you follow the steps explained here.
Also please add a zero arguments public constructor to your class (LatexMathML) in order to instantiate the extension when needed.
After doing this I was able to run the transformation, but the exception is becouse of the missing logger:
16:17:11 19475 ERROR [ Transformation Performer ] ro.sync.xml.transformer.TransformerCreator - Got a NPE trying to validate a stylesheet!! java.lang.NullPointerException: Cannot invoke "net.sf.saxon.lib.Logger.info(String)" because "this.logger" is null
at com.pearson.xprt.extension.LatexMathML.getFunctionQName(LatexMathML.java:29)
at net.sf.saxon.functions.IntegratedFunctionLibrary.registerFunction(IntegratedFunctionLibrary.java:40)
at net.sf.saxon.Configuration.registerExtensionFunction(Configuration.java:1580)
at ro.sync.xml.transformer.SaxonTransformerUtil$1.run(SaxonTransformerUtil.java:233)
Regards,
Mircea.
Mircea Enachescu
<oXygen> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com
jbriner
Posts: 4
Joined: Fri Apr 30, 2021 8:29 pm

Re: NPE when running Saxon-HE 11 extension

Post by jbriner »

So, when running from Oxygen, the class will be instantiated via a service and does not need the Initialize class. This was my largest misunderstanding. I had been following some suggestions from Saxon. This led me to misread which service needed to be registered. I thought it was the initializer. In reality, it is the net.sf.saxon.lib.ExtensionFunctionDefinition class that needs to be defined and not the Initializer.

After removing logger from my classes and removing the use of the Initializer in Oxygen, everything worked as expected.

Thanks again!
Last edited by jbriner on Wed May 15, 2024 8:36 pm, edited 1 time in total.
Post Reply