我实现了code以使我能够打印格式化的XML
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class TransformThis implements ErrorListener {
public static void main(String[] args) throws java.lang.Exception {
TransformThis test = new TransformThis();
String goodXML;
String badXML;
goodXML = "<root><level1>WellFormed</level1></root>";
System.out.println(test.prettyPrint(goodXML));
badXML = "<root><level1>Not Well Formed</level1>";
System.out.println(test.prettyPrint(badXML));
}
public String prettyPrint(String xml) {
Source xmlInput = new StreamSource(new StringReader(xml));
StringWriter stringWriter = new StringWriter();
StreamResult xmlOutput = new StreamResult(stringWriter);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setAttribute("indent-number", 4);
try {
Transformer transformer = transformerFactory.newTransformer();
transformer.setErrorListener(this);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(xmlInput, xmlOutput);
} catch (Exception ex) {
System.out.println("My message: " + ex.getMessage());
}
return xmlOutput.getWriter().toString();
}
@Override
public void warning(TransformerException exception) throws TransformerException {
//throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void error(TransformerException exception) throws TransformerException {
//throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void fatalError(TransformerException exception) throws TransformerException {
//throw new UnsupportedOperationException("Not supported yet.");
}
}
当XML形成良好时,我得到以下输出 - 正是我想要的
<root>
<level1>WellFormed</level1>
</root>
如果XML出现问题,我会得到以下输出 - 很好,除了[致命错误]输出
[Fatal Error] :1:39: XML document structures must start and end within the same entity.
My message: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 39; XML document structures must start and end within the same entity.
<root>
<level1>Not Well Formed</level1>
转换函数抛出异常并向stderr / stdout发送[致命错误]。有没有办法防止出现[致命错误]日志?
答案 0 :(得分:6)
您在JDK中发现了一个错误(实际上是两个)。恭喜! (或者,我想,哀悼)。
第一个错误是它是一个“致命”错误,但它会调用ErrorListener.error()
而不是ErrorListener.fatalError()
。如果您在示例中的println
中添加了error()
语句,则会看到它正在被调用。
第二个错误是忽略上面的第一个错误,你正在做什么应该工作。
但事实并非如此。
在调试器中抛出您的示例并深入研究JDK我发现错误侦听器未向下传播到基础XMLScanner
和XMLErrorReporter
。
正在发生的事情是XMLErrorReporter
正在实例化com.sun.org.apache.xerces.internal.util.DefaultErrorHandler
并调用其fatalError()
方法,这就是将[fatal error]
消息吐出到stderr
的方法
具体而言,这发生在line 422 of com.sun.org.apache.xerces.internal.impl.XMLErrorReporter
之后它会在堆栈中重新抛出异常,TransformerImpl
将它激发给你的监听器。
应该发生的是,那些底层类应该具有您传入的更高级别侦听器的代理,或者应该创建本地无操作侦听器以使较低级别的输出静音。我怀疑它是后者,否则你会得到两次通知。
我需要更仔细地查看抽象树并调试构造链以找出为什么没有发生但简而言之,不幸的是这是JDK中的一个错误而且没有'一种控制/防止它的方法。 (这是在Java 1.7.0_25-b15上测试的)。
答案 1 :(得分:4)
继Brian Roach的回答之后......还有一种可以解决问题的替代方法。如果使用StreamSource
作为变换器的输入,那么您将无法使用系统决定为您提供的任何解析器,以及解析器选择的默认错误报告机制。但是,您可以使用SAX或DOM Source,它允许您自己配置解析器。我已更新您的示例以使用SAXSource
实例。
public class TransformThis implements ErrorListener, ErrorHandler {
public static void main(String[] args) throws java.lang.Exception {
TransformThis test = new TransformThis();
String goodXML;
String badXML;
goodXML = "<root><level1>WellFormed</level1></root>";
System.out.println(test.prettyPrint(goodXML));
badXML = "<root><level1>Not Well Formed</level1>";
System.out.println(test.prettyPrint(badXML));
}
public String prettyPrint(String xml) throws ParserConfigurationException, SAXException {
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
SAXParser parser = parserFactory.newSAXParser();
parser.getXMLReader().setErrorHandler(this);
SAXSource xmlInput = new SAXSource(parser.getXMLReader(), new InputSource(new StringReader(xml)));
StringWriter stringWriter = new StringWriter();
StreamResult xmlOutput = new StreamResult(stringWriter);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setAttribute("indent-number", 4);
try {
Transformer transformer = transformerFactory.newTransformer();
transformer.setErrorListener(this);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(xmlInput, xmlOutput);
} catch (Exception ex) {
System.out.println("My message: " + ex.getMessage());
}
return xmlOutput.getWriter().toString();
}
@Override
public void warning(TransformerException exception) throws TransformerException {
//throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void error(TransformerException exception) throws TransformerException {
//throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void fatalError(TransformerException exception) throws TransformerException {
//throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void warning(SAXParseException exception) throws SAXException {
// Do nothing
}
@Override
public void error(SAXParseException exception) throws SAXException {
// Do nothing
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
// Rethrow the exception
throw exception;
}
}
答案 2 :(得分:-3)
直接来自文档:
要提供自定义错误处理,请实现ErrorListener接口并使用setErrorListener方法向Transformer注册实现的实例。然后,Transformer通过此界面报告所有错误和警告。
如果应用程序未注册自己的自定义ErrorListener,则使用默认的ErrorListener,它向System.err报告所有警告和错误,并且不会抛出任何异常。强烈建议应用程序注册并使用ErrorListener,以确保警告和错误的正确行为。
对于转换错误,Transformer必须使用此接口而不是抛出异常:由应用程序决定是否针对不同类型的错误和警告抛出异常。但请注意,在调用fatalError(TransformerException异常)之后,Transformer不需要继续转换。
现在在您的情况下,因为您的TransformThis
类正在实现ErrorListener。您应该能够使用以下内容转换错误:
transformer.setErrorListener(this);