代码之家  ›  专栏  ›  技术社区  ›  Andy

JAXB对XML的编组方式与OutputStream和StringWriter不同

  •  12
  • Andy  · 技术社区  · 14 年前

    如果回答了这个问题,我很抱歉,但是我一直使用的搜索词(即 jaxb@xmltattribute压缩 JAXB XML封送到字符串不同的结果 )什么都没想出来。

    我正在使用JAXB取消/封送带注释的对象 @XmlElement @XmlAttribute 注释。我有一个格式化程序类,它提供了两个方法——一个方法包装marshal方法并接受要封送的对象,另一个方法 OutputStream 另一个只接受对象并以字符串形式返回XML输出。不幸的是,这些方法不能为相同的对象提供相同的输出。封送到文件时,内部用标记的简单对象字段 @ XmlAttribute 印制为:

    <element value="VALUE"></element>
    

    当封送到字符串时,它们是:

    <element value="VALUE"/>
    

    对于这两种情况,我更喜欢第二种格式,但我对如何控制差异很好奇,不管怎样,我都会满足于它们是相同的。我甚至创建了一个静态封送拆收器,两个方法都使用它来消除不同的实例值。格式代码如下:

    /** Marker interface for classes which are listed in jaxb.index */
    public interface Marshalable {}
    

    /** Local exception class */
    public class XMLMarshalException extends BaseException {}
    

    /** Class which un/marshals objects to XML */
    public class XmlFormatter {
        private static Marshaller marshaller = null;
        private static Unmarshaller unmarshaller = null;
    
        static {
            try {
                JAXBContext context = JAXBContext.newInstance("path.to.package");
                marshaller = context.createMarshaller();
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
    
                unmarshaller = context.createUnmarshaller();
            } catch (JAXBException e) {
                throw new RuntimeException("There was a problem creating a JAXBContext object for formatting the object to XML.");
            }
        }
    
        public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException {
            try {
                marshaller.marshal(obj, os);
            } catch (JAXBException jaxbe) {
                throw new XMLMarshalException(jaxbe);
            }
        }
    
        public String marshalToString(Marshalable obj) throws XMLMarshalException {
            try {
                StringWriter sw = new StringWriter();
                return marshaller.marshal(obj, sw);
            } catch (JAXBException jaxbe) {
                throw new XMLMarshalException(jaxbe);
            }
        }
    }
    

    /** Example data */
    @XmlType
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Data {
    
        @XmlAttribute(name = value)
        private String internalString;
    }
    

    /** Example POJO */
    @XmlType
    @XmlRootElement(namespace = "project/schema")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Container implements Marshalable {
    
        @XmlElement(required = false, nillable = true)
        private int number;
    
        @XmlElement(required = false, nillable = true)
        private String word;
    
        @XmlElement(required = false, nillable = true)
        private Data data;
    }
    

    呼叫的结果 marshal(container, new FileOutputStream("output.xml")) marshalToString(container) 如下:

    输出到文件

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
    <ns2:container xmlns:ns2="project/schema">  
        <number>1</number>  
        <word>stackoverflow</word>  
        <data value="This is internal"></data>  
    </ns2:container>
    

    输出到字符串

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
    <ns2:container xmlns:ns2="project/schema">  
        <number>1</number>  
        <word>stackoverflow</word>  
        <data value="This is internal"/>  
    </ns2:container>
    
    4 回复  |  直到 12 年前
        1
  •  8
  •   Eric Thorbjornsen    14 年前

    看起来这可能是JAXB中的一个“bug”。在源代码中,对marshal()的调用基于输出/编写器类型参数创建不同的编写器:

    public void marshal(Object obj, OutputStream out, NamespaceContext inscopeNamespace) throws JAXBException {
        write(obj, createWriter(out), new StAXPostInitAction(inscopeNamespace,serializer));
    }
    
    public void marshal(Object obj, XMLStreamWriter writer) throws JAXBException {
        write(obj, XMLStreamWriterOutput.create(writer,context), new StAXPostInitAction(writer,serializer));
    }
    

    对于如何处理“空元素”,作者的实现是不同的。以上代码来自:

    jaxb ri\runtime\src\com\sun\xml\bind\v2\runtime\marshallerimpl.java。

    你正在创作的两位作家是:

    jaxb ri\runtime\src\com\sun\xml\bind\v2\runtime\output\utf8xmlout.java

    jaxb ri\runtime\src\com\sun\xml\bind\v2\runtime\output\xmlstreamwriteroutput.java

        2
  •  2
  •   bdoughan    14 年前

    好消息是,JAXB是一个具有多个实现的规范(就像JPA)。如果一个实现不能满足您的需求,那么其他实现也可以使用,例如eclipselink jaxb(moxy):

        3
  •  1
  •   mdma    14 年前

    我不知道为什么JAXB会这样做——或者即使它是JAXB——例如,如果JAXB通过一个SAXContentHandler输出XML,那么它就无法直接控制生成的标签有多接近。

    为了获得一致的行为,可以将输出流包装在OutputStreamWriter中,例如

       public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException {
            try {
                marshaller.marshal(obj, new OutputStreamWriter(os, "UTF-8"));
            } catch (JAXBException jaxbe) {
                throw new XMLMarshalException(jaxbe);
            }
        }
    

    沿着同一行,您可能会看到如果将StringWriter包装在一个PrintWriter中会发生什么。也许有一些自定义代码可以检测 StringWriter 尽量缩短输出。听起来不太可能,但我没有其他解释。

        4
  •  0
  •   lily    14 年前

    为什么重要?<tag attribute=“value”></tag>等同于XML中的<tag attribute=“value”/>。