使用LINQ by属性检索多个XML元素

时间:2011-03-28 15:37:13

标签: c# linq-to-xml

鉴于此XML:

<?xml version="1.0" encoding="utf-8" ?>
<queryableData>
  <table displayName="Shipments" dbName="Quotes">
    <foreignKey column="CustomerId" references="CustomerRegistration"/>
    <foreignKey column="QuoteStatusId" references="QuoteStatus"/>
    <fields>
      <field displayName="Quote Charge" dbColumn="QuoteCharge" type="Number"/>
      <field displayName="Total Weight" dbColumn="TotalWeight" type="Number"/>
    </fields>
  </table>
  <table displayName="Customers" dbName="CustomerRegistration">
    <fields>
      <field displayName="First Name" dbColumn="FirstName" type="Text" />
      <field displayName="Last Name" dbColumn="LastName" type="Text"/>
    </fields>
  </table>
</queryableData>

我想获取一个匿名对象类型列表,其中仅包含“Quotes”表的DisplayName,DbColumn和Type字段。

我能够使用以下LINQ to XML代码获取两个表的列表:

    var xml = XElement.Load(@"C:\Sandbox\queryable.xml");

    // Tables
    var tables = from el in xml.Elements("table")
                        select new 
                        {
                            Text = el.Attribute("displayName").Value,
                            Value = el.Attribute("dbName").Value
                        };

但我不知道如何获取表元素的dbName属性为“Quotes”的字段值。我得到的最接近的是一个包含值列表的列表,而不是一个匿名对象列表,其中一个项目具有dbColumn / displayName对:

var columns = from el in xml.Elements("table")
            where el.Attribute("dbName").Value.Equals("Quotes")
            select new LookupData { 
                Text = el.Elements("fields").Elements("field").Attributes().Where(x => x.Name == "displayName").Select(x => x.Value),
                Value = el.Elements("fields").Elements("field").Attributes().Where(x => x.Name == "dbColumn").Select(x => x.Value)
            };

所以我希望这在列表中:

LookupData#1

文字:“报价费”

价值:“QuoteCharge”

LookupData#2

文字:“总重量”

价值:“TotalWeight”

而我正在接受这个:

LookupData#1

文字:包含两个字符串的列表:[0] =“报价费用”,[1] =“总重量”

值:包含两个字符串的列表:[0] =“QuoteCharge”,[1] =“TotalWeight”

1 个答案:

答案 0 :(得分:1)

使用它:

var result = xml.Elements("table").
    Where(el => el.Attribute("dbName").Value.Equals("Quotes")). // 1
    SelectMany(el => el.Elements("fields").Elements("field")).  // 2
    Select(f => new 
                {
                    Text = f.Attributes().Where(x => x.Name == "displayName").
                        Select(x => x.Value).FirstOrDefault(),
                    Value = f.Attributes().Where(x => x.Name == "dbColumn").
                        Select(x => x.Value).FirstOrDefault()
                }
           ) // 3
;

说明:

  1. 我们选择dbName == "Quotes"
  2. 的元素
  3. 在这些元素的每个元素中,我们选择所有field元素并使用SelectMany展平结果。结果将是IEnumerable<XElement>
  4. 对于每个字段,我们选择一个匿名类型,其中Text属性设置为名为“displayName”的第一个属性的值,Value属性设置为名为“dbColumn”的第一个属性的值“
  5. 您的方法的问题基本上是,您将步骤2放在匿名类型的创建中。或换句话说:您为每个“Quotes”元素创建了一个匿名类型实例,而不是每个“field”元素。