首页 > 解决方案 > 使用 XDocument 从带有重复键的 XML 中读取

问题描述

我需要一些关于 XDocument 的帮助。我有文件:

<?xml version="1.0" encoding="utf-8" ?>
<SaleGroupsFiles>
  <SaleGroup id="1" active="true" name="US"> 
   <files
      location="c:\mypath\"
      fileType="pdf"
      destination="outputpath">
    </files>
  </SaleGroup>

  <SaleGroup id="2" active="true" name="Canada"> 
   <files
      location="c:\mypath\"
      fileType="pdf"
      destination="outputpath">
    </files>
  </SaleGroup>
</SaleGroups>

我正在尝试使用 XDocument 读取文件

static Dictionary<string, string> GetSettings(string path)
    {
        var document = XDocument.Load(path);
        var root = document.Root;
        var results =
          root
            .Elements()
            .ToDictionary(element => element.Name.ToString(), element => element.Value);
        return results;

    }

收到错误“字典中已存在具有该键的元素”。我猜这是因为“SaleGroup”重复了不止一次。

读取数据的正确方法是什么?

标签: c#linq-to-xml

解决方案


你的假设是正确的;正如@maccettura 解释的那样,这就是Dictionary工作原理。

这就是说,请记住,<SaleGroupsFiles>您的 XML 应该有一个匹配的标记才能有效。

根据您的问题,这是一个可能的想法:

var results =
    root
        .Descendants("SaleGroup")
        .ToDictionary(element => element.Attribute("id").Value.ToString(), element => element.ToString());

即添加元素属性的值作为键id,假设它们是唯一的。

其实这个问题

读取数据的正确方法是什么?

很难回答,因为......这取决于你想对数据做什么。你想创建SaleGroup对象吗?List<SaleGroup>在这种情况下,如果你提供一个SaleGroup类,你可以创建一个,而不是创建一个字典。

另一种选择是反序列化您的 XML。

另外,请记住 element.Name 将给出元素的名称(例如 SaleGroup),而您可能想读取name属性的值(例如“Canada”)?


编辑

由于您可以使用稍微更现实的解决方案,如果您声明这些类

public class SaleGroup
{
    public int Id { get; set; }
    public bool Active { get; set; }
    public string Name { get; set; }
    public SaleFile File { get; set; }
}

public class SaleFile
{
    public string Location { get; set; }
    public string FileType { get; set; }
    public string Destination { get; set; }
}

你可以这样编辑你的代码:

var results =
          root
            .Descendants("SaleGroup")
            .Select(element => new SaleGroup()
            {
                Active = Convert.ToBoolean(element.Attribute("active").Value),
                Id = Convert.ToInt32(element.Attribute("id").Value),
                Name = element.Attribute("name").Value,
                File = new SaleFile()
                {
                    Destination = element.Descendants("files").Single().Attribute("destination").Value,
                    FileType = element.Descendants("files").Single().Attribute("fileType").Value,
                    Location = element.Descendants("files").Single().Attribute("location").Value
                }
            })
            .ToList();

也可以优化上面的代码,例如只读取element.Descendants("files").Single()一次,或者修改它以允许SaleFile在你的SaleGroup类中使用多个。


推荐阅读