首页 > 解决方案 > 用索引初始化和访问字典中不知道数量的列表

问题描述

我有这个问题让我彻夜难眠。解释起来很长,所以提前感谢您为这个主题付出的时间。

上下文

我想在 C# 中创建一个类来获取 XML 文件的全部内容,其中节点名称作为索引,并使用列表和字典的组合以树的方式排序。

目标是能够使用如下名称和索引访问特定数据:

Console.WriteLine(xmlContent["employee"][0]["e-mail"][1]);
//Would return the second email from the first employee register in the xml file.

我几乎可以肯定这是可能的。我使用一个列表和两个字典快速创建了类似的东西:

        List<Dictionary<string, Dictionary<string, string>>> test = new List<Dictionary<string, Dictionary<string, string>>>();

        Dictionary<string, Dictionary<string, string>> column1 = new Dictionary<string, Dictionary<string, string>>();
        Dictionary<string, Dictionary<string, string>> column2 = new Dictionary<string, Dictionary<string, string>>();

        Dictionary<string, string> C1ligne1 = new Dictionary<string, string>();
        C1ligne1.Add("value1", "C1ligne1 1");
        C1ligne1.Add("value2", "C1ligne1 2");

        Dictionary<string, string> C1ligne2 = new Dictionary<string, string>();
        C1ligne2.Add("value1", "C1ligne2 1");
        C1ligne2.Add("value2", "C1ligne2 2");

        Dictionary<string, string> C2ligne1 = new Dictionary<string, string>();
        C2ligne1.Add("value1", "C2ligne1 1");
        C2ligne1.Add("value2", "C2ligne1 2");

        Dictionary<string, string> C2ligne2 = new Dictionary<string, string>();
        C2ligne2.Add("value1", "C2ligne2 1");
        C2ligne2.Add("value2", "C2ligne2 2");

        column1.Add("line1", C1ligne1);
        column1.Add("line2", C1ligne2);

        column2.Add("line1", C2ligne1);
        column2.Add("line2", C2ligne2);

        test.Add(column1);
        test.Add(column2);

        Console.WriteLine(test[0]["line1"]["value1"]); //"C1ligne1 1"
        Console.WriteLine(test[0]["line2"]["value2"]); //"C1ligne2 2"
        Console.WriteLine(test[1]["line1"]["value2"]); //"C2ligne1 2"

它真的很好用!

问题

我设法使用方法和函数制作了我想要的东西,它就像我想要的那样工作:

    public void getContent(ref Dictionary<string, List<Object>> content)
    {
        foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
        {
            if (!content.ContainsKey(node.Name))
            {
                content.Add(node.Name, new List<Object>());
                content[node.Name].Add(this.nodeContent(node));
            }
            else
            {
                content[node.Name].Add(this.nodeContent(node));
            }
        }
    }

    private Dictionary<string, List<Object>> nodeContent(XmlNode specificNode)
    {
        Dictionary<string, List<Object>> content = new Dictionary<string, List<Object>>();

        foreach (XmlNode nodeInSpecificNode in specificNode.ChildNodes)
        {
            if (nodeInSpecificNode.ChildNodes.Count > 1)
            {
                content.Add(nodeInSpecificNode.Name, new List<object>  ());
                content[nodeInSpecificNode.Name].Add(this.nodeContent(nodeInSpecificNode));
            }
            else
            {
                content.Add(nodeInSpecificNode.Name, new List<Object>());
                content[nodeInSpecificNode.Name].Add(nodeInSpecificNode.InnerText);
            }
        }

        return content;
    }

不幸的是,它迫使我使用对象列表,因为我不知道每个节点中有多少子节点。这使我无法像我在第一部分中展示的那样访问多个子节点,因为 Object 不是 List。

问题

有没有办法真正解决这个问题?我虽然有一种方法可以根据我的需要将对象列表转换为字典列表,但我真的不知道它是如何工作的。

标签: c#xmllistdictionaryobject

解决方案


我使用了以下 xml:

<?xml version="1.0" encoding="utf-8" ?>
<test>
  <line1>
    <value1>C1ligne1 1</value1>
    <value2>C1ligne1 2</value2>
  </line1>
  <line2>
    <value1>C1ligne2 1</value1>
    <value2>C1ligne2 2</value2>
  </line2>
  <line1>
    <value1>C2ligne1 1</value1>
    <value2>C2ligne1 2</value2>
  </line1>
  <line2>
    <value1>C2ligne2 1</value1>
    <value2>C2ligne2 2</value2>
  </line2>
</test>

这是创建两级字典的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            Dictionary<string, Dictionary<string,string>> dict = doc.Element("test").Elements()
                .GroupBy(x => x.Name.LocalName, y => y.Elements()
                    .GroupBy(a => a.Name.LocalName, b => (string)b)
                    .ToDictionary(a => a.Key, b => b.FirstOrDefault()))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

        }
    }
}

推荐阅读