【发布时间】:2018-01-30 10:22:33
【问题描述】:
我正在尝试设置一个 Apache Camel 路由,该路由输入一个大型 XML 文件,然后使用字段条件将有效负载拆分为两个不同的文件。 IE。如果 ID 字段以 1 开头,则转到一个输出文件,否则转到另一个。使用 Camel 不是必须的,我也看过 XSLT 和常规 Java 选项,但我只是觉得这应该可行。
我已经介绍了拆分实际有效负载,但在确保父节点(包括标头)也包含在每个文件中时遇到了问题。由于文件可能很大,我想确保将流用于有效负载。我觉得我已经在这里阅读了数百个不同的问题、博客条目等,并且几乎每个案例都包括将整个文件加载到内存中,将文件平均分成多个部分,或者仅使用有效负载节点单独使用。
我的原型 XML 文件如下所示:
<root>
<header>
<title>Testing</title>
</header>
<orders>
<order>
<id>11</id>
<stuff>One</stuff>
</order>
<order>
<id>20</id>
<stuff>Two</stuff>
</order>
<order>
<id>12</id>
<stuff>Three</stuff>
</order>
</orders>
</root>
结果应该是两个文件 - 条件为真(id 以 1 开头):
<root>
<header>
<title>Testing</title>
</header>
<orders>
<order>
<id>11</id>
<stuff>One</stuff>
</order>
<order>
<id>12</id>
<stuff>Three</stuff>
</order>
</orders>
</root>
条件假:
<root>
<header>
<title>Testing</title>
</header>
<orders>
<order>
<id>20</id>
<stuff>Two</stuff>
</order>
</orders>
</root>
我的原型路线:
from("file:" + inputFolder)
.log("Processing file ${headers.CamelFileName}")
.split()
.tokenizeXML("order", "*") // Includes parent in every node
.streaming()
.choice()
.when(body().contains("id>1"))
.to("direct:ones")
.stop()
.otherwise()
.to("direct:others")
.stop()
.end()
.end();
from("direct:ones")
//.aggregate(header("ones"), new StringAggregator()) // missing end condition
.to("file:" + outputFolder + "?fileName=ones-${in.header.CamelFileName}&fileExist=Append");
from("direct:others")
//.aggregate(header("others"), new StringAggregator()) // missing end condition
.to("file:" + outputFolder + "?fileName=others-${in.header.CamelFileName}&fileExist=Append");
这按预期工作,除了为每个节点添加父标签(页眉和页脚,如果你愿意的话)。仅使用 tokenizeXML 中的节点仅返回节点本身,但我不知道如何添加页眉和页脚。最好我想将父标签流式传输到页眉和页脚属性中,并在拆分之前和之后添加它们。
我该怎么做?我是否需要先对父标签进行标记,这是否意味着两次流式传输文件?
最后,您可能会注意到最后的聚合。我不想在写入文件之前聚合每个节点,因为这违背了流式传输它并使整个文件超出内存的目的,但我想我可能会通过在写入之前聚合多个节点来获得一些性能文件,以减少写入每个节点的驱动器的性能影响。我不确定这样做是否有意义。
【问题讨论】:
-
你不能在没有父标签的情况下拆分,然后在聚合后手动添加父标签吗?那应该是最省力的方式吧?
-
是的,我相信我需要在没有父标签的情况下进行拆分,但我不确定如何在路由上下文中读取父标签,以便我可以手动添加它们。父标签也包含数据,所以它不能只是一个静态的 xml 结构,如果这是你的建议?
-
我猜你可以将它们提取为字符串并将它们保存为 Exchange 属性,然后在聚合结束时使用它。
-
您对如何在不阅读整个文件的情况下执行此操作有什么建议吗?
-
如果您的父标签包含您需要的数据,您如何将它们从聚合中排除?如果它们包含所有相同的数据,则它是一个静态结构,如果不是,则需要聚合它们以获得数据。
标签: java xml stream apache-camel tokenize