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

Mik*_*and 20 java streaming jaxb

我面临的问题是如何将一大堆对象编组到一个XML文件中,如此之大,我无法一步完成整个列表的编组.我有一个方法以块的形式返回这些对象,但随后我使用JAXB编组它们,marshaller返回一个例外,即这些对象不是根元素.对于您希望在一个步骤中编组完整文档的正常情况,这是正常的,但如果我将JAXB_FRAGMENT属性设置为true,也会发生这种情况.

这是所需的XML输出:

<rootElem>  
    <startDescription></startDescription>  
    <repeatingElem></repeatingElem>
    <repeatingElem></repeatingElem>...
</rootElem>
Run Code Online (Sandbox Code Playgroud)

所以我假设我需要某种类型的侦听器来动态加载下一块重复元素,以便在编写rootElement的结束标记之前将其提供给编组器.但是怎么做呢?到目前为止,我只使用JAXB来编组小文件,而JAXB文档没有给出该用例的大量提示.

Oph*_*ian 21

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

正如@skaffman建议的那样,你想要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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 需要在构造函数中设置marshaller.this.marshaller =米; (2认同)

ska*_*man 9

正如您所发现的,如果一个类没有@XmlRootElement注释,那么您就无法将该类的实例传递给编组器.但是,有一个简单的方法 - 将对象包装在a中JAXBElement,然后将其传递给marshaller.

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

如果您的POJO是由XJC生成的,那么它还将生成一个ObjectFactory类,其中包含用于JAXBElement为您构建包装器的工厂方法,使事情变得更容易.

你仍然必须使用该JAXB_FRAGMENT属性来重复内部元素,否则JAXB每次都会产生类似XML prolog的东西,这是你不想要的.


jas*_*cao -10

我对JAXB不太了解,所以我帮不上忙。但如果你不介意的话,我有一个建议。

编写 XML 比读取 XML 容易得多,因此您的问题的解决方案可能是使用更“低级”的方法。只需使用可用的 XML 开源库之一编写您自己的编组器即可。我认为你可以使用dom4j轻松地做你想做的事。