4

我一直在寻找最好的方法来做到这一点,但我似乎无法找到一个明确的答案应该如何做到这一点。

我的 Java 代码中有一个 Arraylist of Files,表示应合并并写入新 XML 文件的 xml 文件列表。这不是一个固定长度的列表,我估计它会在 2-10 个文件之间。所有这些文件都具有非常相似的文档结构,但是在合并时应该对某些属性进行求和。例如:

文件 1

<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 语法感到很困惑。虽然我不完全确定这些文件可能达到的大小,但我会非常惊讶它们会大于 1mb,因此作为 JDOM 或 XOM 的 Java DOM 解析器也可以工作,但我必须加载所有这些文件同时或成对迭代。

什么被认为是做到这一点的最佳方式?如果 XSLT 被认为是最好的解决方案,是否有可能给我一些提示?

4

2 回答 2

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 检索节点,但即便如此,您也必须编写逻辑以确保正确更新。

于 2013-07-16T17:10:22.693 回答
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 的作者。

于 2014-12-02T23:22:47.787 回答