On 3/12/23 23:24, Bederov, Sergey wrote:
Eric, thank you for your interest in this subject.
The issue tracker appears to be inactive since 2011, and it’s not
possible to register an account there.
Your XSLT files didn’t work for me with an error “An attempt was made
to insert a node where it is not permitted”, apparently because they
are attempting to create multiple elements “first”, “emitted”,
“Output” and “last” at the root level. I added a new wrapping element
to the “Root” template and it started working a bit better.
While the multiple top-level elements of output is not OK for an XML
document, I don't think anything stops you from emitted such with XSL,
and my test with org.apache.xalan.xslt.Process did work. Did it not work
for you because of what you were doing with the output or the Transform
simply refuse to run with these xslt files?
For the “TestNotOK.xsl” file, all three XSLT engines (JDK-Xalan, Xalan
2.7.2, Saxon) give the same result:
<OutputRoot xmlns:exslt="http://exslt.org/common"
xmlns:str="http://exslt.org/strings">
<first>foo</first>
<emitted>foo</emitted>
<Output>
<Display></Display>
<Usage></Usage>
<Display></Display>
</Output>
<emitted>foo</emitted>
<last>foo</last>
</OutputRoot>
The parameter isn’t being passed to the “Created” template.
For the “TestOK.xsl” file, Xalan 2.7.2 gives the same result,
This is peculiar because my version of testOK run with xalan 2.7.2 (or
2.7.3 RC) did not give the same result, it contained
<Display>foo</Display> like your JDK-Xalan and Saxon runs. (And adding
an OutputRoot wrapper did not change that for me. I suppose it's
possible that the way org.apache.xalan.xslt.Process instantiates the
Transformer it's getting a JDK Transformer, but that seems unlikely.)
but JDK-Xalan and Saxon work better:
<OutputRoot xmlns:exslt="http://exslt.org/common"
xmlns:str="http://exslt.org/strings">
<first>foo</first>
<emitted>foo</emitted>
<Output>
<Display>foo</Display>
<Usage></Usage>
<Display>foo</Display>
</Output>
<emitted>foo</emitted>
<last>foo</last>
</OutputRoot>
Here the parameter is being passed successfully. What’s the
difference? “TestNotOK” and “TestOK” differ in having the “/” template.
Probably there is something to do with calling “apply-templates” on a
result-tree-fragment. I have read somewhere that in such cases the
result-tree-fragment is being treated as a separate document with its
own “document element”, and the templates should be called on that
document element first, but, since I don’t have a dedicated template
for that element, a “default template” is being called, and at this
moment the parameter is being forgotten. Probably the “/” template
changes this behavior in some way. But I can’t understand why because
your “/” template also ignores the parameter, and anyway it appears
identical to the “default template” so I can’t see why it can make any
difference.
I can't either. One can see how the "/" could be relevant to getting the
param passed down through a hidden root element (if somehow it passed
it), but I'm almost sure I saw the problem come and go with other
changes less easy to rationalize, and your original case of it not
working with the key usage but working without the key usage seem to be
a case of that. So I still think there is an unexplained "stirring the
pot" effect going on, even if you have found a way to stir the pot to
where it works for your purposes. I would worry that some future code
change would stir your pot again and cause things to break again.
These kinds of irrational seeming "stirring the pot" bugs can occur,
say, when code changes cause data to be overwritten. I've seen this in C
code, but it is harder to imagine in Java, except that in this case the
data of your "created" variable is in the same Document structure as the
xslt templates, and while I can't explain how that would work, it does
point in the direction of something that might make sense, perhaps with
inadvertent changes to the nodes in that variable. (I am also doing
these tests on Unix, and your line breaks indicate Windows, and while I
think I cleaned that up before my most recent tests, one could imagine
something hidden going on with an editor silently introducing or
eliminating what xalan counts as additional nodes.)
(I do have a version of your XSL that works without any "/" template, BTW.)
I have modified your “/” template by adding a “prm” parameter to it
and passing this parameter to “apply-templates”. Please find attached
“TestDocTemplatePrm.xsl”. Now it works! The parameter is being passed
in all three engines including Xalan 2.7.2:
<OutputRoot xmlns:exslt="http://exslt.org/common"
xmlns:str="http://exslt.org/strings">
<first>foo</first>
<emitted>foo</emitted>
<Output>
<Display>foo</Display>
<Usage></Usage>
<Display>foo</Display>
</Output>
<emitted>foo</emitted>
<last>foo</last>
</OutputRoot>
So indeed the result-tree-fragment is being processed starting with an
imaginary “document element”, and if I supply a suitable template
which passes the parameter through, it is being passed to the next
“Created” template I actually need.
Then I uncommented the “key” stuff and finally got working what I
initially needed. I had to make another modification. Apparently at
some stage of these nested templates the context is lost and the “key”
function can’t find the required key. To restore the context, I have
added a DOCUMENT_ROOT variable and wrapped the “key” invocation inside
a “for-each”. Also I modified the key and the source XML file so that
it could find something meaningful. And it finally worked! Please find
attached “TestEverythingWorks.xml” and “TestEverythingWorks.xsl”.
Xalan 2.7.2 and Saxon give the correct result:
<OutputRoot xmlns:exslt="http://exslt.org/common"
xmlns:str="http://exslt.org/strings">
<first>foo</first>
<emitted>foo</emitted>
<Output>
<Display>foo</Display>
<Usage>bar</Usage>
<Display>foo</Display>
</Output>
<emitted>foo</emitted>
<last>foo</last>
</OutputRoot>
The element is being found in the key and from it the value “bar” is
being read. Hooray!
I still don’t know why so many twists are required to pass the
parameter. Is it correct anyway? Probably it’s all towards the
stringent implementation of the XSLT standard. In the JDK-Xalan the
parameter was being passed even in the absence of the “/” template,
probably that was a bug which has been fixed since then. On the other
hand, the JDK-Xalan was losing the parameter which was an obvious bug;
now I see that it has been fixed in Xalan 2.7.2. Thank you!
*Sergey Bederov
*Senior Developer
*Cortona3D**
*www.cortona3D.com <http://www.cortona3d.com/>
*From:*Eric J. Schwarzenbach [mailto:[email protected]]
*Sent:* Saturday, March 11, 2023 11:28 PM
*To:* Bederov, Sergey <[email protected]>
*Cc:* [email protected]
*Subject:* Re: Xalan bug: key( ) clears variable
The issue tracker is here:
https://issues.apache.org/jira/projects/XALANJ/issues/XALANJ-2357?filter=allopenissues
However, I'm seeing even more weirdness with this xsl. It seems I can
make it work by making changes that have no reason to make a
difference. I'd made a number of changes to my copy of your xsl, to
try to make it work, and to test that certain things were working
property and were not the cause of the problem. I started to clean
that up in case it might be useful for the bug submission. But some
change I made caused the variable to be passed and make
<Display>foo</Display> appear in the output. Trying to backtrack I
saw the problem come and go unexpectedly.
I isolated one change that causes the problem to go away. My attached
testOK.xsl works properly. testNotOK.xsl exhibits the problem. The
only difference is testNotOK.xsl having a "/" template (which was not
even in your version and should not be having any effect). I've also
gotten other changes that should be unrelated to cause the problem to
come and go. It is as if various changes "stir the pot" and activate
or deactivate the problem. I realize this makes no sense and makes me
sound like a crazy person, but I urge you to try my two attached
versions of the stylesheet.
I suspect that issue you had with the key usage using the JDK version
was this same "stir the pot" issue and nothing particularly to do with
keys, and it probably behaves the same way in both xalan and the JDK
version of it.