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

Posted

技术标签:

【中文标题】将扁平的分层数据转换为树状结构的 JSON【英文标题】:Converting flattened hierarchical data into a tree structured JSON 【发布时间】:2013-11-24 15:10:57 【问题描述】:

我有一个 C# 字典对象,其中包含该文件可用的文件名和文件夹。我想将数据转换为分层树。下面是数据。如何将其转换为树状结构的 JSON。

我查看了这个example,但我无法获得所需的输出。

+-----------------------------------------------+|
|  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:我不知道该怎么做。以及实现结果的最佳和最有效的方法是什么。 【参考方案1】:

在您链接到的示例中,有两个主要任务。首先,我们需要将字典中的数据转换成分层的形式。一旦完成,我们就可以担心将其序列化为 JSON。

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

class Node

    public Node()
    
        Children = new List<Node>();
    

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

一旦我们有了它,我们就可以遍历字典并构建树。 (注意:在您想要的 JSON 中,您将 Paint bedroomOther 显示为从属于 Remodeling,而在您的示例字典数据中它们从属于 Shopping。我假设 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

希望这会有所帮助。

【讨论】:

感谢您如此深入地回复示例。我不能要求更多。很棒的答案。

以上是关于将扁平的分层数据转换为树状结构的 JSON的主要内容,如果未能解决你的问题,请参考以下文章

JS实现 JSON扁平数据转换树状数据

转换分层 DOM 树 XML 文件:XSLT 能否转换为“扁平化”XML 文件而不会丢失数据?

使用 C# 将数据表转换为分层数据结构 (JSON)

如何将分层表转换为json

使用 python 和 pandas 将多数组 json 数据转换为扁平数据框

JavaScript 扁平与树形数组数据的转换