如何使用JAXB Marshaller流式传输大型文件?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (13)

我面临的问题是如何将大量对象编组为单个XML文件,因此我无法在一个步骤中编组完整列表。我有一个方法以块的形式返回这些对象,但是然后我使用JAXB编组这些对象,编组器返回一个例外情况,即这些对象没有根元素。这对于你想在一个步骤中编组完整文档的正常情况是可以的,但如果将JAXB_FRAGMENT属性设置为true,也会发生这种情况。

这是所需的XML输出:

<rootElem>  
    <startDescription></startDescription>  
    <repeatingElem></repeatingElem>
    <repeatingElem></repeatingElem>...
</rootElem>

所以我假设我需要某种监听器来动态加载下一个重复元素块,以便在编写rootElement的结束标记之前将其馈送给编组器。但如何做到这一点?到目前为止,我只使用JAXB来编组小文件,而JAXB文档并没有提供太多的提示。

提问于
用户回答回答于

正如你发现的,如果一个类没有@XmlRootElement注解,那么你不能将该类的一个实例传递给编组。但是,有一个简单的解决方法 - 将对象包装在a中JAXBElement,然后将其传递给编组。

现在JAXBElement是一个相当笨拙的野兽,但它所做的是包含要编组的对象的元素名称和名称空间,这些信息通常会包含在@XmlRootElement注释中。只要你有名字和名字空间,你可以构造一个JAXBElement包装你的POJO,并编组它。

如果你的POJO是由XJC生成的,那么它也会生成一个ObjectFactory包含工厂方法的类来JAXBElement为你构建包装器,使事情变得更简单。

你仍然必须将该JAXB_FRAGMENT属性用于重复的内部元素,否则JAXB每次都会生成类似XML prolog的内容,这是你不希望的。

用户回答回答于

我知道这是一个老问题,但我在搜索另一个类似问题的重复内容时遇到了这个问题。

你想要JAXB_FRAGMENT启用Marshal 并将对象包装在JAXBElement中。然后你重复编组重复元素的每个单独实例。基本上,这听起来像你想要的东西大概是这样的:

public class StreamingMarshal<T>
{
    private XMLStreamWriter xmlOut;
    private Marshaller marshaller;
    private final Class<T> type;

    public StreamingMarshal(Class<T> type) throws JAXBException
    {
        this.type = type;
        JAXBContext context = JAXBContext.newInstance(type);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
    }

    public void open(String filename) throws XMLStreamException, IOException
    {
        xmlOut = XMLOutputFactory.newFactory().createXMLStreamWriter(new FileOutputStream(filename));
        xmlOut.writeStartDocument();
        xmlOut.writeStartElement("rootElement");
    }

    public void write(T t) throws JAXBException
    {
        JAXBElement<T> element = new JAXBElement<T>(QName.valueOf(type.getSimpleName()), type, t);
        marshaller.marshal(element, xmlOut);
    }

    public void close() throws XMLStreamException
    {
        xmlOut.writeEndDocument();
        xmlOut.close();
    }
}

扫码关注云+社区