LINQ读取XML

212

我正在使用这个XML文件:

<root>
    <level1 name="A">
        <level2 name="A1" />
        <level2 name="A2" />
    </level1>
    <level1 name="B">
        <level2 name="B1" />
        <level2 name="B2" />
    </level1>
    <level1 name="C" />
</root>

有人能给我一个使用LINQ的C#代码,最简单的方法打印这个结果吗:
(请注意如果是level2节点,则会有额外的空格)

A
  A1
  A2
B
  B1
  B2
C

目前我已经编写了以下代码:

XDocument xdoc = XDocument.Load("data.xml"));
var lv1s = from lv1 in xdoc.Descendants("level1")
           select lv1.Attribute("name").Value;

foreach (var lv1 in lv1s)
{
    result.AppendLine(lv1);
    var lv2s = from lv2 in xdoc...???
}

14
以下是需要翻译的内容:Here is nice example of what u need: C# Load XML using XLINQ (LINQ to XML) - user1521684
6个回答

236

试一下这个。

using System.Xml.Linq;

void Main()
{
    StringBuilder result = new StringBuilder();

    //Load xml
    XDocument xdoc = XDocument.Load("data.xml");

    //Run query
    var lv1s = from lv1 in xdoc.Descendants("level1")
               select new { 
                   Header = lv1.Attribute("name").Value,
                   Children = lv1.Descendants("level2")
               };

    //Loop through results
    foreach (var lv1 in lv1s){
            result.AppendLine(lv1.Header);
            foreach(var lv2 in lv1.Children)
                 result.AppendLine("     " + lv2.Attribute("name").Value);
    }

    Console.WriteLine(result);
}

3
@bendewey 我问了一个类似的问题,你能否帮忙查看一下,链接在这里:https://dev59.com/HWrWa4cB1Zd3GeqP_oGz - Saeid
3
这就像用航空母舰去钓鱼。 - TomeeNS

54

或者,如果你想要一个更通用的方法——也就是嵌套到“levelN”:

void Main()
{
    XElement rootElement = XElement.Load(@"c:\events\test.xml");

    Console.WriteLine(GetOutline(0, rootElement));  
}

private string GetOutline(int indentLevel, XElement element)
{
    StringBuilder result = new StringBuilder();

    if (element.Attribute("name") != null)
    {
        result = result.AppendLine(new string(' ', indentLevel * 2) + element.Attribute("name").Value);
    }

    foreach (XElement childElement in element.Elements())
    {
        result.Append(GetOutline(indentLevel + 1, childElement));
    }

    return result.ToString();
}

23

使用几个普通的 foreach 循环可以提供一个清晰的解决方案:

foreach (XElement level1Element in XElement.Load("data.xml").Elements("level1"))
{
    result.AppendLine(level1Element.Attribute("name").Value);

    foreach (XElement level2Element in level1Element.Elements("level2"))
    {
        result.AppendLine("  " + level2Element.Attribute("name").Value);
    }
}

19

以下是一些完整的工作示例,基于@bendewey和@dommer的示例进行改进。 我需要对每个示例进行微调才能使其正常工作,但是如果还有另一个LINQ新手正在寻找工作示例,这里有一些:

//bendewey's example using data.xml from OP
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

class loadXMLToLINQ1
{
    static void Main( )
    {
        //Load xml
        XDocument xdoc = XDocument.Load(@"c:\\data.xml"); //you'll have to edit your path

        //Run query
        var lv1s = from lv1 in xdoc.Descendants("level1")
           select new 
           { 
               Header = lv1.Attribute("name").Value,
               Children = lv1.Descendants("level2")
            };

        StringBuilder result = new StringBuilder(); //had to add this to make the result work
        //Loop through results
        foreach (var lv1 in lv1s)
        {
            result.AppendLine("  " + lv1.Header);
            foreach(var lv2 in lv1.Children)
            result.AppendLine("    " + lv2.Attribute("name").Value);
        }
        Console.WriteLine(result.ToString()); //added this so you could see the output on the console
    }
}

接下来:

//Dommer's example, using data.xml from OP
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

class loadXMLToLINQ
{
static void Main( )
    {
        XElement rootElement = XElement.Load(@"c:\\data.xml"); //you'll have to edit your path
        Console.WriteLine(GetOutline(0, rootElement));  
    }

static private string GetOutline(int indentLevel, XElement element)
    {
        StringBuilder result = new StringBuilder();
        if (element.Attribute("name") != null)
        {
            result = result.AppendLine(new string(' ', indentLevel * 2) + element.Attribute("name").Value);
        }
        foreach (XElement childElement in element.Elements())
        {
            result.Append(GetOutline(indentLevel + 1, childElement));
        }
        return result.ToString();
    }
}

这两个代码在使用版本为4.0.30319.1的csc.exe编译并在VS2010中运行正常,并输出完全相同的结果。希望这些示例能帮助需要有效代码的人。

编辑:由于@eglasius的示例对我很有用,因此也添加到了其中。

//@eglasius example, still using data.xml from OP
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

class loadXMLToLINQ2
{
    static void Main( )
    {
        StringBuilder result = new StringBuilder(); //needed for result below
        XDocument xdoc = XDocument.Load(@"c:\\deg\\data.xml"); //you'll have to edit your path
        var lv1s = xdoc.Root.Descendants("level1"); 
        var lvs = lv1s.SelectMany(l=>
             new string[]{ l.Attribute("name").Value }
             .Union(
                 l.Descendants("level2")
                 .Select(l2=>"   " + l2.Attribute("name").Value)
              )
            );
        foreach (var lv in lvs)
        {
           result.AppendLine(lv);
        }
        Console.WriteLine(result);//added this so you could see the result
    }
}

7
XDocument xdoc = XDocument.Load("data.xml");
var lv1s = xdoc.Root.Descendants("level1"); 
var lvs = lv1s.SelectMany(l=>
     new string[]{ l.Attribute("name").Value }
     .Union(
         l.Descendants("level2")
         .Select(l2=>"   " + l2.Attribute("name").Value)
      )
    );
foreach (var lv in lvs)
{
   result.AppendLine(lv);
}

须注意,在这些版本中,您必须使用.Root。


这会在所有level1之后打印出所有的level2吗? - sblom
@sblom 哎呀,没错,我更新了我本来想发布的内容(对它进行了测试,所以我现在确定它可以工作:)) - eglasius

0

异步加载XML文件可以提高性能,特别是当文件很大或者加载时间很长的时候。在这个例子中,我们使用XDocument.LoadAsync方法来异步加载和解析XML文件,这有助于防止应用程序在加载文件时变得无响应。

示例:https://dotnetfiddle.net/PGFE7c (使用XML字符串解析)

实现:

XDocument doc;

// Open the XML file using File.OpenRead and pass the stream to 
// XDocument.LoadAsync to load and parse the XML asynchronously
using (var stream = File.OpenRead("data.xml"))
{
    doc = await XDocument.LoadAsync(stream, LoadOptions.None, CancellationToken.None);
}

// Select the level1 elements from the document and create an anonymous object for each element
// with a Name property containing the value of the "name" attribute and a Children property
// containing a collection of the names of the level2 elements
var results = doc.Descendants("level1")
                .Select(level1 => new
                {
                    Name = level1.Attribute("name").Value,
                    Children = level1.Descendants("level2")
                                     .Select(level2 => level2.Attribute("name").Value)
                });

foreach (var result in results)
{
    Console.WriteLine(result.Name);
    foreach (var child in result.Children)
        Console.WriteLine("  " + child);
}

结果:

A
  A1
  A2
B
  B1
  B2
C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接