【问题标题】:How can I add ISortedEnumerable<XElement> to XElement?如何将 ISortedEnumerable<XElement> 添加到 XElement?
【发布时间】:2017-05-08 11:13:11
【问题描述】:

我正在尝试使用 Linq 对 XElement 的子项进行排序,然后用 sorted 替换现有的子项。

首先我创建 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: 'Co najmniej jeden obiekt musi implementować element IComparable.'翻译:至少一个对象必须实现 IComparable。

我不明白是什么导致了异常以及如何修复它。

【问题讨论】:

    标签: c# linq linq-to-xml


    【解决方案1】:

    发生错误是因为XElement.Name 的类型为System.Xml.Linq.XNameXName 没有实现 IComparable

    XName 包装了一个System.String 值,它覆盖ToString 以返回该System.String 值。

    由于System.String 实现了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
    

    【讨论】:

      【解决方案2】:

      这是基于 Aluan Haddad 接受的答案的评论。

      建议:考虑使用XName.LocalName 代替XName.ToString()

      直接使用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; }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-27
        • 2019-03-27
        • 2014-08-28
        • 1970-01-01
        • 2015-02-21
        相关资源
        最近更新 更多