JAXB 能否以块的形式解析大型 XML 文件

2022-09-01 16:48:40

我需要解析可能较大的 XML 文件,其中架构已在多个 XSD 文件中提供给我,因此 XML 绑定受到高度青睐。我想知道我是否可以使用JAXB以块的形式解析文件,如果是这样,如何解析。


答案 1

因为代码很重要,所以这里有一个将大文件读成块的人。它可以以这种方式使用PartialUnmarshallernew PartialUnmarshaller<YourClass>(stream, YourClass.class)

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.*;
import java.io.InputStream;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static javax.xml.stream.XMLStreamConstants.*;

public class PartialUnmarshaller<T> {
    XMLStreamReader reader;
    Class<T> clazz;
    Unmarshaller unmarshaller;

    public PartialUnmarshaller(InputStream stream, Class<T> clazz) throws XMLStreamException, FactoryConfigurationError, JAXBException {
        this.clazz = clazz;
        this.unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
        this.reader = XMLInputFactory.newInstance().createXMLStreamReader(stream);

        /* ignore headers */
        skipElements(START_DOCUMENT, DTD);
        /* ignore root element */
        reader.nextTag();
        /* if there's no tag, ignore root element's end */
        skipElements(END_ELEMENT);
    }

    public T next() throws XMLStreamException, JAXBException {
        if (!hasNext())
            throw new NoSuchElementException();

        T value = unmarshaller.unmarshal(reader, clazz).getValue();

        skipElements(CHARACTERS, END_ELEMENT);
        return value;
    }

    public boolean hasNext() throws XMLStreamException {
        return reader.hasNext();
    }

    public void close() throws XMLStreamException {
        reader.close();
    }

    void skipElements(int... elements) throws XMLStreamException {
        int eventType = reader.getEventType();

        List<Integer> types = asList(elements);
        while (types.contains(eventType))
            eventType = reader.next();
    }
}

答案 2

用户指南中对此进行了详细介绍。从 http://jaxb.java.net/ 下载的 JAXB 包含一个如何一次解析一个区块的示例。

当文档很大时,通常是因为其中有重复的部分。它可能是具有大量行项目列表的采购订单,也可能是具有大量日志条目的 XML 日志文件。

这种XML适用于块处理;主要思想是使用StAX API,运行一个循环,并单独取消元帅各个块。您的程序作用于单个块,然后将其丢弃。这样,您最多只能将内存中的一个块保留,从而允许您处理大型文档。

有关如何执行此操作的详细信息,请参阅 JAXB RI 发行版中的流取消编组示例和部分取消编组示例。流式处理-取消分组示例有一个优点,它可以在任意嵌套级别处理块,但它需要您处理推送模型,--- JAXB unmarshaller 会将新块“推送”给您,您需要在那里处理它们。

相比之下,部分取消编组示例在拉模型中工作(这通常使处理更容易),但这种方法在重复部分以外的数据绑定部分有一些限制。


推荐