Инициализация и доступ с индексом к непознаваемому номеру списка в словаре - PullRequest
0 голосов
/ 06 мая 2018

У меня есть проблема, которая не дает мне спать по ночам. Это довольно долго объяснять, поэтому спасибо заранее за то время, которое вы посвятили этой теме.

Контекст

Я хочу создать класс в 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, поскольку я не могу знать, сколько дочерних узлов будет в каждом узле. Это делает меня неспособным получить доступ к нескольким дочерним узлам, как я показал в первой части, потому что Object - это не List.

Вопрос

Есть ли способ на самом деле решить это? Я хотя и мог бы преобразовать список объектов в список Dictionary, основываясь на моих потребностях, но я действительно понятия не имею, как он будет работать.

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Я использовал следующие 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());

        }
    }
}
0 голосов
/ 06 мая 2018

Чтобы избежать вложенных универсальных типов, вы можете создать некоторые неуниверсальные оболочки классов с индексаторами и переместить определение словаря или списка внутрь:

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]; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...