将扁平的分层数据转换为树形结构的 JSON

4
我有一个C#字典对象,其中包含文件名和文件所在文件夹的名称。我希望将这些数据转换为分层树结构。以下是数据。如何将其转换为树形结构的JSON。
我查看了这个示例,但我无法获得所需的输出。
+-----------------------------------------------+|
|  Name             | Path 
|------------------------------------------------|
| Kitchen supplies  |  Shopping / Housewares     |
| Groceries         |  Shopping / Housewares     |
| Cleaning supplies |  Shopping / Housewares     |
| Office supplies   |  Shopping / Housewares     |
| Retile kitchen    |  Shopping / Remodeling     |
| Ceiling           |  Shopping / Paint bedroom  |
| Walls             |  Shopping / Paint bedroom  |
| Misc              |  null                      |
| Other             |  Shopping                  | 
+-----------------------------------------------+|

应该生成以下输出:
   {"text":".","children": [
    {
        Name:' Shopping',
        children:[{
            Name:'Housewares',
            children:[{
                Name:'Kitchen supplies',
                leaf:true,
            },{
                Name:'Groceries',
                leaf:true,
            },{
                Name:'Cleaning supplies',
                leaf:true,
            },{
                Name: 'Office supplies',
                leaf: true,
            }]
        }, {
            Name:'Remodeling',
            children:[{
                Name:'Retile kitchen',
                leaf:true,
            },{
                Name:'Paint bedroom',
                children: [{
                    Name: 'Ceiling',
                    leaf: true
                }, {
                    Name: 'Walls',
                    iconCls: 'Name',
                }]
            },
            {
                Name: 'Other',
                leaf: true
            }]
        }]
    },
    {
        Name: 'Misc',
        leaf: true
    }
]}

你说的“没有得到期望的输出”是什么意思?出了什么问题? - Kuzgun
@Kuzgun:我不确定该如何着手。而且,实现这个结果的最佳和最有效的方法是什么? - SharpCoder
1个回答

6

正如您所链接的示例那样,有两个主要任务。首先,我们需要将字典中的数据转换为分层形式。完成这一步后,我们就可以开始担心将其序列化为JSON。

因此,首先我们需要一个Node类来表示该层次结构:

class Node
{
    public Node()
    {
        Children = new List<Node>();
    }

    public string Name { get; set; }
    public List<Node> Children { get; set; }
}

一旦我们拥有这些数据,我们就可以遍历字典并构建树形结构。(注意:在您所期望的JSON中,您将涂居室其他显示为翻新的下级,而在您的示例字典数据中,它们是购物的下级。 我认为JSON是正确的,在这种情况下,我已相应地更改了字典数据)。

Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("Kitchen supplies", "Shopping / Housewares");
dict.Add("Groceries", "Shopping / Housewares");
dict.Add("Cleaning supplies", "Shopping / Housewares");
dict.Add("Office supplies", "Shopping / Housewares");
dict.Add("Retile kitchen", "Shopping / Remodeling");
dict.Add("Ceiling", "Shopping / Remodeling / Paint bedroom");
dict.Add("Walls", "Shopping / Remodeling / Paint bedroom");
dict.Add("Misc", null);
dict.Add("Other", "Shopping / Remodeling");

Node root = new Node();
foreach (KeyValuePair<string, string> kvp in dict)
{
    Node parent = root;
    if (!string.IsNullOrEmpty(kvp.Value))
    {
        Node child = null;
        foreach (string part in kvp.Value.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries))
        {
            string name = part.Trim();
            child = parent.Children.Find(n => n.Name == name);
            if (child == null)
            {
                child = new Node { Name = name };
                parent.Children.Add(child);
            }
            parent = child;
        }
    }
    parent.Children.Add(new Node { Name = kvp.Key });
}

现在我们有了树,可以对其进行序列化。但是,我们需要进行一些特殊处理,因为你的叶节点在JSON中的呈现方式与非叶节点不同:叶节点具有leaf属性而没有children属性,而非叶节点则相反。为了处理这种逻辑,我们需要一个自定义的JsonConverter。(仅为澄清,我在这里使用Json.Net - 你的问题没有提到特定的JSON序列化器。)
class NodeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Node));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Node node = (Node)value;
        JObject jo = new JObject();
        jo.Add("name", node.Name);
        if (node.Children.Count == 0)
        {
            jo.Add("leaf", true);
        }
        else
        {
            jo.Add("children", JArray.FromObject(node.Children, serializer));
        }
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

我们可以使用JsonConverter将树序列化为JSON,操作如下:
JsonSerializerSettings settings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new NodeConverter() },
    Formatting = Formatting.Indented
};

string json = JsonConvert.SerializeObject(root, settings);

Console.WriteLine(json);

以下是输出结果:
{
  "name": ".",
  "children": [
    {
      "name": "Shopping",
      "children": [
        {
          "name": "Housewares",
          "children": [
            {
              "name": "Kitchen supplies",
              "leaf": true
            },
            {
              "name": "Groceries",
              "leaf": true
            },
            {
              "name": "Cleaning supplies",
              "leaf": true
            },
            {
              "name": "Office supplies",
              "leaf": true
            }
          ]
        },
        {
          "name": "Remodeling",
          "children": [
            {
              "name": "Retile kitchen",
              "leaf": true
            },
            {
              "name": "Paint bedroom",
              "children": [
                {
                  "name": "Ceiling",
                  "leaf": true
                },
                {
                  "name": "Walls",
                  "leaf": true
                }
              ]
            },
            {
              "name": "Other",
              "leaf": true
            }
          ]
        }
      ]
    },
    {
      "name": "Misc",
      "leaf": true
    }
  ]
}

另外需要注意的一点是,在您期望的JSON中,根节点显示为具有“text”属性而不是“name”属性,这与所有其他节点不一致。 我假设这是一个错误。 如果不是,请更改JsonConverter,以便在名称为点(“.”)时输出“text”属性代替“name”。希望这有所帮助。

1
非常感谢您提供如此深入的回复和示例。我再也无法要求更多了。真是太棒了! - SharpCoder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接