Java 如何使用JAXB封送器对大型文件进行流式处理?

Java 如何使用JAXB封送器对大型文件进行流式处理?,java,streaming,jaxb,Java,Streaming,Jaxb,我面临的问题是如何将一个大的对象列表整理成一个XML文件,如此之大,我无法一步整理完整的列表。我有一个方法可以以块的形式返回这些对象,但是我使用JAXB对它们进行封送,封送器返回的异常是这些对象不是根元素。这在正常情况下是可以的,您希望在一个步骤中整理完整的文档,但是如果我将JAXB_FRAGMENT属性设置为true,也会发生这种情况 这是所需的XML输出: <rootElem> <startDescription></startDescription

我面临的问题是如何将一个大的对象列表整理成一个XML文件,如此之大,我无法一步整理完整的列表。我有一个方法可以以块的形式返回这些对象,但是我使用JAXB对它们进行封送,封送器返回的异常是这些对象不是根元素。这在正常情况下是可以的,您希望在一个步骤中整理完整的文档,但是如果我将JAXB_FRAGMENT属性设置为true,也会发生这种情况

这是所需的XML输出:

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

...

因此,我假设我需要某种监听器,在编写rootElement的结束标记之前,动态加载下一个repeatingElements块以将其提供给封送员。但如何做到这一点呢?到目前为止,我只使用JAXB来整理小文件,JAXB文档并没有给出很多关于该用例的提示。

我对JAXB了解不多,所以我无法提供帮助。但是如果你不介意的话,我有个建议


编写XML要比读取XML容易得多,所以解决问题的方法可能是使用更“低级”的方法。只需使用XML可用的开源库之一编写您自己的封送拆收器。我认为您可以很容易地使用它做您想做的事情。

正如您所发现的,如果一个类没有
@XmlRootElement
注释,那么您就不能将该类的实例传递给封送处理程序。但是,有一种简单的方法可以解决这个问题—将对象包装在
JAXBElement
中,然后将其传递给封送处理程序

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

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


对于重复的内部元素,您仍然必须使用
JAXB_FRAGMENT
属性,否则JAXB每次都会生成XML prolog之类的内容,这是您不想要的。

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

正如@skaffman所建议的,您希望在启用
JAXB_片段
的情况下进行封送,并将对象包装在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();
    }
}
公共类流化封送
{
私有xmlOut;
二等兵;
私有最终类类型;
公共StreamingMarshal(类类型)抛出JAXBEException
{
this.type=type;
JAXBContext context=JAXBContext.newInstance(类型);
Marshaller m=context.createMarshaller();
m、 setProperty(Marshaller.JAXB_片段,Boolean.TRUE);
}
公共void open(字符串文件名)引发XMLStreamException,IOException
{
xmlOut=XMLOutputFactory.newFactory().createXMLStreamWriter(新文件输出流(文件名));
writeStartDocument();
writeStarteElement(“根元素”);
}
公共无效写入(T)抛出JAXBEException
{
JAXBElement元素=新的JAXBElement(QName.valueOf(type.getSimpleName()),type,t);
marshaller.marshall(元素,xmlOut);
}
public void close()引发XMLStreamException
{
writeEndDocument();
xmlOut.close();
}
}

需要在构造函数中设置封送拆收器。这个.marshaller=m;