2011-01-06 35 views
27

真的沒有辦法直接寫使用javax.xml.stream.XMLStreamWriter(Java SE 6中)格式的XML ???這實在令人難以置信,因爲其他XML API(如JAXB和某些DOM庫)能夠做到這一點。即使是.NET XMLStreamWriter等價物也可以用這個AFAIK(如果我沒記錯,這個類是System.Xml.XmlTextWriter)。XMLStreamWriter:縮進

這意味着我有唯一的選擇是重新分析XML以產生格式化的輸出??

例如爲:

  StringWriter sw = new StringWriter(); 
    XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory(); 
    XMLStreamWriter xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(sw); 
    writeXml(xmlStreamWriter); 
    xmlStreamWriter.flush(); 
    xmlStreamWriter.close(); 

    TransformerFactory factory = TransformerFactory.newInstance(); 

    Transformer transformer = factory.newTransformer(); 
    transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); 

    StringWriter formattedStringWriter = new StringWriter(); 
    transformer.transform(new StreamSource(new StringReader(sw.toString())), new StreamResult(formattedStringWriter)); 
    System.out.println(formattedStringWriter); 

這種解決方案的問題是財產 「{http://xml.apache.org/xslt}indent-amount」。我沒有找到任何有關它的文檔,它似乎不能保證便攜。

所以我有什麼其他選擇,如果我想用標準的Java 6類做到這一點?創建一個JAXB或DOM對象圖只是爲了漂亮打印?

回答

6

你可以添加必要的代碼在你中WriteXML方法來格式化您的文檔。只需維護一個深度計數器(以指示嵌套的級別)。然後,在writeStartElement之前和writeEndElement之後,使用深度索引插入縮進。

for(int x=0; x<depth; x++) { 
    xmlStreamWriter.writeCharacters(" "); 
} 
+0

我找不到這樣的writeText方法?!? http://download.oracle.com/javase/6/docs/api/javax/xml/stream/XMLStreamWriter。html – Puce 2011-01-06 16:38:10

+0

嗯,也許與writeCharacters,但我認爲這只是爲了元素內容... – Puce 2011-01-06 16:39:36

+0

你是對的,它應該是writeCharacters。此方法可用於在文檔中的任何位置插入文本,而不只是在單個元素中插入文本。 – 2011-01-06 16:42:45

1

你是正確的,該標準java.xml接口,系列化上沒有控制提供很少的,即使底層實現(Apache的Xerces的)一樣。我已經解決了這個問題,我想出了最好的是包括的Xerces的副本,並使用org.apache.xml.serialize類。

+1

是的,我已經閱讀過有關這樣的解決方案,但自從Xerces 2.9.0以來,這個軟件包已被廢棄:http://xerces.apache.org/xerces2-j/javadocs/other/org/apache/xml/serialize/package -summary.html – Puce 2011-01-07 10:37:26

34

這確切question已經在幾個月前回答one of the answers是使用IndentingXMLStreamWriter類:

XMLOutputFactory xmlof = XMLOutputFactory.newInstance(); 
XMLStreamWriter writer = new IndentingXMLStreamWriter(xmlof.createXMLStreamWriter(out)); 

它是儘可能的代碼放在一個整潔的解決方案,但請注意:這是一個的com.sun *一流的,沒有它的一般可用性保證...

+1

正如你所說,不幸的是,這不是一個已發佈的API。 – Puce 2014-03-24 09:27:55

+1

IndentingXMLStreamWriter類及其基類DelegatingXMLStreamWriter可以用反編譯器打開(IntelliJ IDEA現在有一個內置的),並作爲我們自己項目的一部分保存在源代碼中。所以,他們的「不公開」並不是真正的問題。如果你這樣做,一定要修復sun的代碼中的一個bug:在'onEmptyElement()'方法中,對'writeCharacters(「\ n」);'的調用應該是'super.writeCharacters(「\ n」);相反。 – 2015-03-05 20:01:08

2

隨着Spring Batch的,這需要,因爲這JIRA BATCH-1867

public class IndentingStaxEventItemWriter<T> extends StaxEventItemWriter<T> { 

    @Setter 
    @Getter 
    private boolean indenting = true; 

    @Override 
    protected XMLEventWriter createXmlEventWriter(XMLOutputFactory outputFactory, Writer writer) throws XMLStreamException { 
    if (isIndenting()) { 
     return new IndentingXMLEventWriter(super.createXmlEventWriter(outputFactory, writer)); 
    } 
    else { 
     return super.createXmlEventWriter(outputFactory, writer); 
    } 
    } 

} 
一個子類

但是這需要其它附加的依賴,因爲Spring Batch的不包括代碼縮進StAX的輸出:

<dependency> 
    <groupId>net.java.dev.stax-utils</groupId> 
    <artifactId>stax-utils</artifactId> 
    <version>20070216</version> 
</dependency> 
+1

有趣的部分是stax-utils庫,它提供了IndentingXMLEventWriter,並且似乎獨立於Spring Batch。感謝提示! – Puce 2013-09-18 21:53:43

2

只是爲了記錄在案,撒克遜允許您通過s9api接口獲得序列化XMLStreamWriter:

Processor p = new Processor(); 
Serializer s = p.newSerializer(); 
s.setOutputProperty(Property.INDENT, "yes"); 
XMLStreamWriter w = s.getXMLStreamWriter(); 

和序列化器公開了所有XSLT定義的輸出屬性(包括「縮進」)以及一些特定於撒克遜的屬性。

+0

稍微更完整的版本在這裏: http://stackoverflow.com/questions/10105187/java-indentingxmlstreamwriter-alternative/30637501#30637501 – 2015-06-04 07:56:36

2

我沒有回答考慮"{http://xml.apache.org/xslt}indent-amount"財產。但是你可以使用變壓器,而不需要重新分析所有輸出。你可以使用類似下面的代碼來創建漂亮的打印XMLStreamWriter

public static void main(String[] args) { 
    XMLStreamWriter xmlStreamWriter = createXMLStreamWriter(new OutputStreamWriter(System.out)); 
    writeXml(xmlStreamWriter); 
} 

private static XMLStreamWriter createXMLStreamWriter(Writer textWriter) throws XMLStreamException { 
    SAXTransformerFactory xmlTransformerFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); 
    TransformerHandler transformingSAXHandler; 
    try { 
     transformingSAXHandler = xmlTransformerFactory.newTransformerHandler(); 
    } catch (TransformerConfigurationException e) { 
     throw new XMLStreamException(e); 
    } 
    Transformer xmlTransformer = transformingSAXHandler.getTransformer(); 
    xmlTransformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
    transformingSAXHandler.setResult(new StreamResult(textWriter)); 

    XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance(); 
    return xmlOutputFactory.createXMLStreamWriter(new SAXResult(transformingSAXHandler)); 
} 
+0

最後一行導致:'java.lang.UnsupportedOperationException:javax.xml類型的結果.transform.sax.SAXResult @ 184f6be2不受支持。支持的結果類型是:DOMResult,StAXResult和StreamResult'。我們使用Java版本1.8u74,你呢? – sjngm 2017-02-22 09:25:57

+0

我認爲它應該在底層實現是Apache Xerces時工作,但不能保證與其他實現一起工作...... – 2017-02-22 12:07:44