基本的LINQ语法

时间:2009-11-06 20:02:57

标签: c# xml linq parent-node

假设您有类似这样的XML:

 <data>
  <messages>
   <message name="Person" id="P">
    <field name="FirstName" required="Y" />
    <field name="LastName" required="Y" />
    <field name="Sex" required="N" />
   </message>
   <message name="Car" id="C">
    <field name="Make" required="Y" />
    <field name="Model" required="Y" />
    <field name="Year" required="N" />
   </message>
  </messages>
 </data>

使用Linq,您如何获得Person的所有必填字段名称列表?

我今天刚刚开始使用LINQ / XML,这就是我所得到的。

    var q = from c in loaded.Descendants("field")
            where (string)c.Attribute("required") == "Y" &&
            // how to check the parent node (message) has an attribute (id="P")           
            select (string)c.Attribute("name");

    foreach (string name in q)
        Console.WriteLine(name);

4 个答案:

答案 0 :(得分:2)

您可以通过执行以下操作来删除单独的foreach循环和丑陋的演员

(from c in myXML.Descendants("field")
         where c.Attribute("required").Value == "Y" && 
         c.Parent.Attribute("id").Value == "P" 
         select c.Attribute("name").Value).ToList().ForEach(s => Console.WriteLine(s.ToString()));

编辑:

由于出现了null或者可选属性的问题,这里是一个如何添加扩展方法来处理null属性的例子,你可以传递一个默认值来使用,如果一个不存在(这是第二个参数)扩展方法)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;

namespace MyTestApp
{

class Program
{
    static void Main(string[] args)
    {
        XDocument myXML = XDocument.Load(@"C:\file.xml"); 

        (from c in myXML.Descendants("field")
         where c.Attribute("required")
               .GetAttributeValueOrDefault("N") == "Y" && 
                c.Parent.Attribute("id").Value == "P"      
         select 
         c.Attribute("name").Value).ToList().ForEach(s => Console.WriteLine(s.ToString()));

        Console.ReadLine();
    }
}

public static class XLinqHelper
{
    // extension method that handles an xattribute and returns the provided default if the Xattrib is null
    public static string GetAttributeValueOrDefault(this XAttribute s, string defaultValue)
    {
        string retVal;
        if (s == null)
            retVal = defaultValue;
        else
            retVal = s.Value;
        return retVal;


    }
}

}

答案 1 :(得分:2)

我为消息添加了一个根元素和结束标记,以使XML有效:

XDocument loaded = XDocument.Parse(@"
  <messages>
    <message name=""Person"" id=""P"">
      <field name=""FirstName"" required=""Y"" />
      <field name=""LastName"" required=""Y"" />
      <field name=""Sex"" required=""N"" />
    </message>
    <message name=""Car"" id=""C"">
      <field name=""Make"" required=""Y"" />
      <field name=""Model"" required=""Y"" />
      <field name=""Year"" required=""N"" />
    </message>
  </messages>");

不要查找所有字段然后检查每个字段的父节点,而是查找您感兴趣的父节点,以便查看较少的字段:

IEnumerable<string> fields =
  loaded.Root.Elements()
  .Where(m => m.Attribute("id").Value == "P")
  .Single()
  .Elements("field")
  .Where(f => f.Attribute("required").Value == "Y")
  .Select(f => f.Attribute("name").Value);

编辑:
如果message元素包含任何其他类型的元素,则为子元素添加说明符“field”。

编辑2:
我将一个工作示例与实际数据的子集放在一起:

XDocument loaded = XDocument.Parse(@"
  <fix major=""4"" minor=""4"">
    <header>
    </header>
    <trailer>
    </trailer>
    <messages>
      <message name=""ResendRequest"" msgtype=""2"" msgcat=""admin"">
        <field name=""BeginSeqNo"" required=""Y"" />
        <field name=""EndSeqNo"" required=""Y"" />
      </message>
      <message name=""Reject"" msgtype=""3"" msgcat=""admin"">
        <field name=""RefSeqNum"" required=""Y"" />
        <field name=""RefTagID"" required=""N"" />
        <field name=""RefMsgType"" required=""N"" />
        <field name=""SessionRejectReason"" required=""N"" />
        <field name=""Text"" required=""N"" />
        <field name=""EncodedTextLen"" required=""N"" />
        <field name=""EncodedText"" required=""N"" />
      </message>
    </messages>
  </fix>");

IEnumerable<string> fields =
  loaded.Root.Element("messages").Elements("message")
  .Where(m => m.Attribute("name").Value == "Reject")
  .Single()
  .Elements("field")
  .Where(f => f.Attribute("required").Value == "Y")
  .Select(f=>f.Attribute("name").Value);

答案 2 :(得分:1)

您使用System.Xml.Linq.XNodeSystem.Xml.Linq.XObject

定义的Ancestors()方法或Parent属性

答案 3 :(得分:1)

考虑到提问者改变了他的xml,这个答案是完全错误的。我应该删除它。

var q = from c in loaded.Descendants("field")
            where (string)c.Attribute("required") == "Y" &&
                    c.Parent.Attribute("id").Value == "P"
            select (string)c.Attribute("name");

添加我使用的Xml,因为对正确的解决方案存在一些困惑。

XDocument loaded = XDocument.Parse(@"
<message name=""Person"" id=""P"">
    <field name=""FirstName"" required=""Y"" /> 
    <field name=""LastName"" required=""Y"" />
    <field name=""Sex"" required=""N"" />
    <message name=""Car"" id=""C"">
        <field name=""Make"" required=""Y"" />
        <field name=""Model"" required=""Y"" />
        <field name=""Year"" required=""N"" />
    </message>
</message>");