Bug #2323
closedDifferent XSLT compilation error obtained when I set SAXResult to transformer
100%
Description
An XSLT stylesheet has an error in it at some point.
The created Saxon transformer is called to transform over a custom SAXResult implementation.
When the transformation runs, it reports a different error than the one which exists in the XSLT styleshet:
java.lang.RuntimeException: Internal error evaluating template at line 5 in module file:/C:/Users/radu_coravu/Desktop/test.xsl
at net.sf.saxon.expr.instruct.Template.applyLeavingTail(Template.java:375)
at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:1146)
at net.sf.saxon.Controller.transformDocument(Controller.java:2176)
at net.sf.saxon.Controller.transform(Controller.java:1777)
at net.sf.saxon.s9api.XsltTransformer.transform(XsltTransformer.java:547)
at net.sf.saxon.jaxp.TransformerImpl.transform(TransformerImpl.java:186)
at ro.sync.dxsl.debugger.AbstractXSLTDebugger.run(AbstractXSLTDebugger.java:540)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalStateException: Attempt to end document in serializer when elements are unclosed
at net.sf.saxon.serialize.XMLEmitter.endDocument(XMLEmitter.java:257)
at net.sf.saxon.event.ProxyReceiver.endDocument(ProxyReceiver.java:120)
at net.sf.saxon.event.ReceivingContentHandler.endDocument(ReceivingContentHandler.java:236)
at ro.sync.dxsl.debugger.backmapping.ContentFilter.endDocument(ContentFilter.java:96)
at ro.sync.dxsl.debugger.backmapping.BackMappingSAXResult$BackMappingContentHandler.endDocument(BackMappingSAXResult.java:343)
at net.sf.saxon.event.ContentHandlerProxy.close(ContentHandlerProxy.java:316)
at net.sf.saxon.event.ProxyReceiver.close(ProxyReceiver.java:104)
at net.sf.saxon.event.ComplexContentOutputter.close(ComplexContentOutputter.java:543)
at net.sf.saxon.expr.instruct.ResultDocument.processInstruction(ResultDocument.java:610)
at net.sf.saxon.Configuration.processResultDocument(Configuration.java:2024)
at net.sf.saxon.expr.instruct.ResultDocument.process(ResultDocument.java:519)
at net.sf.saxon.expr.instruct.ResultDocument.processLeavingTail(ResultDocument.java:505)
at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:44)
at net.sf.saxon.expr.instruct.TraceExpression.processLeavingTail(TraceExpression.java:287)
at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:44)
at net.sf.saxon.expr.instruct.TraceExpression.processLeavingTail(TraceExpression.java:287)
at net.sf.saxon.expr.instruct.Template.applyLeavingTail(Template.java:354)
... 7 more
The method "ResultDocument.processInstruction" has a finally clause which closes the receiver if an error occurs when transforming:
try {
out.startDocument(0);
content.process(context);
out.endDocument();
} catch (XPathException err) {
err.setXPathContext(context);
err.maybeSetLocation(this);
throw err;
} finally {
//RECEIVER CLOSE IS CALLED
out.close();
}
and in this case the ContentHandlerProxy.close() method delegates to the "handler.endDocument()" method which throws an exception because not all elements in the SAX handler have been closed. The elements have not been closed because of the original exception which is now masked by this IllegalStateException which jumps from the finally clause.
Files
Updated by Michael Kay over 9 years ago
- Status changed from New to In Progress
First point to note is that there has been considerable debate about whether the SAX endDocument() even should be called after a parse error has been signalled. See for example http://cafeconleche.org/SAXTest/paper.html#S4.1.1. The code here is calling endDocument() after a failure, and at first sight I think that is correct.
The implication is that XmlEmitter is wrong to regard a call on endDocument when there are unclosed elements as erroneous, and either it shouldn't report an error here, or the error should be intercepted somewhere.
Updated by Radu Coravu over 9 years ago
I agree, for example the XMLEmitter would throw a certain extension class of the XPathException instead of IllegalStateException.
And it would be caught specifically on the "ResultDocument.processInstruction" when the receiver is closed and silently ignored.
Updated by Michael Kay over 9 years ago
I'm wondering what kind of error is triggering this. It seems to me it must be a run-time error rather than a compilation error as stated in the title. Also, I think it must be an error that's detected in the output pipeline. The classic would be writing an attribute when there is no open start tag. I'll see if I can simulate the problem with that. But also, I can't see the relevance of the SAXResult. On the contrary, the failure is an an XMLEmitter, which suggests the output (at least, the output from xsl:result-document) is going to a StreamResult.
I think we would have a better chance of fixing this (without adverse side-effects) if you could provide a repro (ideally in the form of a JUnit test).
Updated by Radu Coravu over 9 years ago
Added simple test files.
Updated by Radu Coravu over 9 years ago
Please see a main method to reproduce this below. We have lots of code in our debugger, I tried to cut as much as possible so it may not make a lot of sense:
public static void main(String[] args) throws Exception {
net.sf.saxon.jaxp.TransformerImpl tr = (TransformerImpl) new TransformerFactoryImpl().newTransformer(new StreamSource(new File("C:\\Users\\radu_coravu\\Desktop\\test.xsl")));
net.sf.saxon.Controller underlyingController = tr.getUnderlyingController();
PipelineConfiguration pipelineConfiguration = underlyingController.makePipelineConfiguration();
final Receiver receiver = new net.sf.saxon.lib.SerializerFactory(tr.getConfiguration()).getReceiver(
new StreamResult(new StringWriter()),
pipelineConfiguration,
tr.getOutputProperties());
ReceivingContentHandler receivingContentHandler = new ReceivingContentHandler() ;
receiver.setPipelineConfiguration(pipelineConfiguration);
receivingContentHandler.setPipelineConfiguration(pipelineConfiguration);
receivingContentHandler.setReceiver(receiver);
tr.transform(new StreamSource(new File("C:\\Users\\radu_coravu\\Desktop\\test.xml")), new SAXResult(receivingContentHandler));
}
Updated by Michael Kay over 9 years ago
- Category set to Internals
- Status changed from In Progress to Resolved
- Assignee set to Michael Kay
- Priority changed from Low to Normal
I suspect that the call on close() in the finally block (when a failure occurs during xsl:result-document processing) is designed to ensure that the underlying file is closed, since leaving files open causes all sorts of problems. The tricky thing here is that the Receiver pipeline distinguishes endDocument() from close(), but the SAX pipeline doesn't. So a close() in the Receiver pipe is being translated to a SAX endDocument(), which then gets translated to a Receiver endDocument(), which the XmlEmitter isn't expecting. Would it do any harm for the XmlEmitter to ignore the endDocument() event? Hard to tell. It's not as if we see the exception every day, so if we remove the test, it's unlikely to have major impact, but there could be cases where it causes trouble. Certainly, if we remove it, this test does what's expected. So I think I'm going to patch XmlEmitter.endDocument() to remove the test, and hope for the best.
A patch is being committed on the 9.6 and 9.7 branches.
Updated by O'Neil Delpratt over 9 years ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Found in version set to 9.6
- Fixed in version set to 9.6.0.5
Bug fix applied in the Saxon 9.6.0.5 maintenance release.
Updated by O'Neil Delpratt almost 9 years ago
- Sprint/Milestone set to 9.6.0.5
- Applies to branch 9.6 added
- Fix Committed on Branch 9.6 added
- Fixed in Maintenance Release 9.6.0.5 added
Please register to edit this issue