[英]How do I change the default logging in Java Transformer
我实现了代码 ,使我能够打印格式化的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>
transform函数抛出异常并向stderr / stdout发送[Fatal Error]。 有没有办法防止出现[致命错误]日志?
您在JDK中发现了一个错误(实际上是两个)。 恭喜! (或者,我想,哀悼)。
第一个错误是它是一个“致命”错误,但它将调用ErrorListener.error()
而不是ErrorListener.fatalError()
。 如果在示例中将println
语句放在error()
中,您将看到它被调用。
第二个错误是忽略了上面的第一个错误,你正在做的事情应该有效。
但事实并非如此。
在调试器中抛出您的示例并深入研究JDK我发现错误侦听器没有传播到底层的XMLScanner
和XMLErrorReporter
。
发生的事情是XMLErrorReporter
正在实例化一个com.sun.org.apache.xerces.internal.util.DefaultErrorHandler
并调用它的fatalError()
方法,这就是将[fatal error]
消息吐出到stderr
。
具体来说,这发生在com.sun.org.apache.xerces.internal.impl.XMLErrorReporter
第422行。
之后,它会将异常重新抛出堆栈, TransformerImpl
会将其激发给您的侦听器。
应该发生的是,那些底层类应该具有您传入的更高级别侦听器的代理,或者应该创建本地无操作侦听器以使较低级别的输出静音。 我怀疑它是后者,否则你会得到两次通知。
我需要更仔细地查看抽象树并调试构造链以找出为什么没有发生但简而言之,遗憾的是这是JDK中的一个错误,并且没有办法控制/阻止它。 (这是在Java 1.7.0_25-b15上测试的)。
继Brian Brian的回答之后......还有另一种方法可以解决问题。 如果您使用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;
}
}
直接来自文档:
要提供自定义错误处理,请实现ErrorListener接口并使用setErrorListener方法向Transformer注册实现的实例。 然后,Transformer通过此界面报告所有错误和警告。
如果应用程序未注册自己的自定义ErrorListener,则使用默认的ErrorListener向System.err报告所有警告和错误,并且不会抛出任何异常。 强烈建议应用程序注册并使用ErrorListener,以确保警告和错误的正确行为。
对于转换错误,Transformer必须使用此接口而不是抛出异常:由应用程序决定是否针对不同类型的错误和警告抛出异常。 但请注意,在调用fatalError(TransformerException异常)之后,Transformer不需要继续转换。
现在,在您的情况下,因为您的TransformThis
类正在实现ErrorListener。 您应该能够使用以下内容转换错误:
transformer.setErrorListener(this);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.