【问题标题】:Querying XML attributes using LINQ使用 LINQ 查询 XML 属性
【发布时间】:2015-09-23 07:53:59
【问题描述】:

我的应用程序设置在一个简单的 XML 文档中,如下所示:

<Settings>
    <Server>
        <Id>1</Id>
        <Name>SRV123456</Name> 
        <Par Type="Desktop" Region="Western">12</Par>
        <Par Type="Laptop" Region="Western">15</Par>
        <Par Type="Desktop" Region="Eastern">22</Par>
        <Par Type="Laptop" Region="Eastern">25</Par>
        <State>WA</State>
    </Server>
</Settings>

我正在尝试使用 C# 和 LINQ 查询它,使用以下代码:

xelement = XElement.Load(startpath + "\\Settings.xml");
var sn = from sl in xelement.Elements("Server")
       where (string)sl.Element("State") == "WA"
       where (string)sl.Element("Par").Attribute("Region") == "Western"
       where (string)sl.Element("Par").Attribute("Type") == "Desktop"
       select sl;

       foreach (XElement xele in sn)
       {
               Console.WriteLine(xele);
               Console.WriteLine(xele.Element("Par").Value);
       }

这适用于第一个“Par”值,并将返回“12”。但是如果我改变了

   where (string)sl.Element("Par").Attribute("Type") == "Desktop"

   where (string)sl.Element("Par").Attribute("Type") == "Laptop"

它没有返回任何结果...我错过了什么?

【问题讨论】:

  • 尝试混合两种查询方式真的很难看。坚持任何一个(最好 - 代码版本)
  • Element 返回文档顺序中的第一个元素。该元素上的属性将被检查。
  • 没有理由一个会工作而另一个不会。仔细检查你的拼写和大写/小写字母。
  • @jdweng - 一个可以工作而另一个不能工作是有原因的。它与 Element (vs Elements) 和文档中 &lt;Par&gt; 元素的顺序有关。如果&lt;Par Type="Laptop" Region="Western"&gt;15&lt;/Par&gt; 是文档中名为“Par”的第一个元素,那么第二行可以工作(而第一行不行)
  • @Tim - 你应该这样回答。我会赞成。

标签: c# xml linq


【解决方案1】:

这是一个有效且看起来更漂亮的查询:

var parValue = xdoc.Descendants("Par")
    .Where(par=>par.Parent.Element("State")?.Value == "WA")
    .Where(par=>par.Attribute("Region")?.Value == "Western")
    .Where(par=>par.Attribute("Type")?.Value == "Laptop")
    .Select(par=>par.Value)
    .FirstOrDefault();

注意 ?.是 CS6 功能,如果使用 CS5,只需省略 ?,如果需要,请检查 null

【讨论】:

  • 你也可以在 C# 的早期版本中使用.Where(par =&gt; (string)par.Attribute("Region") == "Western")。如果未找到该属性,则显式转换为 string 将安全地返回 null。
  • 效果很好——我刚刚删除了?,它每次都返回结果。我希望我今天早上发布了这个问题......谢谢!
  • @BigfootNick 肯定会按照 Tim 的评论进行明确的演员阵容以避免 NRE
【解决方案2】:

我绝不是 LINQ 专家

然而

    var sn = from sl in xelement.Elements("Server")
           where (string)sl.Element("State") == "WA"
           where (string)sl.Element("Par").Attribute("Region") == "Western"
           where (string)sl.Element("Par").Attribute("Type") == "Desktop"
           select sl;

我相信只返回 Attribute("Type") == "Desktop" 的元素 意味着只返回等于“桌面”的那些......所以当你循环时,你的结果集中没有

改成

    var sn = from sl in xelement.Elements("Server")
             where (string)sl.Element("State") == "WA"
             where (string)sl.Element("Par").Attribute("Region") == "Western"
              select sl;

它应该返回所有类型......不仅仅是“桌面”

【讨论】:

    【解决方案3】:

    也许您正试图返回 Western/Laptop 值 = 15?

    var state  = "WA";
    var region = "Western";
    var type   = "Laptop";
    var xElement = XElement.Parse(@"<Settings>
        <Server>
            <Id>1</Id>
            <Name>SRV123456</Name> 
            <Par Type='Desktop' Region='Western'>12</Par>
            <Par Type='Laptop' Region='Western'>15</Par>
            <Par Type='Desktop' Region='Eastern'>22</Par>
            <Par Type='Laptop' Region='Eastern'>25</Par>
            <State>WA</State>
        </Server>
    </Settings>");
    
    foreach (XElement server in xElement.XPathSelectElements(
                String.Format("//Server[State='{0}']", state)))
    {
        Console.WriteLine(server);
    
        // In your sample the Western/Desktop is the first element
        // If you want a specific Par element, you should query again with that filter
        foreach (XElement par in server.XPathSelectElements(
                    String.Format("Par[@Region='{0}' and @Type='{1}']", region, type)))
            Console.WriteLine(par.Value); ;
    }
    

    我选择 XPath 而不是 Linq 来过滤 XML 文档,因为 XPath 对我来说似乎更简洁。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多