2013-07-16 109 views
4

我一直在尋找最好的方法來做到這一點,但我似乎無法找到明確的答案應該如何完成。在Java中合併多個XML文件

我在我的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語法來做到這一點。 雖然我並不完全確定這些文件可能會達到的大小,但是我會非常驚訝的發現它們會大於1mb,所以像JDOM或XOM一樣的Java DOM解析器也可以工作,但是我必須加載所有這些文件在同一時間或成對迭代。

什麼被視爲做到這一點的最佳方式?如果XSLT被認爲是最好的解決方案,是否有可能爲我提供一些技巧?

+0

如果將文件加載到DOM中,內存是否會成爲問題? – parsifal

+0

我不這麼認爲,即使它超出了我的預期,我也有10個1,5-2mb的文件,但我認爲DOM仍然可行嗎?該代碼將運行在普通的臺式機上,不會做比這更多的事情。 – Robust2

回答

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

檢查XmlCombiner這是一個Java庫,它實現XML合併,並允許添加過濾器,您可以在其中指定合計'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的作者。