JAXP使用Stax API时格式化输出XML

最近项目中需要生成XBRL instance,对于XML读写和验证进行了一些学习。由于Stax API不支持格式化输出,默认全都写在一行上,网上也没有搜到现成的东西,自己写了一个格式化输出的帮助类。

 

说明:

1. 使用了WoodStox 4.2.0的Stax实现来写XML,顺便提一下,经过比较JAXP默认实现(SJSXP),WoodStox,DOM4J, XOM(NUX)。发现WoodStox速度最快,通过自己扩展的Stax2 API,功能也比较强大。

2. 实现了特殊的XML验证,一般来说使用SAXParser来读入XML文件再进行验证,但是这里使用了边写边验证的功能,如果是不合法的写入就会失败,所以只要写完XML肯定就是合法的。这也是Stax2 API提供的功能。

关于XML验证有一个相当不错的链接:http://www.edankert.com/validate.html

3. 关于XMLPrettyFormatter的用法主要在三行代码上,XbrliWriterHelper类中的 formatter.writeStartElementIndention(), formatter.writeValueIndention(), formatter.writeEndElementIndention()。注意调用这三个函数一定要writer.writerXXX()的方法前面。

以下是主要代码,最后会附上整个工程(包含XSD文件等)。

(2014-04-18 15:00 编辑) 这个实现有一个问题,会导致没有值的节点也分开显示结束标签,新的版本解决了这个问题:

http://www.cnblogs.com/lyhtbc/p/3673192.html

 

入口类WoodstoxWriter:

public class WoodstoxWriter {

    public static void main(String[] args) throws IOException, XMLStreamException {
        Timer t = new Timer();
        t.begin();
        streamWriter();
        t.end();
    }

    private static void streamWriter() throws IOException, XMLStreamException {
        File xsdFile = new File("src/main/resources/book.xsd");
        XMLValidationSchemaFactory xsdFactory = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
        XMLValidationSchema schema = xsdFactory.createSchema(xsdFile);

        XbrliWriterBean writer = new XbrliWriterBean();
        writer.init(schema);

        writer.writeStartElement("bk", "books", Const.NSURI_BOOK);
        writer.writeNamespace("bk", Const.NSURI_BOOK);
        writer.writeNamespace("au", Const.NSURI_AUTHER);

        for (int i = 0; i < Const.NODE_COUNTS_S; ++i) {
            writer.writeStartElement("bk", "book", Const.NSURI_BOOK);
            writer.writeAttribute("id", String.valueOf(i + 1));

            writer.writeStartElement("bk", "name", Const.NSURI_BOOK);
            String name = new StringBuilder("Name").append(i + i).toString();
            writer.writeValue(name);
            writer.writeEndElement();

            writer.writeStartElement("au", "author", Const.NSURI_AUTHER);

            writer.writeStartElement("au", "age", Const.NSURI_AUTHER);
            writer.writeValue("30");
            writer.writeEndElement();

            writer.writeEndElement();

            writer.writeEndElement();
        }
        writer.writeEndElement();
        writer.close();
    }

}

 XbrliWriterHelper:

public class XbrliWriterHelper {

    private FileOutputStream out;
    private XMLStreamWriter2 writer;
    private XMLPrettyFormatter formatter;

    public void init(XMLValidationSchema schema) throws IOException, XMLStreamException {
        out = new FileOutputStream("Woodstox.xml");
        XMLOutputFactory factory = XMLOutputFactory2.newInstance();
        writer = (XMLStreamWriter2) factory.createXMLStreamWriter(out);
        writer.validateAgainst(schema);
        writer.writeStartDocument("UTF-8", "1.0");

        formatter = new DefaultPrettyFormatter(writer);
        // formatter = new DefaultPrettyFormatter(writer, "  ");
        // formatter = new EmptyPrettyFormatter(writer);
    }

    public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
        formatter.writeStartElementIndention();
        writer.writeStartElement(prefix, localName, namespaceURI);
    }

    public void writeValue(String value) throws XMLStreamException {
        formatter.writeValueIndention();
        writer.writeCharacters(value.toCharArray(), 0, value.length());
    }

    public void writeEndElement() throws XMLStreamException {
        formatter.writeEndElementIndention();
        writer.writeEndElement();
    }

    public void writeAttribute(String localName, String value) throws XMLStreamException {
        writer.writeAttribute(localName, value);
    }

    public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
        writer.writeNamespace(prefix, namespaceURI);
    }

    public void close() throws XMLStreamException, IOException {
        writer.writeEndDocument();
        writer.close();
        out.close();
    }

}

XMLPrettyFormatter:

public interface XMLPrettyFormatter {

    enum NodeType {
        ELEMENT, VALUE
    }

    String DEFAULT_INDENTION = "\t";

    void writeStartElementIndention() throws XMLStreamException;

    void writeValueIndention() throws XMLStreamException;

    void writeEndElementIndention() throws XMLStreamException;

}

DefaultPrettyFormatter:

public class DefaultPrettyFormatter implements XMLPrettyFormatter {

    private String indent = DEFAULT_INDENTION;
    private int currentLevel = 0;
    private NodeType nodeType;

    private XMLStreamWriter2 writer;

    public DefaultPrettyFormatter(XMLStreamWriter2 writer) {
        this.writer = writer;
    }

    public DefaultPrettyFormatter(XMLStreamWriter2 writer, String indent) {
        this.writer = writer;
        this.indent = indent;
    }

    @Override
    public void writeStartElementIndention() throws XMLStreamException {
        nodeType = NodeType.ELEMENT;

        writeLineBreaker();
        for (int i = 0; i < currentLevel; ++i) {
            writeIndention();
        }
        ++currentLevel;
    }

    @Override
    public void writeValueIndention() throws XMLStreamException {
        nodeType = NodeType.VALUE;
    }

    @Override
    public void writeEndElementIndention() throws XMLStreamException {
        --currentLevel;

        if (nodeType == NodeType.ELEMENT) {
            writeLineBreaker();
            for (int i = 0; i < currentLevel; ++i) {
                writeIndention();
            }
        } else {
            // after write value, the node type should back to element
            nodeType = NodeType.ELEMENT;
        }
    }

    private void writeLineBreaker() throws XMLStreamException {
        writer.writeCharacters("\n");
    }

    private void writeIndention() throws XMLStreamException {
        writer.writeCharacters(indent.toCharArray(), 0, indent.length());
    }

}

工程下载:晕啊,找不到上传文件地方,记得以前弄过的。。。只有直接贴文件内容了

POM 依赖

    <dependencies>
        <dependency>
            <groupId>org.codehaus.woodstox</groupId>
            <artifactId>woodstox-core-asl</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb1-impl</artifactId>
            <version>2.2.5.1</version>
        </dependency>
    </dependencies>

book.xsd:

<xs:schema targetNamespace="http://www.test.com/book" xmlns="http://www.test.com/book" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:au="http://www.test.com/author"
    elementFormDefault="qualified">
    
    <xs:import namespace="http://www.test.com/author" schemaLocation="author.xsd" />

    <xs:element name="books" type="booksType" />
    <xs:element name="book" type="bookType" />

    <xs:complexType name="booksType">
        <xs:sequence>
            <xs:element ref="book" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="bookType">
        <xs:sequence>
            <xs:element name="name" type="xs:string" />
            <xs:element ref="au:author" type="xs:string" />
        </xs:sequence>
        <xs:attribute name="id" type="xs:string" />
    </xs:complexType>

</xs:schema>

author.xsd:

<xs:schema targetNamespace="http://www.test.com/author" xmlns="http://www.test.com/author" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified">

    <xs:element name="author" type="authorType" />

    <xs:complexType name="authorType">
        <xs:sequence>
            <xs:element name="age" type="xs:positiveInteger" />
        </xs:sequence>
    </xs:complexType>

</xs:schema>

 

posted @ 2014-01-11 19:41  小1  阅读(2106)  评论(0编辑  收藏  举报