Bug #5906
closedC# context item absent
100%
Description
Hi everyone,
Discovered while developing a .NET 6.0 console application in Visual Studio 2022. In Saxon 12.0 C# via NuGet, I have the following stylesheet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0">
<xsl:variable name="root-el" as="element()" select="/*"/>
<xsl:template match="/">
<out>
<xsl:copy-of select="name($root-el)"/>
</out>
</xsl:template>
</xsl:stylesheet>
When used along the model of the C# example, transformer.ApplyTemplates(input, results) produces this:
Error at char 1 in expression in xsl:variable/@select on line 4 column 6 of bill2.xsl:
XPDY0002 Finding root of tree: the context item is absent
at variable root-el on line 4 column 6 of bill2.xsl:
invoked by global variable root-el at file:///D:/XPUB_STANDARD/XSLT-Specs/XSLT/XSLT-Bill_TypeSetting/main/bill2.xsl#4
In template rule with match="/" on line 5 of bill2.xsl
Finding root of tree: the context item is absent
I've replicated the same error in the Saxon resources summarize.xsl by adding $root-el as a global variable and copying the value of its name to the result tree created by the main template. (The template, out of the box, otherwise works like a charm.)
Also seems to happen when I downgrade to version 11.5.
I do not have this error running the code into the Saxon-CS downloaded directly from Saxonica or in other . So there might be something in the NuGet or C# infrastructure that's causing this.
Updated by Joel Kalvesmaki almost 2 years ago
I solved my own problem, and discovered that transformer.GlobalContextItem should be set to the input XdmNode.
I would have expected that to have been assumed to be the default, no? At any rate, I think it needs to be documented better, particularly in the resource examples. It's used a few times, but the user is not really informed that by default there is no global context supplied in the invocation of .ApplyTemplates()
Updated by Joel Kalvesmaki almost 2 years ago
Tinkering around further I have noted that an error is thrown whenever someone attempts to set the .GlobalContextItem field after running .ApplyTemplates(). It seems that a new Xslt30Transformer has to be built each time the global context needs to be reset.
I think more than 90% of the stylesheet apps I have written presume that the putative catalyzing XML document is the context for global variables, and I suspect it is quite common elsewhere. (Aside from no context at all, I can't think of what other global context would be useful.) Further, my first point-of-entry tonight in the Saxon resource Examples.cs was the class XsltReuseTransformer, because it best resembled the situation I wanted to deal with.
My recommendation is to offer a variation of the test example XsltReuseTransformer immediately below it, to illustrate best practices for multiple input documents on a single stylesheet that depends for its global context upon the catalyzing input document. And I recommend adjusting the documentation of XsltReuseTransformer to be clear that it applies only when the global context is identical for every input document. Unless I've misunderstood the error messages.
One of my takeaways is that it may be possible leverage performance gains if the global variables can be constructed context-free. If so, that's a gem that deserves not to be hidden.
Updated by Martin Honnen almost 2 years ago
The Java API is not different e.g. in https://saxonica.plan.io/projects/saxonmirrorhe/repository/he/revisions/he_mirror_saxon_12_0/entry/src/samples/java/he/S9APIExamples.java#L580 the code uses setGlobalContextItem
and passes the source node to applyTemplates
.
If you don't need streaming then you might want to use the Transform
method (which I think uses the same input as both the initial match selection as well as the global context item).
Updated by Michael Kay almost 2 years ago
There were two triggers for the separation of "initial match selection" and "global context item" in the XSLT 3.0 spec.
One was a (possibly misguided) attempt to reconcile the spec with the Java API for DOMSource, which states "Create a new input source with a DOM node. The operation will be applied to the subtree rooted at this node. In XSLT, a "/" pattern still means the root of the tree (not the subtree), and the evaluation of global variables and parameters is done from the root node also." Conforming with this means you have to allow the initial match selection to differ from the initial context item, whereas XSLT 2.0 said they had to be the same. I believe the MSXML API also worked like this.
The second was streaming. For streaming, you don't want the global context item referring to the root of the streamed input document.
I agree that the result is immensely confusing for people accustomed to the traditional pattern of a single input document.
Updated by Michael Kay almost 2 years ago
I have made additions to the API documentation of Xslt30Transformer for both SaxonJ and SaxonCS.
Updated by Michael Kay almost 2 years ago
- Category set to Documentation
- Status changed from New to Resolved
- Assignee set to Michael Kay
- Applies to branch trunk added
- Fix Committed on Branch 12, trunk added
The API documentation has been improved.
Updated by O'Neil Delpratt almost 2 years ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in Maintenance Release 12.1 added
Bug fix applied in the Saxon 12.1 maintenance release.
Please register to edit this issue