2014-01-18 25 views
6

我實現了code讓我打印格式的XML如何更改默認的日誌記錄在Java中變壓器

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

+1好問題 - 發佈一個完整的[MCVE](http://stackoverflow.com/help/mcve)讓我感興趣,足以想知道爲什麼它不起作用。 –

回答

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

} 
+0

工作就像一個魅力。感謝您爲解決這個問題所做的額外工作。我很欣賞解決方案。 – jhadley

+0

對我不起作用:-(終止來自XSLT的消息仍然轉到STDERR。任何想法? – SharonBL

+0

這對我也不適用,net.sf.saxon.lib.StandardErrorListener仍然用於輸出...並打印到std err – Amalgovinus

-3

直從文檔:

要提供自定義錯誤處理,實現ErrorListener接口並使用setErrorListener方法註冊一個帶有Transformer的實現的一個實例。 Transformer然後通過此界面報告所有錯誤和警告。

如果應用程序未註冊自己的自定義ErrorListener,則會使用默認的ErrorListener,它向System.err報告所有警告和錯誤,並且不會拋出任何異常。強烈建議應用程序註冊並使用ErrorListener,以確保警告和錯誤的正確行爲。

對於轉換錯誤,Transformer必須使用此接口而不是拋出異常:由應用程序決定是否針對不同類型的錯誤和警告拋出異常。但請注意,調用fatalError(TransformerException異常)後,Transformer不需要繼續轉換。

現在在你的情況下,因爲你的TransformThis類正在實現ErrorListener。您應該能夠通過以下方式轉換錯誤:

transformer.setErrorListener(this); 
+1

這是**完全** OP在顯示的代碼示例中顯示的內容。他們甚至去發佈一個完整的例子,你可以運行的麻煩,看看它不會阻止他們顯示的錯誤信息輸出到'stderr'。 JDK中存在一個錯誤。 –

+0

我明白你在說什麼。我瀏覽了文檔,並且覺得它必須工作,因爲它在API中。很高興知道它存在的問題。很好的信息謝謝 – Ashish

6

您在JDK中發現了一個錯誤(實際上是兩個)。恭喜! (或者,我想是哀悼)。

第一個錯誤是它是一個「致命」錯誤,但它會調用ErrorListener.error()而不是ErrorListener.fatalError()。如果您在示例中將println語句放在error()中,您會看到它被調用。

第二個錯誤是忽略了上面的第一個,你在做什麼應該工作。

但它沒有。

在調試器中拋出您的示例並深入研究JDK,我發現錯誤偵聽器不會傳播到底層的XMLScannerXMLErrorReporter

正在發生的事情是,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上測試的)。

+0

我很感謝吊as以及對SDK的深入瞭解!如果你繼續調查,我很想聽聽你的發現。 – jhadley

+0

@jhadley沒問題;當我運行你的例子,我無法抗拒:)當我有機會,我會進一步調試,我會更新/平你。 –

+0

Jon Iles提交了一個解決我的問題的答案。因此,我正在改變對他答案的接受答案,以便那些在未來發現這個問題的人知道解決問題的方法。 – jhadley

相關問題