我正在使用javax.xml.transform.*
进行XSLT转换。由于要使用的xslt文件来自外部世界,因此该文件可能存在错误,我将向用户回复一些有意义的响应。
虽然我可以很容易地抓住TransformationException
,但我发现无法从中获取足够的信息。例如,如果标记被结束标记终止,printStackTrace()
会给出疤痕消息
javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(Unknown Source)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTransformer(Unknown Source)
... (100 lines)
和getMessage()
仅提供
Could not compile stylesheet
它们都没有给出错误的真正原因。
我注意到在Eclipse测试控制台中我可以看到以下内容
[Fatal Error] :259:155: The element type "sometag" must be terminated by the matching end-tag "</sometag>".
ERROR: 'The element type "sometag" must be terminated by the matching end-tag "</sometag>".'
FATAL ERROR: 'Could not compile stylesheet'
这正是我想要的。不幸的是,由于这是一个Web应用程序,用户无法看到这一点。
如何向用户显示正确的错误消息?
答案 0 :(得分:1)
使用ErrorListener
将您自己的Transformer.setErrorListener
放在Transformer
个实例上,如下所示:
final List<TransformationException> errors = new ArrayList<TransformationException>();
Transformer transformer = ... ;
transformer.setErrorListener(new ErrorListener() {
@Override
public void error(TransformerException exception) {
errors.add(exception);
}
@Override
public void fatalError(TransformerException exception) {
errors.add(exception);
}
@Override
public void warning(TransformerException exception) {
// handle warnings as well if you want them
}
});
// Any other transformer setup
Source xmlSource = ... ;
Result outputTarget = ... ;
try {
transformer.transform(xmlSource, outputTarget);
} catch (TransformerException e) {
errors.add(e); // Just in case one is thrown that isn't handled
}
if (!errors.isEmpty()) {
// Handle errors
} else {
// Handle output since there were no errors
}
这将记录errors
列表中发生的所有错误,然后您可以使用这些错误消息来获取您想要的内容。这具有额外的好处,它将在错误发生后尝试恢复转换。如果这导致任何问题,只需通过执行以下操作重新抛出异常:
@Override
public void error(TransformerException exception) throws TransformationException {
errors.add(exception);
throw exception;
}
@Override
public void fatalError(TransformerException exception) throws TransformationException {
errors.add(exception);
throw exception;
}
答案 1 :(得分:0)
首先,任何解决方案都可能取决于您选择的XSLT处理器。 JAXP接口的不同实现可能会在它们生成的异常中提供不同的信息。
XML解析器中的错误可能在包装的异常中可用。由于历史原因,TransformerConfigurationException提供getException()和getCause()来访问包装的异常,并且可能值得检查它们。
或者,可能是在对ErrorListener的单独调用中提供了信息。
最后,XML解析器(而不是XSLT处理器)检测到这个特定错误,因此在第一个实例中它将由解析器处理。可能值得设置解析器的ErrorHandler并捕获该级别的解析错误。如果要显式控制转换使用的XML解析器,请使用其XMLReader已正确初始化的SAXSource。
答案 2 :(得分:-1)
您可以将System.out配置为在您自己的OutputStream中写入。 使用ErrorListener不会捕获所有输出。 如果您使用线程,可以查看此处(http://maiaco.com/articles/java/threadOut.php)以避免更改其他线程的System.out。
例如
public final class XslUtilities {
private XslUtilities() {
// only static methods
}
public static class ConvertWithXslException extends Exception {
public ConvertWithXslException(String message, Throwable cause) {
super(message, cause);
}
}
public static String convertWithXsl(String input, String xsl) throws ConvertWithXslException {
ByteArrayOutputStream systemOutByteArrayOutputStream = new ByteArrayOutputStream();
PrintStream oldSystemOutPrintStream = System.out;
System.setOut(new PrintStream(systemOutByteArrayOutputStream));
ByteArrayOutputStream systemErrByteArrayOutputStream = new ByteArrayOutputStream();
PrintStream oldSystemErrPrintStream = System.err;
System.setErr(new PrintStream(systemErrByteArrayOutputStream));
String resultXml;
try {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(new StreamSource(new StringReader(xsl)));
StringWriter stringWriter = new StringWriter();
transformer.transform(new StreamSource(new StringReader(input)), new StreamResult(stringWriter));
resultXml = stringWriter.toString();
} catch (TransformerException e) {
System.out.flush();
final String systemOut = systemOutByteArrayOutputStream.toString();
System.err.flush();
final String systemErr = systemErrByteArrayOutputStream.toString();
throw new ConvertWithXslException("TransformerException - " + e.getMessageAndLocation()
+ (systemOut.length() > 0 ? ("\nSystem.out:" + systemOut) : "")
+ (systemErr.length() > 0 ? ("\nSystem.err:" + systemErr) : ""), e);
} finally {
System.setOut(oldSystemOutPrintStream);
System.setErr(oldSystemErrPrintStream);
}
return resultXml;
}
}