2011-10-11 92 views
12

我遇到的有關合並XML文檔的所有解決方案都無法實現我的願望。讓我來解釋:合併XML文檔

XML文檔1:

<?xml version="1.0" encoding="utf-8" ?> 
<a> 
    <b title="Original Section"> 
     <b title="Original Child Section"></b> 
     <b title="Original Child Section 2"></b> 
    </b> 
</a> 

XML文檔2:

<?xml version="1.0" encoding="utf-8" ?> 
<a> 
    <b title="New Section"> 
     <b title="New Child Section"></b> 
    </b> 
    <b title="Original Section"> 
     <b title="Original Child Section"> 
      <b title="New Child For Old Section"></b> 
     </b> 
    </b>  
</a> 

到最終的文檔是這樣的:

<?xml version="1.0" encoding="utf-8" ?> 
<a> 
    <b title="Original Section"> 
     <b title="Original Child Section"> 
      <b title="New Child For Old Section"></b> 
     </b> 
     <b title="Original Child Section 2"></b> 
    </b>  
    <b title="New Section"> 
     <b title="New Child Section"></b> 
    </b> 
</a> 

的文件在內容上相似,但可以有任意數量的子節點。我也想消除重複。我認爲重複項是具有相同屬性的元素(基於屬性名稱和值)。有沒有人看過這個實現的一個工作示例?我可以設想如何使用一些循環和一些遞歸來編寫它,但對我來說,這似乎並不是完成我想要的最佳方式:)

歡呼聲,並提前致謝!

* 編輯 *

因爲共識是循環和遞歸是必須的,這將是完成這一任務的最優雅,最有效的方法?我想這個問題的另一個基本問題是在迭代時比較節點的最佳方法是什麼?

+2

我爲客戶實現了這樣的東西。它基本上按照你實現它的方式工作:使用循環和遞歸。 –

+2

+1代表很好的例子 –

+0

我同意@DanielHilgarth。循環和遞歸基本上是實現這一點的最簡單方法。 – Kian

回答

1

最終,這個問題的任何解決方案都會歸結爲循環和/或遞歸。您正在談論基本集合論,linq可能對提煉流程很有用,但它最終將對這兩個集合進行迭代併合並結果。

+0

這就是我的想法。那麼我想我應該修改我的問題以尋求這個問題的最優雅和最有效的解決方案。 – nokturnal

1

我會寫一個IEqualityComparer,指定兩個節點何時「匹配」 - 即設置標題匹配規則。

class XElementComparer : IEqualityComparer<XElement> 
{ 
    public bool Equals(XElement x, XElement y) 
    { 
     var xTitle = x.Attribute("title"); 
     var yTitle = y.Attribute("title"); 

     if (xTitle == null || yTitle == null) return false; 

     return xTitle.Value == yTitle.Value; 
    } 

    public int GetHashCode(XElement obj) 
    { 
     return base.GetHashCode(); 
    } 
} 

然後編寫一個遞歸的方法來拖拉你的XML,合併根據比較器匹配的節點。

private XElement Merge(XElement node1, XElement node2) 
{ 
    // trivial cases 
    if (node1 == null) return node2; 
    if (node2 == null) return node1; 

    var elements1 = node1.Elements(); 
    var elements2 = node2.Elements(); 

    // create a merged root 
    var result = new XElement(node1.Name, node1.Attribute("title")); 

    var comparer = new XElementComparer(); 
    var mergedNodes = elements1.Union(elements2, comparer).ToList(); 

    // for the union of the elements, insert their merge values 
    foreach (var title in mergedNodes) 
    { 
     var child1 = elements1.SingleOrDefault(e => comparer.Equals(e, title)); 
     var child2 = elements2.SingleOrDefault(e => comparer.Equals(e, title)); 

     result.Add(Merge(child1, child2)); 
    } 

    return result; 
} 
+0

我知道變量名是有點naff,我應該正確實施'GetHashCode',但基本知識在那裏。 –

+0

這看起來很有前途。這正是我如何處理這個問題,但更聰明:)讓我把它搞砸,看看我能想出什麼 – nokturnal