【问题标题】:LINQ to XML Newbie Question: Returning More Than One ResultLINQ to XML 新手问题:返回多个结果
【发布时间】:2008-09-24 13:51:29
【问题描述】:

您好!

我正在研究 LINQ。如果我将诸如此类的一些 XML 加载到 XDocument 对象中:

<Root>
    <GroupA>
        <Item attrib1="aaa" attrib2="000" attrib3="true" />
    </GroupA>
    <GroupB>
        <Item attrib1="bbb" attrib2="111" attrib3="true" />
        <Item attrib1="ccc" attrib2="222" attrib3="false" />
        <Item attrib1="ddd" attrib2="333" attrib3="true" />
    </GroupB>
    <GroupC>
        <Item attrib1="eee" attrib2="444" attrib3="true" />
        <Item attrib1="fff" attrib2="555" attrib3="true" />
    </GroupC>
</Root>

我想获取 Group 元素的所有 Item 子元素的属性值。这是我的查询的样子:

var results = from thegroup in l_theDoc.Elements("Root").Elements(groupName)
              select new
              { 
                 attrib1_val = thegroup.Element("Item").Attribute("attrib1").Value,      
                 attrib2_val = thegroup.Element("Item").Attribute("attrib2").Value,
              };

查询有效,但如果 groupName 变量包含“GroupB”,则只返回一个结果(第一个 Item 元素)而不是三个。我错过了什么吗?

【问题讨论】:

    标签: c# linq-to-xml


    【解决方案1】:
    XElement e = XElement.Parse(testStr);
    
    string groupName = "GroupB";
    var items = from g in e.Elements(groupName)
                from i in g.Elements("Item")
                select new {
                               attr1 = (string)i.Attribute("attrib1"),
                               attr2 = (string)i.Attribute("attrib2")
                           };
    
    foreach (var item in items)
    {
        Console.WriteLine(item.attr1 + ":" + item.attr2);
    }
    

    【讨论】:

      【解决方案2】:

      是的,.Element() 只返回第一个匹配的元素。你想要 .Elements() 并且你需要重新编写你的查询:

      var results = from group in l_theDoc.Root.Elements(groupName)
                    select new
                    {
                        items = from i in group.Elements("Item")
                                select new 
                                {
                                    attrib1_val = i.Attribute("attrib1").Value,
                                    attrib2_val = i.Attribute("attrib2").Value
                                }
                    };
      

      【讨论】:

      • 总体思路是对的,但至少有2个语法错误和2个不必要的操作:)
      • 是的,你不能使用 group 作为变量名,因为它是一个 linq 关键字。
      • 1) 组 - 保留 kw。 2) l_theDoc.Root - 没有这样的东西 3) 不需要将项目包装在单独的对象中 4) .Value 可以安全地省略
      【解决方案3】:

      答案的查询方法形式如下:

      var items = 
        e.Elements("GroupB")
          .SelectMany(g => g.Elements("Item"))
          .Select(i => new {
            attr1 = i.Attribute("attrib1").Value,
            attr2 = i.Attribute("attrib2").Value,
            attr3 = i.Attribute("attrib3").Value
          } )
          .ToList()
      

      【讨论】:

      • 与其他方法不同,这个方法注定会抛出 NullReferenceException :)
      • 考虑到编译器会将您的答案翻译成这个,NullReferenceException 呢?
      • 大卫,我很抱歉。我误认为 Select with First 的行为(最后一个可以抛出异常)只有你的代码可能失败的地方 - 值属性。如果缺少属性 Value 属性将导致异常。编译器还将代码转换为略有不同(但等效)的表示
      【解决方案4】:

      另一种可能性是使用 where 子句:

      var groupName = "GroupB";
      var results = from theitem in doc.Descendants("Item")
                    where theitem.Parent.Name == groupName
                    select new 
                    { 
                        attrib1_val = theitem.Attribute("attrib1").Value,
                        attrib2_val = theitem.Attribute("attrib2").Value, 
                    };
      

      【讨论】:

      • 相当反常的逻辑 IMO。通常是从父节点遍历到子节点的 XML 树
      • 一切都取决于你的孩子是否比父母多;)——只要确保所有的可能性都显示出来。
      • 是的,这有点原始的解决方案:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      相关资源
      最近更新 更多