Project

Profile

Help

how to call xslt functions from a XPath query?

Added by Xavier Coble over 9 years ago

Greetings,

Our team is trying to upgrade our libraries to use a later version of Saxon-HE. We are trying to upgrade from 9.4.0.7 to 9.6.0.5. A module in our project executes XPath queries that use xslt functions. The module's purpose is to read an xslt at startup and convert the user defined functions in the stylesheet to an XPath extension function so it can be used XPath queries.

The upgrade did reveal some internal changes - ValueRepresentation is replaced by Sequence and UserFunction.getResultType() no longer takes a TypeHeiarchy.

There seems to be some functional behavior changes too. It seems the user-defined xslt functions that use the "current()" function are not behaving correctly.

I've attached the following files:

XsltHelperV94 - code using the 9.4.0.7 implementation

XsltHelperV96 - code using the 9.6.0.5 implementation

foo.xsl - sample xslt with functions to be called via XPath query

XsltHelperTest2 - sample test that calls the xslt function.

The 9.6 implementation is throwing a NullPointerException:

java.lang.NullPointerException
	at net.sf.saxon.expr.XPathContextMajor.getTargetComponent(XPathContextMajor.java:778)
	at net.sf.saxon.expr.XPathContextMinor.getTargetComponent(XPathContextMinor.java:554)
	at net.sf.saxon.expr.UserFunctionCall.callFunction(UserFunctionCall.java:507)
	at net.sf.saxon.expr.UserFunctionCall.evaluateItem(UserFunctionCall.java:463)
	at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:301)
	at net.sf.saxon.expr.LetExpression.eval(LetExpression.java:410)
	at net.sf.saxon.expr.LetExpression.iterate(LetExpression.java:366)
	at net.sf.saxon.expr.instruct.Choose.iterate(Choose.java:895)
	at net.sf.saxon.expr.instruct.ForEach.map(ForEach.java:454)
	at net.sf.saxon.expr.ContextMappingIterator.next(ContextMappingIterator.java:61)
	at net.sf.saxon.tree.iter.UntypedAtomizingIterator.next(UntypedAtomizingIterator.java:50)
	at net.sf.saxon.tree.iter.UntypedAtomizingIterator.next(UntypedAtomizingIterator.java:32)
	at net.sf.saxon.expr.ItemMappingIterator.next(ItemMappingIterator.java:90)
	at net.sf.saxon.functions.FoldingFunction.evaluateItem(FoldingFunction.java:56)
	at net.sf.saxon.expr.CastExpression.evaluateItem(CastExpression.java:396)
	at net.sf.saxon.expr.CastExpression.evaluateItem(CastExpression.java:34)
	at net.sf.saxon.functions.StringFn.evaluateItem(StringFn.java:143)
	at net.sf.saxon.functions.StringFn.evaluateItem(StringFn.java:30)
	at net.sf.saxon.functions.NormalizeSpace_1.evaluateItem(NormalizeSpace_1.java:77)
	at net.sf.saxon.expr.CastExpression.evaluateItem(CastExpression.java:396)
	at net.sf.saxon.expr.CastExpression.evaluateItem(CastExpression.java:34)
	at net.sf.saxon.expr.AtomicSequenceConverter.evaluateItem(AtomicSequenceConverter.java:275)
	at net.sf.saxon.expr.AtomicSequenceConverter.evaluateItem(AtomicSequenceConverter.java:30)
	at net.sf.saxon.expr.LetExpression.evaluateItem(LetExpression.java:431)
	at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:301)
	at net.sf.saxon.expr.instruct.UserFunction.call(UserFunction.java:382)
	at net.sf.saxon.expr.instruct.UserFunction.call(UserFunction.java:457)
	at cw.validation.streaming.impl.saxon.XsltHelperV96$1.call(XsltHelperV96.java:116)
	at net.sf.saxon.s9api.Processor$ExtensionFunctionDefinitionWrapper$1.call(Processor.java:580)
	at net.sf.saxon.functions.IntegratedFunctionCall.iterate(IntegratedFunctionCall.java:262)
	at net.sf.saxon.sxpath.XPathExpression.iterate(XPathExpression.java:175)
	at net.sf.saxon.s9api.XPathSelector.evaluate(XPathSelector.java:143)
	at cw.validation.streaming.impl.saxon.XsltHelperTest2.testFunction(XsltHelperTest2.java:40)

Thanks for any suggestions.


Replies (2)

RE: how to call xslt functions from a XPath query? - Added by Michael Kay over 9 years ago

Before I even look at your code, I can see from the stack trace that there is a problem with the new mechanism for binding and linking functions across packages. XSLT 3.0 introduces the idea of separately compiled packages, and this means that when an XSLT function is called, the processor needs to decide which version/override of the function to call as there can be versions in several packages. The resolution (performed by the getTargetComponent() method at the top of your stack trace) is based on knowing which package the caller is in, which is based on the value of "currentComponent" in the dynamic context. If you're trying to call XSLT functions from outside XSLT, then this isn't going to be initialized.

There may be a "quick fix" -- I'll take a look at it in the morning -- but I think the correct approach would be to call XSLT functions via the mechanism that is now available in the s9api Xslt30Transformer class, specifically

public XdmValue callFunction(QName function, XdmValue[] arguments) throws SaxonApiException

Michael Kay Saxonica

RE: how to call xslt functions from a XPath query? - Added by Xavier Coble over 9 years ago

Thanks for the quick reply! I was able to use the new Xslt30Transformer class like you said - which also simplified our code too.

Thanks, Xavier

    (1-2/2)

    Please register to reply