Project

Profile

Help

XPDY0002: Finding root of tree: the context item is undefined

Added by Rob Oaks about 11 years ago

I emailed Michael about this issue but I thought it would be better to post it to the forum. I would so appreciate your help.

I have some Java code that uses the s9API to call a function in an XQuery module that I’m using XQueryCompiler.compileLibrary on. I know the XQuery code is absolutely correct because I developed/debugged it in XMLSpy and it works fine. When I call XQueryEvaluator.iterator() from Java I get

XPDY0002: Finding root of tree: the context item is undefined

The Java code appears below, and I have attached the relevant XQuery and other files. Note the following:

Currently the module that I’m calling XQueryCompiler.compileLibrary on has its own import module statement, as it uses functions in another small library I wrote. I assume that Saxon supports this scenario without doing a separate XQueryCompiler.compileLibrary on the child library. In case that was the problem, however, I combined everything into the one library module; the same error was reported.

I did have to make one change from the XMLSpy version of the XQuery code, which is I had to use saxon:evaluate() to postpone evaluation of an XPath until the source document was set. I tested that separately and it worked fine.

Here is the simplified Java code (removed try/catch blocks, class/method declarations, etc. and other inconsequentials):

First this code:

this.xqProcessor.setConfigurationProperty(FeatureKeys.LICENSE_FILE_LOCATION,getXQueryFilePath("saxon-license.lic"));
this.xqProcessor.setConfigurationProperty(FeatureKeys.SCHEMA_VALIDATION, Validation.LAX);
this.xqProcessor.setConfigurationProperty(FeatureKeys.XQUERY_SCHEMA_AWARE, true);

this.xqCompiler = this.xqProcessor.newXQueryCompiler();
this.xqCompiler.compileLibrary(new File(getXQueryFilePath("ACORD--ZAG.xq")));
this.xqCommlDriverEval = this.xqCompiler.compile(
            "import module namespace acord-zag = 'http://www.itsdataservices.com/idcp/xq/acord/zag';\n"
            + "acord-zag:getDelimitedCommlDriver()").load();

Later I call:

this.xqCommlDriverEval.setSource(new StreamSource(new File(getXQueryFilePath("ACORD 127+129+137CA+163.xml"))));
this.xqCommlDriverEval.iterator();
...

Here is the full stack trace:

Error on line 1 of IDCP--Function.xq:
  XPDY0002: Finding root of tree: the context item is undefined
  at acord-zag:getDelimitedCommlDriver() (*module with no systemId*#2)
Exception in component tJavaMapsInput_1
net.sf.saxon.s9api.SaxonApiUncheckedException: Finding root of tree: the context item is undefined
	at net.sf.saxon.s9api.XQueryEvaluator.iterator(XQueryEvaluator.java:432)
	at routines.Test_tJavaMapsInput_Helper_WithACORD.getIterableOfMap(Test_tJavaMapsInput_Helper_WithACORD.java:91)
	at umv_data_conversion_try.test_tjavamapsinput_withacord_0_1.Test_tJavaMapsInput_WithACORD.tJavaMapsInput_1Process(Test_tJavaMapsInput_WithACORD.java:861)
	at umv_data_conversion_try.test_tjavamapsinput_withacord_0_1.Test_tJavaMapsInput_WithACORD.runJobInTOS(Test_tJavaMapsInput_WithACORD.java:1725)
	at umv_data_conversion_try.test_tjavamapsinput_withacord_0_1.Test_tJavaMapsInput_WithACORD.main(Test_tJavaMapsInput_WithACORD.java:1551)
Caused by: net.sf.saxon.trans.XPathException: Finding root of tree: the context item is undefined
[statistics] disconnected
	at net.sf.saxon.expr.Expression.dynamicError(Expression.java:1036)
	at net.sf.saxon.expr.RootExpression.getNode(RootExpression.java:77)
	at net.sf.saxon.expr.SingleNodeExpression.iterate(SingleNodeExpression.java:134)
	at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:700)
	at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:101)
	at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:700)
	at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:101)
	at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:700)
	at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:101)
	at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:700)
	at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:101)
	at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:700)
	at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:101)
	at com.saxonica.functions.extfn.Evaluate$EvaluateCall.call(Evaluate.java:271)
	at net.sf.saxon.functions.IntegratedFunctionCall.call(IntegratedFunctionCall.java:298)
	at CE_acord_zag_getDelimitedCommlDriver_357632074.iterate(file:/C:/Users/Rob/Documents/2--Work/ITS/Clients/UMV/Projects/Policy%20Conversion/Construction/ETL/Inputs/Configuration/XQuery/ACORD--ZAG.xq:52)
	at com.saxonica.bytecode.CompiledExpression.iterate(CompiledExpression.java:169)
	at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:332)
	at net.sf.saxon.expr.instruct.UserFunction.call(UserFunction.java:344)
	at CE_main_305946482.iterate(*module with no systemId*)
	at com.saxonica.bytecode.CompiledExpression.iterate(CompiledExpression.java:169)
	at net.sf.saxon.query.XQueryExpression.iterator(XQueryExpression.java:341)
	at net.sf.saxon.s9api.XQueryEvaluator.iterator(XQueryEvaluator.java:430)
	... 4 more

Thanks so much!


Replies (8)

Please register to reply

RE: XPDY0002: Finding root of tree: the context item is undefined - Added by Michael Kay about 11 years ago

There are some unresolved issues with separately-compiled query libraries, which distracted my attention from the problem as reported, but I think that's a red herring in this case. The query library contains a number of functions with this general form:

declare function acord-zag:tester() as element() { let $rootXPath as xs:string := "/ACORD/InsuranceSvcRq/CommlAutoPolicyQuoteInqRq/CommlAutoLineBusiness/CommlDriver[1]" return saxon:evaluate($rootXPath) };

There's no difference here between using saxon:evaluate and using the XPath expression directly; saxon:evaluate uses its own context as the context for evaluating the dynamic XPath expression. Inside a function, the dynamic context has no context item. When there is no context item, evaluation of a path starting with "/" will fail with this error. You need to pass the document being processed as an argument to the function, or reference it as a global variable. (It's global variables that account for the known problems with separate library compilation, so that might be best avoided).

RE: XPDY0002: Finding root of tree: the context item is undefined - Added by Rob Oaks about 11 years ago

Thank you Michael. This makes sense, but I have one question.

Given the fact that the source document is dynamically determined in my Java code and given to Saxon using @XQueryEvaluator.setSource@, what would you say is the most elegant/performant way to deal with this? I have to use @saxon:evaluate@ because otherwise the code I previously used:

let $rootNode as element(CommlDriver)* := /ACORD/InsuranceSvcRq/CommlAutoPolicyQuoteInqRq/CommlAutoLineBusiness/CommlDriver
return  idcp-func:nodesToDelimited($rootNode,  ())

will fail during Saxon compilation since the source document doesn’t exist at that point.

Thus, since it appears that I have to use saxon:evaluate to postpone evaluation of the XPath, are you saying that I should just pass the entire document (about 100K) as a String to @acord-zag:getDelimitedCommlDriver@ which then, in turn, passes it as the second parameter to @saxon:evaluate@? Doesn’t this obviate the @XQueryEvaluator.setSource@ call entirely, since once the XPath (/ACORD/InsuranceSvcRq/CommlAutoPolicyQuoteInqRq/CommlAutoLineBusiness/CommlDriver) has been evaluated, the function that is invoked (@nodesToDelimited@) has no need to refer to the source document? Sorry to be so painfully explicit, but I still consider myself an XQuery newbie.

Thanks again.

RE: XPDY0002: Finding root of tree: the context item is undefined - Added by Michael Kay about 11 years ago

You're mistaken about the need to use saxon:evaluate. The expression (let l$rootNode as element(CommlDriver)* := /ACORD/....) fails for exactly the same reason that your call on saxon:evaluate fails - there is no context item for the path expression. It just fails a bit earlier, because the compiler can see what's wrong. The fix is the same - you have to supply a parameter to the function to tell it what document to search within.

When you use setSource() from the API, that determines the context node passed to the query. Typically the body of your query will then call a function passing "." as a parameter, for example f:acord-tester(.), and the function in question will declare a parameter to accept this node, and use it as the root of the path expression, something like

declare function acord-zag:tester($root as document-node()) as element() { $root/ACORD/InsuranceSvcRq/CommlAutoPolicyQuoteInqRq/CommlAutoLineBusiness/CommlDriver1 };

I'm afraid I'm not answering your questions very well, because it's clear you have some mind-picture of what's going on that needs to be corrected, and I'm having trouble understanding where the conceptual blocks are.

RE: XPDY0002: Finding root of tree: the context item is undefined - Added by Rob Oaks about 11 years ago

I reread your prior response more carefully and now understand how conceptually muddy my last response was: the whole problem is that within a function there is no context item to evaluate paths against, whether that's recognized early or late. So is it therefore not possible to directly pass a context node to a function in a library (where there is no query body)? This means there's no way to directly invoke a function that operates on a context?

RE: XPDY0002: Finding root of tree: the context item is undefined - Added by Michael Kay about 11 years ago

That's correct: in the body of a function, you have no access to the context item outside the function (either the initial context item passed when invoking the query, or the local context item at the point of the function call). You have to pass this information explicitly as a function argument.

RE: XPDY0002: Finding root of tree: the context item is undefined - Added by Rob Oaks about 11 years ago

Is it possible (and desirable) with Saxon to construct a context (XPath evaluated node) in my Java code and then pass that context directly to the desired function in my compiled library? The other approach is to change my library to a regular module and then have the query use the equivalent of a Java switch statement to invoke the appropriate function based on the value of an external variable. I suspect the latter approach is the only way to accomplish my goal.

Sorry for continuing to parse this topic :-)

RE: XPDY0002: Finding root of tree: the context item is undefined - Added by Michael Kay about 11 years ago

Both approaches are possible. I think that while direct calling of an XQuery function from Java might seem more elegant, it's territory that's less well charted, and I think my advice would be to stick to the more orthodox approach of executing the query via its main module, even if this requires use of a switch to decide which function to execute.

RE: XPDY0002: Finding root of tree: the context item is undefined - Added by Rob Oaks about 11 years ago

Perfect. That was the direction I was leaning. Thanks again for your help.

    (1-8/8)

    Please register to reply