如何从TransformerException中提取有用的信息

时间:2013-09-05 06:14:56

标签: java exception xslt

我正在使用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应用程序,用户无法看到这一点。

如何向用户显示正确的错误消息?

3 个答案:

答案 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;
    }
}