2011-01-06 3 views
27

нет способа напрямую написать отформатированный XML с помощью javax.xml.stream.XMLStreamWriter (Java SE 6) ??? Это действительно невероятно, поскольку другие 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. Просто поддерживайте счетчик глубины (чтобы указать уровни гнездования). Затем перед записьюStartElement и после того, как вы напишитеEndElement, используйте индекс глубины, чтобы вставить отступ.

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

+0

Хм, может быть, с writeCharacters, но я думал, что это просто для содержимого элемента ... – Puce

+0

Вы правы, это должны были быть записи символов. Этот метод можно использовать для вставки текста в любом месте документа не только в пределах одного элемента. –

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

34

Это точное question было отвечено несколько месяцев назад и one of the answers является использование класса IndentingXMLStreamWriter:

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

Это изящное решение, насколько код идет, но осторожно: это com.sun . * класс, нет никакой гарантии его общедоступности ...

+1

Как вы сказали, к сожалению, это не опубликованный API. – Puce

+1

Класс 'IndentingXMLStreamWriter' и его базовый класс' DelegatingXMLStreamWriter' могут быть открыты с помощью декомпилятора (IntelliJ IDEA в настоящее время имеет один встроенный) и сохранены в исходной форме как часть нашего собственного проекта. Таким образом, их «неопубликование» на самом деле не проблема. Если вы это сделаете, обязательно исправьте ошибку в коде солнца: в методе 'onEmptyElement()' вызов 'writeCharacters (" \ n ");' должен быть 'super.writeCharacters (" \ n "); вместо этого. –

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

} 

Но это требует additionnal зависимости, потому что 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

2

Только для записи, Saxon позволяет получить сериализации XMLStreamWriter через интерфейс s9api:

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

и Serializer предоставляет все свойства вывода, определенные XSLT (включая «отступ»), а также некоторые саксонские.

+0

Немного более полная версия здесь: http://stackoverflow.com/questions/10105187/java-indentingxmlstreamwriter-alternative/30637501#30637501 –

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

+0

Я думаю, что он должен работать, когда базовая реализация - Apache Xerces, но не гарантируется работа с другими реализациями ... –

Смежные вопросы