【问题标题】:Linq to XML: create an anonymous object with element attributes and valuesLinq to XML:创建具有元素属性和值的匿名对象
【发布时间】:2010-05-17 09:35:21
【问题描述】:

我是 Linq 的新手,我正在尝试查询 XML 文档以查找特定用户的客户经理列表。 (我意识到将它放在数据库或其他东西中可能更有意义,但这种情况需要 XML 文档)。

<user emailAddress='user@fabrikam.com'>
    <accountManager department='Customer Service' title='Manager'>manager@fabrikam.com</accountManager>
    <accountManager department='Sales' title='Account Manager'>manager@fabrikam.com</accountManager>
    <accountManager department='Sales' title='Account Manager'>manager@fabrikam.com</accountManager>
</user>

我试图创建一个对象列表(匿名类型?),其属性由 XElement 属性(部门、标题)和值(电子邮件)组成。我知道我可以得到两者中的任何一个,但我的问题是同时选择两者。

这是我正在尝试的:

var managers = _xDoc.Root.Descendants("user")
               .Where(d => d.Attribute("emailAddress").Value == "user@fabrikam.com")
               .SelectMany(u => u.Descendants("accountManager").Select(a => a.Value));

foreach (var manager in managers)
{
     //do stuff
}

我可以访问a.Valuea.Attribute,但我不知道如何同时将它们存储在一个对象中。我有一种感觉,它最终会看起来像:

select new { 
    department = u.Attribute("department").Value,
    title = u.Attribute("title").Value,
    email = u.Value
};

【问题讨论】:

    标签: c# .net linq


    【解决方案1】:

    你是对的。它看起来就像那样。

    例如:

    _xDoc.Root.Descendants("user")
              .Where(d => d.Attribute("emailAddress").Value == "user@fabrikam.com")
              .SelectMany(u => u.Descendants("accountManager"))
              .Select(a => new { 
                  department = a.Attribute("department").Value,
                  title = a.Attribute("title").Value,
                  email = a.Value
              });
    

    编辑:使用查询理解语法:

    from u in _xDoc.Root.Descendants("user")
    where u.Attribute("emailAddress").Value == "user@fabrikam.com"
    from a in u.Descendants("accountManager")
    select new { 
                   department = a.Attribute("department").Value,
                   title = a.Attribute("title").Value,
                   email = a.Value
               });
    

    【讨论】:

      【解决方案2】:

      我假设只有一个用户使用sipAddress == sipUri

      让我们从这个开始:

      var managers = _xDoc.Root
      

      您可以使用 .First 仅选择第一个匹配的元素

      .First(d => d.Attribute("sipAddress").Value == sipUri)
      

      这将获取谓词返回 true 的第一个用户。然后,您需要将元素中的属性和值都提取到一个新对象(匿名类型)中。

      如果有很多用户并且您想要所有列出的经理,这可以通过使用.SelectMany 来完成(即对于每个用户,有很多经理,选择所有)但在这种情况下,我假设只有一个,.First 已经返回了那个元素,所以你可以使用它的属性来访问管理器列表

      .Descendants("accountManager")
      

      然后你会得到所有XElement 从被选元素降序。使用元素中的值将其转换为另一个对象是通过使用映射函数完成的,在 Linq 中是 .Select

      .Select(managerElem => new {
          department = u.Attribute("department").Value,
          title = u.Attribute("title").Value,
          email = u.Value 
      });
      

      正如我之前所说,如果有多个用户使用正确的sipAddress,并且您希望所有管理员,只需将.Descendants 包裹在.SelectMany 内。

      .SelectMany(userElem => userElem.Descendants("accountManager"))
      

      我还没有测试过代码,但我相信你可以按照我写的来弄清楚。

      希望这会有所帮助! :) 如果您仍然感到困惑,请随时在 cmets 中提问。

      【讨论】:

      • 感谢详细的解释,帮助很大。我还在学习。
      【解决方案3】:

      如果你想从Select 方法返回匿名类型,你可以这样写:

      var managers = 
        _xDoc.Root.Descendants("user") 
             .Where(d => d.Attribute("emailAddress").Value == "user@fabrikam.com") 
             .SelectMany(u => 
                u.Descendants("accountManager")
                 .Select(a => new {  
                    Department = u.Attribute("department").Value, 
                    Title = u.Attribute("title").Value, 
                    Email = u.Value })
              );
      

      创建匿名类型的语法不直接绑定到select 关键字。例如,您可以像这样使用它:

      var manager = new { Department = "Somewhere", Title = "Mr" };
      

      所以,a =&gt; new { ... } 语法是一个返回新匿名类型的 lambda 表达式,就像 select new { ... } 是构造新匿名类型的子句一样。

      关于点表示法和查询语法之间的选择 - 这确实是个人喜好(尽管有些事情看起来更好用查询语法和一些方法,如 Count 只能使用点表示法)。但是,所有查询都被编译器转换为方法调用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-14
        相关资源
        最近更新 更多