All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.daisy.common.xpath.saxon.XsltFunction Maven / Gradle / Ivy

The newest version!
package org.daisy.common.xpath.saxon;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;

import javax.xml.transform.sax.SAXSource;

import net.sf.saxon.Configuration;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmValue;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.s9api.Xslt30Transformer;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.SequenceType;

import org.xml.sax.InputSource;

public class XsltFunction extends ExtensionFunctionDefinition {

	private final StructuredQName functionName;
	private final URL xslt;

	public XsltFunction(URL xslt, StructuredQName functionName) {
		this.functionName = functionName;
		this.xslt = xslt;
	}

	@Override
	public StructuredQName getFunctionQName() {
		return functionName;
	}

	// allow any number of argument and of any type
	@Override
	public int getMinimumNumberOfArguments() {
		return 0;
	}

	@Override
	public int getMaximumNumberOfArguments() {
		return 20;
	}

	@Override
	public SequenceType[] getArgumentTypes() {
		return new SequenceType[] { SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE,
		                            SequenceType.ANY_SEQUENCE };
	}

	// allow any type of result
	@Override
	public SequenceType getResultType(SequenceType[] arg) {
		return SequenceType.ANY_SEQUENCE;
	}

	@Override
	public ExtensionFunctionCall makeCallExpression() {
		return new ExtensionFunctionCall() {
			public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
				Xslt30Transformer xslt; {
					try {
						xslt = compileXslt(XsltFunction.this.xslt, context.getConfiguration());
					} catch (SaxonApiException|IOException|URISyntaxException e) {
						throw new XPathException("Failed to compile XSLT: " + XsltFunction.this.xslt, e);
					}
				}
				XdmValue[] xdmArguments = new XdmValue[arguments.length];
				for (int i = 0; i < arguments.length; i++) {
					xdmArguments[i] = XdmValue.wrap(arguments[i]);
				}
				try {
					return xslt.callFunction(new QName(functionName), xdmArguments).getUnderlyingValue();
				} catch (SaxonApiException e) {
					throw new XPathException("Failed to call XSLT function: " + functionName, e);
				}
			}
		};
	}

	private static Xslt30Transformer compileXslt(URL xslt, Configuration config) throws SaxonApiException, IOException, URISyntaxException {
		Processor processor = new Processor(config);
		XsltCompiler compiler = processor.newXsltCompiler();
		compiler.setSchemaAware(processor.isSchemaAware());
		DocumentBuilder builder = processor.newDocumentBuilder();
		builder.setBaseURI(xslt.toURI());
		XsltExecutable executable = compiler.compile(
			builder.build(new SAXSource(new InputSource(xslt.openStream()))).asSource());
		return executable.load30();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy