使用JAXB和XMLStreamWriter编写空标记

时间:2014-11-26 20:56:24

标签: java xml jaxb

我正在使用标准的JAXB实现 这是我的带注释的类(是一组类的一部分)

@XmlType()
@XmlAccessorType(FIELD)
class MyClass {
  @XmlValue
  protected final String value = null;
  @XmlAttribute
  protected String attr;

  ...get/set for attr...
}

我正在使用

编写根对象
JaxbContext ctx = JAXBContext.newInstance("path.to.package");
XMLStreamWriter writer = new IndentingXMLStreamWriter(file); //stax-utils writer
ctx.marshal(rootObject, writer);

结果为<my-class attr="attrValue"></my-class>,但我需要空标记为<my-class attr="attrValue"/>。 我尝试了编写器和目标流的一些不同组合(并读取了十几个SO问题)(不仅是文件,还有StringWriter和其他人,但我需要将对象保存到文件中)。 有什么建议或解决方案吗?

2 个答案:

答案 0 :(得分:2)

这是在编组到XMLStreamWriter时可能出现的问题。如果您可以封送到FileFileOutputStreamFileWriter来获取您正在寻找的行为。

注意:

要使用这些输出目标格式化输出,您可以在Marshaller上设置以下属性:

marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

答案 1 :(得分:1)

我决定使用自定义XMLStreamWriter,如果tag-name根本没有内容,则将<tag-name></tag-name>替换为<tag-name/>。 背后的想法是推迟 startElement-endElement 之间的写事件。 当找到 endElement 时,如果不是边界之间的内容事件,则使用 emptyElement 替换 startElement 并禁止 endElement 一点都不 对不起评论不好,我稍后会回来让它更容易理解。

public class EmptyTagXMLStreamWriter extends StreamWriterDelegate {
    class Event {
        Method m;
        Object[] args;
    }
    enum EventEnum {
        writeStartElement,
        writeAttribute,
        writeNamespace,
        writeEndElement,
        setPrefix,
        setDefaultNamespace,    
    }
    private List<Event> queue = new ArrayList<Event>();

    protected EmptyTagXMLStreamWriter(XMLStreamWriter out) {
        super(out);
    }

    @Override
    public void writeStartElement(String localName) throws XMLStreamException {
        d(e(m("writeStartElement",String.class)), localName);
    }
    @Override
    public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException
    {
        d(e(m("writeStartElement",String.class,String.class)), namespaceURI, localName);
    }
    @Override
    public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException
    {
        d(e(m("writeStartElement",String.class,String.class,String.class)), prefix, localName, namespaceURI);
    }
    @Override
    public void writeAttribute(String localName, String value)
            throws XMLStreamException {
        d(e(m("writeAttribute",String.class, String.class)), localName, value);
    }
    @Override
    public void writeAttribute(String namespaceURI, String localName,
            String value) throws XMLStreamException {
        d(e(m("writeAttribute",String.class, String.class, String.class)), namespaceURI, localName, value);
    }
    @Override
    public void writeAttribute(String prefix, String namespaceURI,
            String localName, String value) throws XMLStreamException {
        d(e(m("writeAttribute",String.class, String.class, String.class, String.class)), prefix, namespaceURI, localName, value);
    }
    @Override
    public void writeCData(String data) throws XMLStreamException {
        fq();
        super.writeCData(data);
    }
    @Override
    public void writeCharacters(char[] text, int start, int len)
            throws XMLStreamException {
        fq();
        super.writeCharacters(text, start, len);
    }
    @Override
    public void writeCharacters(String text) throws XMLStreamException {
        fq();
        super.writeCharacters(text);
    }
    @Override
    public void writeComment(String data) throws XMLStreamException {
        fq();
        super.writeComment(data);
    }
    @Override
    public void writeDTD(String dtd) throws XMLStreamException {
        fq();
        super.writeDTD(dtd);
    }
    @Override
    public void writeProcessingInstruction(String target)
            throws XMLStreamException {
        fq();
        super.writeProcessingInstruction(target);
    }
    @Override
    public void writeProcessingInstruction(String target, String data)
            throws XMLStreamException {
        fq();
        super.writeProcessingInstruction(target, data);
    }
    @Override
    public void writeNamespace(String prefix, String namespaceURI)
            throws XMLStreamException {
        d(e(m("writeNamespace",String.class, String.class)), prefix, namespaceURI);
    }
    @Override
    public void writeEndElement() throws XMLStreamException {
        d(e(m("writeEndElement")));
    }
    @Override
    public void writeEndDocument() throws XMLStreamException {
        fq();
        super.writeEndDocument();
    }
    @Override
    public void writeDefaultNamespace(String namespaceURI)
            throws XMLStreamException {
        super.writeDefaultNamespace(namespaceURI);
    }
    @Override
    public void flush() throws XMLStreamException {
        if(queue.isEmpty())
            super.flush();
    }
    @Override
    public void close() throws XMLStreamException {
        fq();
        out.close();
    }
    @Override
    public void setPrefix(String prefix, String uri) throws XMLStreamException {
        d(e(m("setPrefix", String.class, String.class)), prefix, uri);
    }
    @Override
    public void setDefaultNamespace(String uri) throws XMLStreamException {
        d(e(m("setDefaultNamespace", String.class)), uri);
    }

    void d(Event e,Object...args) throws XMLStreamException {
        e.args = args;
        switch(EventEnum.valueOf(e.m.getName()))
        {
            case writeStartElement:
                fq();
                queue.add(e);
                break;
            case writeAttribute:
            case writeNamespace:
            case setPrefix:
            case setDefaultNamespace:
                if(!queue.isEmpty())
                    queue.add(e);
                else
                    ex(e, args);
                break;
            case writeEndElement:
                if(!queue.isEmpty())
                {
                    final Event e1 = queue.get(0);
                    e1.m = m("writeEmptyElement", e1.m.getParameterTypes());
                    fq();
                }
                else
                {
                    ex(e, args);
                }
                break;
        }
    }
    Event e(Method m,Object...params)
    {
        final Event e = new Event();
        e.m = m;
        e.args = params;
        return e;
    }
    Method m(String methodName,Class<?>...args) throws XMLStreamException {
        try {
            return XMLStreamWriter.class.getMethod(methodName, args);
        } catch (Exception e) {
            throw new XMLStreamException(e);
        }
    }
    void fq() throws XMLStreamException
    {
        for(int i = 0;i < queue.size();i++)
        {
            Event e = queue.get(i);
            ex(e, e.args);
        }
        queue.clear();
    }
    void ex(Event e,Object...args) throws XMLStreamException
    {
        try
        {
            e.m.invoke(super.out, e.args);
        }
        catch(Exception ex)
        {
            throw new XMLStreamException(ex);
        }
    }
}