使用LINQ读取XML时防止重复元素访问

时间:2011-08-21 19:14:01

标签: c# xml linq linq-to-xml

我有一个XML,我正在尝试使用LINQ to XML解析并将其转换为匿名的对象列表。为此,我想出了以下代码片段:

var res = doc
            .Root
            .Elements("Record")
            .Elements("Term")
            .Select(term => new
            {
                LanguageCode = term.Attribute("languageCode").Value,
                ConceptNumber = Convert.ToInt32(term.Attribute("conceptNumber").Value),
                IsHidden = Convert.ToBoolean(term.Attribute("hidden").Value),
                Label = term.Value,

                InputDate = DateTime.Parse(term.Parent.Element("InputDate").Value),
                LastUpdate = DateTime.Parse(term.Parent.Element("LastUpdated").Value)
            }).ToList();

请注意InputDate& LastUpdate部分。如您所见,我将访问父节点(例如,term.Parent),以便我可以访问这两个元素,这看起来很混乱。有没有办法声明term.Parent一次并反复使用它来提取这些属性?

以下是我正在尝试阅读的XML的摘录:

<Record>
  <Term  languageCode="Prs" conceptNumber="10" hidden="False">Whatever</Term>
  <Status>Approved</Status>
  <Frequency>0</Frequency>
  <InputDate>12/30/1899</InputDate>
  <LastUpdate>10/25/2009</LastUpdate>
</Record>

谢谢

2 个答案:

答案 0 :(得分:6)

您需要使用let clause。它在查询中创建一个新变量,并允许多次使用它。

在你的情况下,它将是

var res = (from term in doc.Root.Elements("Record").Elements("Term")
           let parent = term.Parent
           select new
           {
               LanguageCode = term.Attribute("languageCode").Value,
               ConceptNumber = Convert.ToInt32(term.Attribute("conceptNumber").Value),
               IsHidden = Convert.ToBoolean(term.Attribute("hidden").Value),
               Label = term.Value,
               InputDate = parent.Element("InputDate").Value,
               LastUpdate = parent.Element("LastUpdated").Value
           }).ToList();

请注意,它是一个纯LINQ语法的代码,可以让您比使用问题中的扩展方法更清晰地表达想法。

答案 1 :(得分:1)

您可以在投影中引入一个匿名类(这类似于let在幕后的内容),然后使用SelectMany()使用额外属性展平:

var results = doc.Elements("Record")
                 .Select( x => new 
                  {
                    Terms = x.Elements("Term"),
                    InputDate = DateTime.Parse(x.Element("InputDate").Value),
                    LastUpdate = DateTime.Parse(x.Element("LastUpdate").Value)
                  }) 
                 .SelectMany(x => x.Terms, (record,term) => new
                 {
                    LanguageCode = term.Attribute("languageCode").Value,
                    ..
                    InputDate = record.InputDate,
                    LastUpdate = record.LastUpdate
                 });