javasaxon

Saxon-HE Integrated Extension Functions | how and where?


Although writing Saxon Integrated Extension Functions are pretty clear to me.

I have red:

I'm having extremely hard time finding information how to actually get them to work.

Q: Where to put files, do I have to complie anything, do I have to edit saxon configuration? Basically what do I have to do to get this working besides registering an extension function with the s9api Processor.


Solution

  • TestMain.java - some java file with access to transformation factory

    import javax.xml.transform.*;
    import javax.xml.transform.stream.StreamResult;
    import javax.xml.transform.stream.StreamSource;
    import java.io.File;
    import java.io.IOException;
    import java.net.URISyntaxException;
    import net.sf.saxon.TransformerFactoryImpl;
    import net.sf.saxon.s9api.ExtensionFunction;
    import net.sf.saxon.s9api.Processor;
    import net.sf.saxon.jaxp.SaxonTransformerFactory;
    import location.to.test.java.file.Test;
    
    public class TestMain {
        public static void main(String[] args) throws IOException, URISyntaxException, TransformerException {
    
            TransformerFactory factory = TransformerFactory.newInstance();
    
            // Grab the handle of Transformer factory and cast it to TransformerFactoryImpl
            TransformerFactoryImpl tFactoryImpl = (TransformerFactoryImpl) factory;
    
            // Get the currently used processor
            net.sf.saxon.Configuration saxonConfig = tFactoryImpl.getConfiguration();
            Processor processor = (Processor) saxonConfig.getProcessor();
    
            // Here extension happens, test comes from class Test -> Test.java
            ExtensionFunction test = new Test();
            processor.registerExtensionFunction(test);
    
            Source xslt = new StreamSource(new File("test.xsl"));
            Transformer transformer = factory.newTransformer(xslt);
    
            Source text = new StreamSource(new File("input.xml"));
            transformer.transform(text, new StreamResult(new File("result.xml")));
        }
    }
    

    Test.java - the actual extension function logic

    import net.sf.saxon.s9api.ExtensionFunction;
    import net.sf.saxon.s9api.ItemType;
    import net.sf.saxon.s9api.OccurrenceIndicator;
    import net.sf.saxon.s9api.QName;
    import net.sf.saxon.s9api.SaxonApiException;
    import net.sf.saxon.s9api.SequenceType;
    import net.sf.saxon.s9api.XdmAtomicValue;
    import net.sf.saxon.s9api.XdmValue;
    
    public class Test implements ExtensionFunction {
    
        @Override
        public QName getName() {
            return new QName("http://some.namespace.com", "test");
        }
    
        @Override
        public SequenceType getResultType() {
            return SequenceType.makeSequenceType(ItemType.STRING, OccurrenceIndicator.ONE);
        }
    
        @Override
        public net.sf.saxon.s9api.SequenceType[] getArgumentTypes() {
            return new SequenceType[] {};
        }
    
        @Override
        public XdmValue call(XdmValue[] arguments) throws SaxonApiException {
            String result = "Saxon is being extended correctly.";
            return new XdmAtomicValue(result);
        }
    
    }
    

    test.xsl - test xsl. file

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:ext="http://some.namespace.com">
        <xsl:output indent="yes"/>
    
        <xsl:template match="/">
            <root>
                    <xsl:value-of select="ext:test()" />
            </root>
         </xsl:template>
    </xsl:stylesheet>
    

    result.xml - the result of entire process

    <?xml version="1.0" encoding="UTF-8"?>
    <root>Saxon is being extended correctly.</root>
    

    Please notice that namespace used in .java and .xsl file must be the same, declared in QName