Project

Profile

Help

Bug #2771

closed

Xslt30Transformer#applyTemplates(Source source) always returns empty value if stylesheet has <xsl:result-document> element

Added by Anonymous almost 8 years ago. Updated over 7 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Internals
Sprint/Milestone:
-
Start date:
2016-06-03
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
9.7
Fix Committed on Branch:
Fixed in Maintenance Release:
Platforms:

Description

Given:

<!-- test.xsl -->
<xsl:stylesheet version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="a">
    <c>d</c>
  </xsl:template>

  <xsl:template match="whatever">
    <xsl:result-document href="out.xml">
      <e>f</e>
    </xsl:result-document>
  </xsl:template>

</xsl:stylesheet>

Then:

Xslt30Transformer transformer = compiler.compile(new StreamSource(new File("test.xsl"))).load30();
StreamSource source = new StreamSource(new StringReader("<a>b</a>"));
XdmValue xdmValue = transformer.applyTemplates(source);

Returns an empty value, even though I would expect it to return <c>d</c>@, because there's a template that matches the @<a> element.

If I remove the <xsl:result-document> element from the unmatched template, the code returns <c>d</c> as expected.

Is this a bug in Saxon or am I doing something wrong?

I attached a set of files you can test this with.


Files

saxon-result-document-issue.zip (822 Bytes) saxon-result-document-issue.zip Anonymous, 2016-06-03 12:16
Actions #1

Updated by Anonymous almost 8 years ago

Also, I discovered that if you add a template like this into the stylesheet, then it also returns the expected result:

  <xsl:template match="/">
    <xsl:result-document>
      <xsl:apply-templates/>
    </xsl:result-document>
  </xsl:template>
Actions #2

Updated by Michael Kay almost 8 years ago

Thanks for reporting.

There's some complex logic here designed to enforce the XSLT 2.0 rule: (section 2.4):

An implicit result tree is also created when the result sequence is empty, provided that no xsl:result-document instruction has been evaluated during the course of the transformation. In this situation the implicit result tree will consist of a document node with no children.

This means that the processor handles the principal output differently depending on whether or not there has been a secondary output; if there has, then an empty principal output is discarded (the destination file is not overwritten), but if not, then the principal output file is overwritten whether or not the result is empty.

Now in this case the principal output isn't empty, so this rule shouldn't matter; and in any case you're using an XSLT 3.0 API where the rules are different. But somewhere in here lies the explanation.

Actions #4

Updated by Michael Kay almost 8 years ago

We're generating an output pipeline containing an ImplicitResultChecker followed by a SequenceOutputter. The first output to the ImplicitResultChecker is a startElement() event, and the code at ImplicitResultChecker line 104 is generating a startDocument() event. This is apparently a legacy of the fact that in 2.0 the result of a transformation must always be a document node. No corresponding endDocument() event is fired when the transformation completes, with the result that the SequenceOutputter doesn't know things have finished, and doesn't complete getting the constructed output element from its treeBuilder into its result list. The result list is therefore empty when the Controller assembles the transformation result.

The code here is all very delicate, changing anything has a high risk of breaking some other path.

I think the most robust way forward is to avoid creating the ImplicitResultChecker on this path (it's only created if the stylesheet is capable of creating secondary result documents, and we know that the code works if that isn't the case).

Creating the ImplicitResultChecker only if the variable buildTree is set (that is, if the raw result sequence of the transformation is to undergo sequence normalization as defined in the serialization spec) seems to do the trick: on this path, buildTree is false because the application is asking for the result to be delivered as an XdmValue. (Change is in Controller line 2603).

After this change I'm seeing some unit test failure in the s9apitest package. I suspect these are not related to this specific patch but I will investigate before committing the change.

Actions #5

Updated by Michael Kay over 7 years ago

  • Category set to Internals
  • Status changed from New to Closed
  • Assignee set to Michael Kay
  • Priority changed from Low to Normal

It looks as if the patch alluded to was actually applied and released some while ago and has not caused any problems. I'm therefore closing this as resolved. The patch had not been made on the 9.8 branch so I have now done that.

Please register to edit this issue

Also available in: Atom PDF