2017-05-08 59 views
2

我想排序XElement的孩子使用Linq,然後用排序替換現有的孩子。如何將ISortedEnumerable <XElement>添加到XElement?

首先我創建的XElement:

XElement WithLinq = 
      new XElement("Names", 
       from cust in Customers.AsEnumerable() 
       select 
        new XElement("Customer", 
         new XAttribute("ID", cust.ID), 
         new XElement("Name", cust.Name), 
         new XElement("Purchases", 
         from pur in cust.Purchases 
         select 
          new XElement("Purchase", 
           new XElement("Produkt",pur.Description), 
           new XAttribute("ID",pur.ID), 
           new XElement("Price",pur.Price), 
           new XComment("teraz daty"), 
           new XElement("Date",pur.Date), //Formatuje DateTime zgodnie z normami XMLa 
           new XElement("DataAleNieDoKonca",pur.Date.ToString(CultureInfo.InvariantCulture)))))  
         ); 

接着我節點:

var NowaKolejnosc = WithLinq.Elements().Last().Elements().OrderBy(n => n.Name).ThenBy(n => n.Value); 

並進行更換:

WithLinq.Elements().Last().ReplaceNodes(NowaKolejnosc); 

但我得到一個運行時異常:ArgumentException的:「合作najmniej jeden obiekt musiimplementsowaćelement IComparable。'翻譯:至少有一個對象必須實現IComparable。

我不明白是什麼導致異常,以及如何解決它。

回答

2

發生此錯誤的原因是XElement.Name的類型爲System.Xml.Linq.XNameXName不執行IComparable

XName包裝System.String值,它會覆蓋ToString以返回System.String值。

由於System.String implements IComparable我們可以利用這些知識正確成功地調用OrderBy。這具有所需的語義,因爲從邏輯上講,我們想要比較包裝的字符串。

WithLinq.Elements().Last().Elements().OrderBy(n => n.Name.ToString()).ThenBy(n => n.Value) 

當使用多個排序的LINQ操作符時,我發現使用查詢表達式語法更具可讀性。

from element in WithLinq.Elements().Last().Elements() 
orderby element.Name.ToString(), element.Value 
select element 
1

這是建立在Aluan Haddad公認的答案基礎上的評論。

建議:考慮代替XName.ToString()使用XName.LocalName

直接與element.Name.LocalName物業工作可能是合適的,只要該XML不使用名稱空間是不需要在XML命名空間用於特定的操作。

處理大型(> 1GB)XML文件時,我發現通過將XName.ToString()替換爲XName.LocalName可以獲得適度的性能提升。

雖然有趣的是,這種改變在需要重複分類和比較的1小時長的程序中保存了大約6分鐘。在其他情況下,YMMV。

對於某些方面,這裏通過the reference source有區別:

/// <summary> 
/// Returns the expanded XML name in the format: {namespaceName}localName. 
/// </summary> 
public override string ToString() { 
    if (ns.NamespaceName.Length == 0) return localName; 
    return "{" + ns.NamespaceName + "}" + localName; 
} 
/// <summary> 
/// Gets the local (unqualified) part of the name. 
/// </summary> 
/// <seealso cref="XName.Namespace"/> 
public string LocalName { 
    get { return localName; } 
} 
相關問題