我一直在寻找最好的方法,但我似乎无法找到明确的答案。
我的Java代码中有一个文件的Arraylist,表示应该合并并写入新XML文件的xml文件列表。这不是固定长度列表,我估计它将在2-10个文件之间。所有这些文件都有一个非常相似的文档结构,但是一些属性应该在合并时求和。例如:
File1中
<events>
<commandEvents date="2013-07-16">
<commandEvent count="1" commandId="update"/>
<commandEvent count="1" commandId="debug"/>
<commandEvent count="3" commandId="resume"/>
</commandEvents>
</events>
文件2
<events>
<commandEvents date="2013-07-16">
<commandEvent count="2" commandId="resume"/>
</commandEvents>
<commandEvents date="2013-07-15">
<commandEvent count="2" commandId="resume"/>
<commandEvent count="1" commandId="update"/>
</commandEvents>
</events>
结果
<events>
<commandEvents date="2013-07-16">
<commandEvent count="1" commandId="update"/>
<commandEvent count="1" commandId="debug"/>
<commandEvent count="5" commandId="resume"/>
</commandEvents>
<commandEvents date="2013-07-15">
<commandEvent count="2" commandId="resume"/>
<commandEvent count="1" commandId="update"/>
</commandEvents>
</events>
为了澄清,合并应该发生在commandEvents [@date] / commandEvent [@commandId]上.commandEvent元素有一些更多的属性,但是每个元素都是相同的,所以我在这里省略了它们。并非每个文档都提供所有日期。
我首先找到了一些XSLT路由的答案,但我对XSLT语法很困惑。 虽然我不完全确定这些文件可能达到的大小,但我会非常惊讶它们将是&gt; 1mb,所以像JDOM或XOM这样的Java DOM解析器可能也可以工作,但我必须加载所有这些文件同时或成对迭代。
什么被认为是最好的方法?如果XSLT被认为是最好的解决方案,那么可以给我一些提示吗?
答案 0 :(得分:3)
这是一个简单的合并,其中一个文档中根节点的所有子节点都附加到第二个文档的根节点:
public static void mergeSecondLevel(Document from, Document to) {
Element fromRoot = from.getDocumentElement();
Element toRoot = to.getDocumentElement();
Node child = null;
while ((child = fromRoot.getFirstChild()) != null) {
to.adoptNode(child);
toRoot.appendChild(child);
}
}
如果您在合并它们之前尝试对节点进行某种处理(您说某些属性应该求和),那么这将是不够的。有一个链接的帖子,涵盖了使用XPath来检索节点,但即使这样,你也必须编写逻辑来确保正确的更新。
答案 1 :(得分:1)
检查XmlCombiner这是一个实现XML合并的Java库,并允许添加过滤器,您可以在其中指定用于汇总'count'属性值的逻辑。
以下是库初始化的代码:
import org.atteo.xmlcombiner.XmlCombiner;
// create combiner specifying the attributes which are used as a keys
XmlCombiner combiner = new XmlCombiner(Lists.newArrayList("date", "commandId"));
// add the filter
combiner.setFilter(filter);
// combine files
combiner.combine(firstFile);
combiner.combine(secondFile);
// store the result
combiner.buildDocument(resultFile);
以下是过滤器本身的代码:
XmlCombiner.Filter filter = new XmlCombiner.Filter() {
@Override
public void postProcess(Element recessive, Element dominant, Element result) {
if (recessive == null || dominant == null) {
return;
}
Attr recessiveNode = recessive.getAttributeNode("count");
Attr dominantNode = dominant.getAttributeNode("count");
if (recessiveNode == null || dominantNode == null) {
return;
}
int recessiveValue = Integer.parseInt(recessiveNode.getValue());
int dominantValue = Integer.parseInt(dominantNode.getValue());
result.setAttribute("count", Integer.toString(recessiveValue + dominantValue));
}
};
免责声明:我是XmlCombiner的作者。