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

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

这是所需的XML输出:

   ...  

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

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

正如@skaffman建议的那样,你想要在启用JAXB_FRAGMENT并且你的对象包装在JAXBElement中的Marshal。 然后,您反复编组重复元素的每个单独实例。 基本上听起来你想要的东西大致是这样的:

 public class StreamingMarshal { private XMLStreamWriter xmlOut; private Marshaller marshaller; private final Class type; public StreamingMarshal(Class 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 element = new JAXBElement(QName.valueOf(type.getSimpleName()), type, t); marshaller.marshal(element, xmlOut); } public void close() throws XMLStreamException { xmlOut.writeEndDocument(); xmlOut.close(); } } 

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

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

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

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

我对JAXB知之甚少,所以我无能为力。 但如果你不介意,我有一个建议。

编写XML比阅读它要容易得多,因此解决问题的方法可能是使用更“低级”的方法。 只需使用一个可用的XML开源库编写自己的marshaller。 我想你可以用dom4j轻松做你想做的事。