在C#中使用LINQ解析XML

Parsing XML with LINQ in C#

我正在尝试使用LINQ在C#和XML之间进行映射。当前,我有一个用C#定义的类,如下所示:

Item.cs

1
2
3
4
5
6
7
8
public class Item
{
  public string DepartmentName { get; set; }
  public Dictionary<string, string> DepartmentNames { get; set; }

  public string Name { get; set; }
  public Dictionary<string, string> Names { get; set; }
}

我的XML文件如下所示:

departments.xml

1
2
3
4
5
6
7
8
9
10
11
<Departments>
  <Department Name="Sports" Title="Sports Department" Path="/sports" en-us="Sports" de-de="Sport">
    <Item Name="Football" en-us="Football" de-de="Fu?ball" es-mx="" />
    <Item Name="TennisBall" en-us="Tennis Ball" de-de="Tennisball" />
  </Department>

  <Department Name="Automotive" Title="Automotive Department" Path="/autos" en-us="Automotive" de-de="kraftfahrtechnisch">
    <Item Name="Oil" en-us="Oil" de-de="?l" />
    <Item Name="Tires" en-us="Tires" de-de="Bereifung" es-mx="Ruedas" />
  </Department>
</Departments>

基本上,我有一些要加载到确定属性中的值。然后,我有一个我想加载到字典中的属性列表(" zh-cn"," de-de"," es-mx")。当前,我有以下内容:

1
2
3
4
5
6
7
8
9
10
11
var items = XDocument.Parse(File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\\Items.xml")))
  .Element("Departments")
  .Elements("Department")
  .Elements("Item")
  .Select(e => new Item
  {
    DepartmentName = ?,
    DepartmentNames = ?,
    Name = e.Attribute("Name").Value,
    Names = ?
  }).ToList();

我不确定如何从a)父元素b)加载Dictionary对象中加载属性。 LINQ甚至有可能吗?本质上,我正在尝试整理内存中的数据结构。


在这种情况下,您需要在嵌套循环中访问外部元素的属性,因此我发现Linq from / select语法更舒适。因此:

1
2
3
4
5
6
7
8
9
10
11
        var doc = XDocument.Load(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),"InputData.xml"));
        var query = from department in doc.Element("Departments").Elements("Department")
                    from item in department.Elements("Item")
                    select new Item
                    {
                        DepartmentName = department.Attribute("Name").Value,
                        DepartmentNames = department.Attributes().Where(a => a.Name !="Name").ToDictionary(a => a.Name.LocalName, a => a.Value),
                        Name = item.Attribute("Name").Value,
                        Names = item.Attributes().Where(a => a.Name !="Name").ToDictionary(a => a.Name.LocalName, a => a.Value),
                    };
        var items = query.ToList();

在这里,我假设您希望除Name属性(它具有自己的属性)之外的所有其他属性都放置在字典中。

更新

如果您有待放入字典的已知属性列表,则可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
        var attributes = new HashSet<string>(new[] {"en-us","de-de","es-mx" }); // Possibly initialized in a static constructor.

        var query = from department in doc.Element("Departments").Elements("Department")
                    from item in department.Elements("Item")
                    select new Item
                    {
                        DepartmentName = department.Attribute("Name").Value,
                        DepartmentNames = department.Attributes().Where(a => attributes.Contains(a.Name.LocalName)).ToDictionary(a => a.Name.LocalName, a => a.Value),
                        Name = item.Attribute("Name").Value,
                        Names = item.Attributes().Where(a => attributes.Contains(a.Name.LocalName)).ToDictionary(a => a.Name.LocalName, a => a.Value),
                    };
        var items = query.ToList();

我认为下面的代码是您想要的。我在这里进行了测试,它确实有效,但是我不确定这是否是您的意图。
我只是用所有语言值填充字典。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
            var items = XDocument.Parse(
            File.ReadAllText(
            Path.Combine(
                Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
               "InputData.xml")))
                      .Element("Departments")
                      .Elements("Department")
                      .Select(
                      d => d.Elements("Item").Select(e => new Item
                      {
                        DepartmentName = d.Attribute("Name").Value,
                        DepartmentNames = new Dictionary<string,string>()
                        {
                            {"en-us", d.Attribute("en-us").Value },
                            {"de-de", d.Attribute("de-de").Value}
                        },
                        Name = e.Attribute("Name").Value,
                        Names = new Dictionary<string,string>()
                        {
                            {"en-us", e.Attribute("en-us").Value},
                            {"de-de", e.Attribute("de-de").Value}
                        }
                      })).ToList();