Project

Profile

Help

SaxonCS command line tool: how to hook up extension functions?

Added by Martin Honnen over 2 years ago

For the Java command line there are ways to add extension functions programmatically, using https://www.saxonica.com/html/documentation11/javadoc/net/sf/saxon/Transform.html#applyLocalOptions-net.sf.saxon.trans.CommandLineOptions-net.sf.saxon.Configuration-.

Is there any way to do that with the SaxonCS command line tool?


Replies (4)

Please register to reply

RE: SaxonCS command line tool: how to hook up extension functions? - Added by Martin Honnen over 2 years ago

I have now also tried to use a configuration file with SaxonCS 11.4 to see whether that allows me to register an extension function.

What is the right form of value for an <extensionFunction></extensionFunction> element?

I have tried

<configuration xmlns="http://saxon.sf.net/ns/configuration">
	<resources>
		<extensionFunction>SaxonCSSampleExtensions.Sqrt</extensionFunction>
	</resources>
</configuration>

where I have

using Saxon.Api;

Processor processor;

using (var fs = File.OpenRead("saxon-config-ext-sample.xml"))
{
    processor = new(fs, new Uri(Environment.CurrentDirectory));
}

var compiler = processor.NewXPathCompiler();
compiler.DeclareNamespace("ex", "http://example.com/math");

Console.WriteLine(compiler.EvaluateSingle("ex:sqrt(4)", null));

and below extension (taken nearly literally from the samples and shown at the end), but all I get is

Saxon.Api.SaxonApiException
  HResult=0x80131500
  Message=Cannot find a 1-argument function named Q{http://example.com/math}sqrt()
  Source=SaxonCS-b6
  StackTrace:
   at Saxon.Hej.s9api.XPathCompiler.internalCompile(String source)
   at Saxon.Hej.s9api.XPathCompiler.compile(String source)
   at Saxon.Hej.s9api.XPathCompiler.evaluateSingle(String expression, XdmItem contextItem)
   at Program.<Main>$(String[] args) in C:\Users\marti\source\repos\SaxonCSSampleExtensions\TestSaxonCSSampleExtension2\Program.cs:line 13
using Saxon.Api;

namespace SaxonCSSampleExtensions
{
    /// <summary>
    /// Example extension function to compute a square root, using the full API
    /// </summary>

    public class Sqrt : ExtensionFunctionDefinition
    {
        public override QName FunctionName => new QName("http://example.com/math", "sqrt");

        public override int MinimumNumberOfArguments => 1;

        public override int MaximumNumberOfArguments => 1;

        public override XdmSequenceType[] ArgumentTypes =>
        new[]{
                new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_DOUBLE), '?')
            };

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new(XdmAtomicType.BuiltInAtomicType(QName.XS_DOUBLE), '?');
        }

        public override bool TrustResultType => true;


        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new SqrtCall();
        }
    }

    internal class SqrtCall : ExtensionFunctionCall
    {
        public override XdmValue Call(XdmValue[] arguments, DynamicContext context)
        {
            if (arguments[0].Empty)
            {
                return XdmEmptySequence.Instance;
            }
            XdmAtomicValue arg = (XdmAtomicValue)arguments[0].ItemAt(0);
            double val = (double)arg.Value;
            double sqrt = System.Math.Sqrt(val);
            return new XdmAtomicValue(sqrt);
        }
    }
}

RE: SaxonCS command line tool: how to hook up extension functions? - Added by Michael Kay over 2 years ago

SaxonCS does no dynamic loading, which means that all entries in the configuration file that refer to classes by name are inoperative.

This applies equally to command line options that refer to classes by name.

We may find a way around this one day, but dynamic loading in .NET seems to be very troublesome so we've steered clear of it so far.

RE: SaxonCS command line tool: how to hook up extension functions? - Added by Martin Honnen over 2 years ago

Is there any way configured/allowed to add extension functions to the command line tools?

I have tried something like subclassing Saxon.Hej.Transform e.g. along the lines of

   public class IXsltSaxonCS : Saxon.Hej.Transform
    {
        protected override void initializeConfiguration(Configuration config)
        {

        }
        internal override void applyLocalOptions(CommandLineOptions options, Configuration config)
        {

        }

        internal override void setPermittedOptions(CommandLineOptions options)
        {

        }
    }

but it seems all such attempts fail due to various "wrong" access declarations, the CommandLineOptions class is not public, like it is in the Java code, the InitializeConfiguration method is not set up to be overridable.

Is that just not wanted for the SaxonCS command line tools to be able to add extension functions? Or how could one do it?

RE: SaxonCS command line tool: how to hook up extension functions? - Added by Martin Honnen over 2 years ago

As far as I have read through the Saxon 11 Java API and have also tested it easily allows me to do e.g.

import net.sf.saxon.Configuration;
import net.sf.saxon.Transform;
import org.nineml.coffeesacks.RegisterCoffeeSacks;

import javax.xml.transform.TransformerException;

public class SaxonIXslt extends Transform {

    public void initializeConfiguration(Configuration config) {
        config.getProcessor().registerExtensionFunction(new MyExtensionFunctionDefinition1());
        config.getProcessor().registerExtensionfFunction(new MyExtensionFunctionDefinition2());
    }

    public static void main(String[] args) {
        new SaxonIXslt().doTransform(args);
    }
}

and I have a Saxon command line wrapper/extension to run XSLT with my extension functions present.

Isn't something similar possible with the SaxonCS command line tool/API?

    (1-4/4)

    Please register to reply