繁体   English   中英

XMLStreamWriter:缩进

[英]XMLStreamWriter: indentation

是否真的没有办法直接使用javax.xml.stream.XMLStreamWriter(Java SE 6)编写格式化的XML? 这真是令人难以置信,因为其他XML API(如JAXB和一些DOM库)能够做到这一点。 即使.NET XMLStreamWriter等效也能够使用此AFAIK(如果我没记错的话,该类是System.Xml.XmlTextWriter)。

这意味着我唯一的选择是重新分析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对象图只是为了漂亮的打印?

几个月前已经回答了这个确切的问题其中一个答案是使用IndentingXMLStreamWriter类:

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

就代码而言,它是一个简洁的解决方案,但要小心:这是一个com.sun。*类,不能保证其一般可用性......

您可以在writeXml方法中添加必要的代码来格式化文档。 只需保持深度计数器(以指示嵌套水平)。 然后在writeStartElement之前和writeEndElement之后使用深度索引来插入缩进。

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

使用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>

只是为了记录,Saxon允许您通过s9api接口获取序列化XMLStreamWriter:

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

并且Serializer公开了所有XSLT定义的输出属性(包括“缩进”)以及一些特定于Saxon的输出属性。

考虑到"{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));
}

你是正确的,标准的java.xml接口几乎不提供对序列化的控制,即使底层实现(Apache Xerces)也是如此。 我必须解决这个问题,我提出的最好的方法是包含一个Xerces副本并使用org.apache.xml.serialize类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM