【问题标题】:What is the best way to sort xml elements by attribute values in c#/.net 3.5在 c#/.net 3.5 中按属性值对 xml 元素进行排序的最佳方法是什么
【发布时间】:2011-08-01 14:11:17
【问题描述】:

我有一个包含如下数据的 XML 文件:

<Details>
  <TableDef>
    <Column Name="Calldate" HeaderName="Calldate" SourceColumnName="Calldate" IsHidden = "false" Position="4" />
    <Column Name="Issue" HeaderName="Issues" SourceColumnName="Issues" IsHidden = "false" Position="3" />
    <Column Name="ParamortizedValue" HeaderName="paramortizedvalue" SourceColumnName="Value" IsHidden = "false" Position="1" />
    <Column Name="PercentBondTotal" HeaderName="percentbondtotal" SourceColumnName="Percentage" IsHidden = "false" Position="2" />
  </TableDef>
</Details>

我想知道按属性过滤和排序元素的最佳和有效方法是什么,以便我可以在代码中进一步使用排序后的元素?

在上面的例子中,我想按“IsHidden = false”过滤,然后按“Position”属性对元素进行排序。

我有以下代码可以读取所有元素而不进行任何排序:

var doc = XDocument.Load("data.xml");
var nodeTableDefInfo = doc.XPathSelectElements("/Details");
var elements = nodeTableDefInfo.Elements("TableDef").Elements();
foreach (var e in elements)
{
  //want to work on the sorted elements
}

各位,感谢您提供的所有解决方案。在我阅读您的解决方案之前,我想出了这个:

var elements = nodeTableDefInfo.Elements("TableDef").Elements();
var sortedElements = (from element in elements 
                where element.Attribute("IsHidden").Value == "false" 
                orderby element.Attribute("Position").Value ascending 
                select element);
foreach (var e in sortedElements)
{
//work on the sorted elements
}

现在,经过解决方案,我真的很喜欢GFK提供的解决方案和解释。我想我需要对空值进行一些处理。谢谢大家。

【问题讨论】:

    标签: c# xml xelement


    【解决方案1】:

    使用更多的 LINQ!

    var sortedElements =
        from element in elements
        let hiddenAttribute = element.Attribute("IsHidden")
        let positionAttribute = element.Attribute("Position")
        where hiddenAttribute != null
            && positionAttribute != null
            && hiddenAttribute.Value == "false"
       let position = int.Parse(positionAttribute)
       orderby position
       select element;
    
    foreach (var e in sortedElements)
    {
        // ...
    }
    

    编辑:另外,我通常使用 LINQ-to-XML 做的是创建一个匿名类型,这样我就可以一次性将所有属性解析为强类型值(并处理缺失或无效值),例如:

    int parsedInt;
    var sortedElements =
        from element in elements
        let hiddenAttribute = element.Attribute("IsHidden")
        let positionAttribute = element.Attribute("Position")
        // add other attributes here
        select new
            {
                IsHidden = hiddenAttribute == null || hiddenAttribute.Value != "false",
                Position = positionAttribute == null || !int.TryParse(positionAttribute.Value, out parsedInt)
                    ? default(int?)
                    : parsedInt,
                // add other parsed attributes here
            };
    

    这样,所有操作都变得更加容易,例如排序或过滤:

    foreach(var element in sortedElements.Where(e => !e.IsHidden).OrderBy(e => e.Position)
    {
        // ...
    }
    

    【讨论】:

    • 如果您在 let 语句中绑定匿名类型的对象,您还可以过滤您从第二个示例中发出的对象。
    • 是的,这取决于你是否想明确地丢弃它们。
    • 我喜欢这些解决方案和解释。谢谢。
    【解决方案2】:
    var tableDefs = nodeTableDefInfo.Elements("TableDef").Elements();
    foreach(var column in tableDefs.Where(x=>
                                     x.Attributes("IsHidden") != null && 
                                     bool.Parse(x.Attributes("IsHidden").value) == false && 
                                     x.Attributes("Position") != null)
                                   .OrderBy(x=>int.Parse(x.Attributes("Position"))
    

    【讨论】:

      【解决方案3】:

      linq..

      string str = @"
                  <Details>
                      <TableDef>
                          <Column Name='Calldate' HeaderName='Calldate' SourceColumnName='Calldate' IsHidden='false' Position='4' />
                          <Column Name='Issue' HeaderName='Issues' SourceColumnName='Issues' IsHidden='false' Position='3' />
                          <Column Name='ParamortizedValue' HeaderName='paramortizedvalue' SourceColumnName='Value' IsHidden = 'false' Position='1' />
                          <Column Name='PercentBondTotal' HeaderName='percentbondtotal' SourceColumnName='Percentage' IsHidden = 'false' Position='2' />
                      </TableDef>
                  </Details>";
      XDocument xml = XDocument.Parse(str);
      List<XElement> columns = (from t in xml.Descendants("TableDef").Descendants("Column") where (bool)t.Attribute("IsHidden") == false orderby (int)t.Attribute("Position") ascending select t).ToList();
      

      【讨论】:

        【解决方案4】:

        试试 Linq2XML。

        XDocument ip = XDocument.Load(Server.MapPath("~/data.xml"));
        var op = ip.Descendants("Column")
            .Where(node => node.Attribute("IsHidden").Value == "false")
            .OrderBy(node => int.Parse(node.Attribute("Position").Value))
            .ToList();
        

        现在,op 将变为 List&lt;XElement&gt;。使用forforeach 对其进行操作。

        【讨论】:

        • 如果节点缺少 'Position' 或 'IsHidden' 属性,这将引发异常,它将根据 Position 属性的字符串值而不是 int 值排序(即10 会在 2) 之前出现
        【解决方案5】:

        示例方法:

                    var list = new List<KeyValuePair<string, XElement>>();
                    foreach(var element in elements)
                    {
                        list.Add(new KeyValuePair<string,XElement>(
                            element.Attribute("someAttr").Value,
                            element));
                    }
                    var sorted = from entry in list
                                 orderby entry.Value.Attribute("someAttr").Value
                                 select entry;
                    // just test:
                    foreach (var entry in sorted)
                    {
                        Debug.WriteLine(String.Format("attribute value: {0} - element: {1}", entry.Key, entry.Value.ToString()));
                    }
        

        我们正在检索您选择的属性值并将其视为索引。

        我们创建一个字典(准确地说是键值对的列表,因为这些值可能不是唯一的),然后我们只需按键对列表进行排序。

        我假设每个XElement 都会存在此属性 - 如果不是这种情况,您当然需要检查 null。

        【讨论】:

          猜你喜欢
          • 2011-10-13
          • 1970-01-01
          • 2011-11-22
          • 1970-01-01
          • 2010-09-18
          • 2021-08-28
          • 1970-01-01
          • 2013-03-25
          • 1970-01-01
          相关资源
          最近更新 更多