Spring 批量 JAXB XML 解组目标多个 XML 节点

Spring Batch JAXB XML unmarshal targeting multiple XML nodes

我正在使用 Spring 批处理(使用 Spring 引导)在 MultiResourceItemReader 中使用 StaxEventItemReader 读取 XML 文件。批处理 reader 旨在针对 XML-source.

中每个寄存器的 <Receipt> 和 process/write

我的问题是我需要将<Header>内容与每个寄存器一起写入。我能够配置 Jaxb2Marshaller 以读取收据 one-by-one(为每个寄存器获得对 process() 的回调),但我无法弄清楚如何使 reader/unmarshaller 到每次都阅读 <Header><Receipt>

也许我必须创建一个 ReceiptWrapper class 来保存 header + 收据?那么,如何指示Jaxb2Marshaller这样做呢?以及如何注释Wrapper class? 我对注释一团糟,reader.setFragmentRootElementNames()marshaller.setClassesToBeBound().

有什么简单的方法可以实现吗?

目的是在每个寄存器的开头连接header。

注意: 我通过 Eclipse JAXB 代码生成从我生成的 XSD 创建了 Header 和收据 classes。

下面是XML的结构,读起来:

<ProcesosEIAC xsi:schemaLocation="http://www.tirea.es/EIAC/ProcesosEIAC ProcesosEIAC.xsd" xmlns="http://www.tirea.es/EIAC/ProcesosEIAC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Header>
    <!-- [...] -->
</Header>
<Objects>
    <Receipt>
        <!-- [...] -->
    </Receipt>
    [...]
    <Receipt>
        <!-- [...] -->
    </Receipt>
</Objects>

以下是我的摘录:

// Don't know how this should be...
fileReader.setFragmentRootElementNames(new String[]{"ProcesosEIAC", "Header", "Receipt"});

Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(ReceiptWrapper.class /*, HeaderType.class, ReceiptType.class*/);
fileReader.setUnmarshaller(marshaller);

我终于成功了。从本质上讲,根据我的理解,要获得结果,您必须设置 StaxEventItemReader 将要生成的片段的根元素。

就我而言:

fileReader.setFragmentRootElementNames(new String[]{ "Header", "Receipt" }
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(HeaderType.class, ReceiptType.class);
fileReader.setUnmarshaller(marshaller);

其中 HeaderType.classReceiptType.class 是 JAXB-generated classes.

诀窍是为 JAXB classes(例如 MyXmlTargetElement)定义一个公共接口或基础 class,以便 reader 类型声明与未编组的 objects:

StaxEventItemReader<MyXmlTargetElement> fileReader = new StaxEventItemReader<>();

这允许按顺序读取元素 one-by-one(包括 <Header>)并且不需要包装器 class。

然后在 Batch ItemProcessor 的 process(MyXmlTargetElement item) 方法中,我使用 instanceof 检查项目的实际类型,当 header 已被读取时,将其设置为私有成员字段(lastHeader).然后,当 <Receipt> 出现时,您已经在该成员中存储了之前的 header。