2017-05-08 58 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; } 
} 
相关问题