使用索引初始化和访问dictionnary

时间:2018-05-05 23:34:26

标签: c# xml list dictionary object

我有这个让我夜不能寐的问题。这是很长的解释,所以提前感谢你专注于这个主题的时间。

上下文

我想在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和两个词典快速创建类似的东西:

        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列表,因为我不知道每个节点中有多少子节点。这使我无法访问多个子节点,就像我在第一部分中所示,因为Object不是List。

问题

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

2 个答案:

答案 0 :(得分:0)

为了避免嵌套泛型类型,您可以使用索引器创建一些非泛型类包装器,并在其中移动字典或列表的定义:

public class DictionaryNode 
{
    public Dictionary<string, ListNode> Dictionary { get; } = new Dictionary<string, ListNode>();

    public ListNode this[string name]
    {
        get
        {
            return Dictionary[name];
        }
    }
}

public class ListNode 
{
    public List<DictionaryNode> List { get; } = new List<DictionaryNode>();

    public DictionaryNode this[int index]
    {
        get
        {
            return List[index];
        }
    }

    //to make writing [0] optional
    public ListNode this[string name]
    {
        get
        {
            return List[0][name];
        }
    }
}

使用这样的包装器,您可以创建这样的树结构:

var node1 = new DictionaryNode();
var node2 = new ListNode();
var node3 = new DictionaryNode();
var node4 = new ListNode();
node4.List.AddRange(new[] { new DictionaryNode(), new DictionaryNode() });
node3.Dictionary.Add("bb", node4);
node2.List.Add(node3);
node1.Dictionary.Add("aa", node2);

var n = node1["aa"][0]["bb"][1];
var n2 = node1["aa"]["bb"][1]; 

答案 1 :(得分:0)

我使用了以下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());

        }
    }
}