java 如何使用 JAXB Marshaller 流式传输大文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1775202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to stream large Files using JAXB Marshaller?
提问by Mike Rohland
The Problem I'm facing is how to marshall a large list of objects into a single XML File, so large I can not marshall the complete list in one step. I have a method that returns these objects in chunks, but then I marshall these using JAXB, the marshaller returns with an exception that these objects are no root elements. This is ok for the normal case there you want to marshall the complete document in one step, but it also happens if I set the JAXB_FRAGMENT Property to true.
我面临的问题是如何将一大堆对象编组到一个 XML 文件中,如此之大,我无法一步编组完整的列表。我有一个方法以块的形式返回这些对象,但是然后我使用 JAXB 对这些对象进行编组,编组器返回一个例外,即这些对象不是根元素。对于您希望一步整理完整文档的正常情况,这是可以的,但如果我将 JAXB_FRAGMENT 属性设置为 true,也会发生这种情况。
This is the desired XML output:
这是所需的 XML 输出:
<rootElem>
<startDescription></startDescription>
<repeatingElem></repeatingElem>
<repeatingElem></repeatingElem>...
</rootElem>
So I assume I need some kind of listener that dynamically loads the next chunk of repeatingElements to feed it to the marshaller before he would write the closing tag of the rootElement. But how to do that? Up until now I only used JAXB to marshall small files and the JAXB documentation does not give much hints for that use case.
所以我假设我需要某种侦听器来动态加载下一个重复元素块,以便在编组器编写 rootElement 的结束标记之前将其提供给编组器。但是怎么做呢?到目前为止,我只使用 JAXB 来编组小文件,而 JAXB 文档并没有为该用例提供太多提示。
回答by Ophidian
I'm aware that this is an old question but I came across it while searching for duplicates of another similar question.
我知道这是一个老问题,但我在搜索另一个类似问题的重复项时遇到了它。
As @skaffman suggests, you want to Marshal with JAXB_FRAGMENTenabled and your objects wrapped in JAXBElement. You then repeatedly marshal each individual instance of the repeated element. Basically it sounds like you want something roughly like this:
正如@skaffman 所建议的那样,您希望使用已JAXB_FRAGMENT启用的方式进行编组,并且您的对象包装在 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();
}
}
回答by skaffman
As you've discovered, if a class does not have the @XmlRootElementannotation, then you can't pass an instance of that class to the marshaller. However, there is an easy way around this - wrap the object in a JAXBElement, and pass that to the marshaller instead.
正如您所发现的,如果一个类没有@XmlRootElement注释,那么您就不能将该类的实例传递给编组器。但是,有一个简单的方法可以解决这个问题 - 将对象包装在 a 中JAXBElement,然后将其传递给编组器。
Now JAXBElementis a rather clumsy beast, but what it does is contains the element name and namespace of the object that you want to marshal, information which would normally be contained in the @XmlRootElementannotation. As long as you have the name and namespace, you can construct a JAXBElementto wrap your POJO, and marshal that.
现在JAXBElement是一个相当笨拙的野兽,但它所做的是包含要编组的对象的元素名称和命名空间,这些信息通常包含在@XmlRootElement注释中。只要您拥有名称和命名空间,就可以构造一个JAXBElement来包装您的 POJO,并对其进行编组。
If your POJOs were generated by XJC, then it will also have generated an ObjectFactoryclass which contains factory methods for building JAXBElementwrappers for you, making things a bit easier.
如果您的 POJO 是由 XJC 生成的,那么它也会生成一个ObjectFactory类,其中包含JAXBElement为您构建包装器的工厂方法,使事情变得更容易一些。
You'll still have to use the JAXB_FRAGMENTproperty for the repeating inner elements, otherwise JAXB will generate stuff like the XML prolog each time, which you don't want.
您仍然必须JAXB_FRAGMENT为重复的内部元素使用该属性,否则 JAXB 每次都会生成诸如 XML 序言之类的东西,这是您不想要的。
回答by jassuncao
I don't know much of JAXB, so I can't help. But if you don't mind, I have a suggestion.
我不太了解 JAXB,所以我无能为力。但如果你不介意的话,我有一个建议。
Writing XML is a lot easier than reading it, so an solution for your problem might be to use a more "low level" approach. Just write your own marshaller using one of the available open source libraries for XML. I think you can easily do what you want using dom4j.
编写 XML 比阅读它容易得多,因此解决您的问题的方法可能是使用更“低级”的方法。只需使用可用的 XML 开源库之一编写您自己的编组器。我认为您可以使用dom4j轻松地做您想做的事。

