使用Linq到XML将分层XML文件展平

时间:2014-07-14 18:15:48

标签: c# xml linq

我目前有以下C#与Linq到XML代码有效,但我希望有更好的方法来形成Linq查询,然后才能将结果提取到平面结构中。

以下是我希望它们显示的当前结果格式:

7990697: result_status = Complete
7990756: result_status = Incomplete

我希望能够使用语法result.resultStatusId而不是result.meta.ToList()[0] .resultStatusId

来访问结果
    var xDoc = XDocument.Parse(@"<fs_response status='success' timestamp='2014-07-10 14:38:39'>
<headings>
<heading for='result_status'>Result Status</heading>
<heading for='1'>First Name</heading>
<heading for='2'>Last Name</heading>
</headings>
<results>
<result id='7990697'>
<metas>
<meta id='result_status'>Complete</meta>
</metas>
<items>
<item id='1' index='3' type='text'>
<value>Bugs</value>
</item>
<item id='2' index='4' type='text'>
<value>Bunny</value>
</item>
</items>
</result>
<result id='7990756'>
<metas>
<meta id='result_status'>Incomplete</meta>
</metas>
<items>
<item id='1' index='3' type='text'>
<value>Yogi</value>
</item>
<item id='2' index='4' type='text'>
<value>Bear</value>
</item>
</items>
</result>
</results>
<total_results>2</total_results>
</fs_response>");

    var results =
    from x in xDoc.Elements("fs_response").Elements("results").Elements("result")
    select new
    {
        id = x.Attribute("id").Value,
        meta = from m in x.Elements("metas").Elements("meta")
               where m.Attribute("id").Value == "result_status"
               select new
               {
                   resultStatusId = m.Attribute("id").Value,
                   resultStatus = m.Value
               }
    };

    results.Dump();

    foreach (var result in results.ToList())
    {
        Console.WriteLine("{0}: {1} = {2}", 
            result.id, 
            result.meta.ToList()[0].resultStatusId, 
            result.meta.ToList()[0].resultStatus);
        //Console.WriteLine("{0}: {1} = {2}", 
        //    result.id, 
        //    result.resultStatusId, 
        //    result.resultStatus);
    }

2 个答案:

答案 0 :(得分:0)

我会将查询更改为以下内容:

var results = xDoc.Element("fs_response")
                  .Element("results")
                  .Elements("result")
                  .Select (e => new
                  {
                      id = e.Attribute("id").Value,
                      meta = e.Element("metas")
                              .Elements("meta")
                              .Where (m =>
                                  m.Attribute("id").Value == "result_status")
                              .Select (m => new
                              {
                                  resultStatusId = m.Attribute("id").Value,
                                  resultStatus = m.Value
                              })
                              .Single()
                  });

一些注意事项:

  • 请注意从ElementsElement的几个位置的更改。这表示您知道只有一个具有该名称的结果,或者您只希望第一个具有该名称。当您期望多个结果时,请使用Elements。在上面的示例中的某些情况下,我正在假设您的xml架构(例如每个结果只有一个metas元素的事实)。这可能会更快,因为一旦找到特定名称的元素,就不必继续搜索它们。
  • 另见Single()的使用。这表示您期望一个一个元素id属性等于result_status。如果您期望0或1,则可以使用SingleOrDefault(),或者如果您想要匹配元素的潜在列表中的第一个,则可以使用First()FirstOrDefault()。添加后,您将不再需要在结果中调用ToList()[0]
Console.WriteLine("{0}: {1} = {2}", 
    result.id, 
    result.meta.resultStatusId, 
    result.meta.resultStatus);

答案 1 :(得分:0)

    var results =
        from x in xDoc.Elements("fs_response").Elements("results").Elements("result")
        from m in x.Elements("metas").Elements("meta")
        where m.Attribute("id").Value == "result_status"
        select new
        {
        id = x.Attribute("id").Value,
        resultStatusId = m.Attribute("id").Value,
        resultStatus = m.Value,
        };

    foreach (var result in results.ToList())
    {
        Console.WriteLine("{0}: {1} = {2}", result.id, result.resultStatusId, result.resultStatus);
    }