使用JAXB和XMLStreamWriter编写空标记 [英] Write empty tag with JAXB and XMLStreamWriter

查看:260
本文介绍了使用JAXB和XMLStreamWriter编写空标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用标准的JAXB实现。

这是我的带注释的类(是一组类的一部分)

I'm using standard JAXB implementation.
This is my annotated class (is part of a set of classes)

@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和其他人,但我需要将对象保存到文件中)。
任何建议或解决方案?

the result is <my-class attr="attrValue"></my-class> but I need empty tag as <my-class attr="attrValue"/>. I tried some different combination (and read dozen of SO questions) of writer and target stream (not only file,but also StringWriter and others but I need to persist object to file). Any advice or solution?

推荐答案

我使用替换<的自定义XMLStreamWriter解析; tag-name>< / tag-name> < tag-name /> 如果tag-name完全没有内容。
背后的想法是在 startElement-endElement 之间推迟写事件。
当找到 endElement 时,如果不是边界之间的内容事件,则使用 emptyElement 替换 startElement 并禁止 endElement
很抱歉评论不好,我稍后会回来让它更容易理解。

I resolved using a custom XMLStreamWriter that replace the <tag-name></tag-name> with <tag-name/> if tag-name has no content at all. The idea behind is to defer write events between startElement-endElement. When an endElement is found if the aren't content events between boundaries replace startElement with a emptyElement and suppress endElement at all. Sorry for poor comments, I'll came back later to make it more understandable.

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

这篇关于使用JAXB和XMLStreamWriter编写空标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆