I'm trying to throw exception from java code that will include the message from xsl:message tag when using Saxon.
Using the following xslt file
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:message terminate="yes">exception message</xsl:message>
</xsl:template>
</xsl:stylesheet>
On Saxon 9.4 with the following code
public static void main(String[] args) throws TransformerException {
try {
TransformerFactory fact = new net.sf.saxon.TransformerFactoryImpl();
Transformer newTransformer = fact.newTransformer(new StreamSource(new File("throw.xslt")));
((net.sf.saxon.Controller)newTransformer).setRecoveryPolicy(Configuration.DO_NOT_RECOVER);
((net.sf.saxon.Controller)newTransformer).setMessageEmitter(new MessageWarner());
newTransformer.transform(new StreamSource(new File("input.xml")), new StreamResult(new File("output.xml")));
} catch (TransformerException e) {
System.out.println("THIS IS EXCEPTION: " + e.getMessage() + " <<<");
throw e;
}
}
it gives THIS IS EXCEPTION: exception message <<<
, which is the behavior I'm expecting.
But on Saxon 9.6 with a little adjusted code because of API changes
public static void main(String[] args) throws TransformerException {
try {
TransformerFactory fact = new net.sf.saxon.TransformerFactoryImpl();
Transformer newTransformer = fact.newTransformer(new StreamSource(new File("throw.xslt")));
((net.sf.saxon.jaxp.TransformerImpl)newTransformer).getUnderlyingController().setRecoveryPolicy(Configuration.DO_NOT_RECOVER);
((net.sf.saxon.jaxp.TransformerImpl)newTransformer).getUnderlyingController().setMessageEmitter(new MessageWarner());
newTransformer.transform(new StreamSource(new File("input.xml")), new StreamResult(new File("output.xml")));
} catch (TransformerException e) {
System.out.println("THIS IS EXCEPTION: " + e.getMessage() + " <<<");
throw e;
}
}
it gives THIS IS EXCEPTION: Processing terminated by xsl:message at line 4 in throw.xslt <<<
and the xsl:message is somewhere lost.
How can I achieve the "9.4" behavior on "9.6"?
This is due to the message listener, to which MessageEmitter is sending messages. In saxon 9.6 the default listener is implementing UnfailingErrorListener which cannot throw exception (as all the other listeners in 9.6), but in 9.4 it was possible to throw exceptions from listeners.
However, you can implement your own message emitter, that would throw an exception while encountering xml:message with terminate set to yes, like this:
final class ExceptionThrowingMessageEmitter extends XMLEmitter {
boolean abort = false;
public void startDocument(int properties) throws XPathException {
setWriter(new StringWriter());
abort = (properties & ReceiverOptions.TERMINATE) != 0;
super.startDocument(properties);
}
public void endDocument() throws XPathException {
XPathException de = new XPathException(getWriter().toString());
de.setErrorCode("XTMM9000");
if (abort) {
throw de;
} else {
//terminate set to no, do something like writing to the log file
}
}
public void close() {
// do nothing
}
}
and then, register it like this:
transformer.getUnderlyingController().setMessageEmitter(new ExceptionThrowingMessageEmitter());
This way, exception will be thrown, when there is terminating xml:message
Unfortunately, the new Processing terminated...
message is hardcoded in net.sf.saxon.expr.instruct.Message (Message.java:253 in 9.6.0-7). Here's a workaround that might give you what you need:
public static void main(String[] args) throws TransformerException {
final StringWriter messageOut = new StringWriter();
try {
TransformerFactory fact = new net.sf.saxon.TransformerFactoryImpl();
Transformer newTransformer = fact.newTransformer(new StreamSource(new File("throw.xslt")));
((net.sf.saxon.jaxp.TransformerImpl)newTransformer).getUnderlyingController().setRecoveryPolicy(Configuration.DO_NOT_RECOVER);
((net.sf.saxon.jaxp.TransformerImpl)newTransformer).getUnderlyingController().setMessageEmitter(new MessageEmitter() {
@Override
public void open() throws XPathException {
setWriter(messageOut);
super.open();
}
});
newTransformer.transform(new StreamSource(new File("input.xml")), new StreamResult(new File("output.xml")));
} catch (TransformerException e) {
System.out.println("THIS IS EXCEPTION: " + e.getMessage() + " <<<");
String message = messageOut.toString(); // this is the "exception message\n" that you want
// not sure why it has a \n on it
System.out.println("THIS IS THE MESSAGE WE WANT: " + message);
throw new TransformerException(message, e); // rethrow using the captured message, if you really want that "exception message" available to a caller in e.getMessage()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With