转换扁平分层数据为结构化JSON树 [英] Converting flattened hierarchical data into a tree structured JSON

查看:854
本文介绍了转换扁平分层数据为结构化JSON树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含文件和文件夹的文件可在其下的文件名的C#字典对象。欲将该数据转换成层次结构树。下面是数据。我怎样才能将其转换为树型结构JSON。



我看着这个的例如但我没能获得所需的输出。

  + -------------------------------------- --------- + | 
|名称|路径
| -------------------------------------------- ---- |
|厨房用品|购物/家庭用品|
|食品杂货|购物/家庭用品|
|清洁用品|购物/家庭用品|
|办公用品|购物/家庭用品|
| Retile厨房|购物/重塑|
|天花板|购物中心/油漆卧室|
|墙|购物中心/油漆卧室|
|杂项|空|
|其他|购物|
+ --------------------------------------------- - + |



应该产生这样的输出:



  {文:孩子们,:
{
名称:购物,
儿: [{
名称:家庭用品,
儿:[{
名称:厨房用品,
叶:真的,
},{
产品名称:杂货,
叶:真的,
},{
名称:'清洁用品',
叶:真的,
},{
产品名称:办公用品,
叶:真的,
}]
},{
名称:'重塑',
儿:[{
产品名称:Retile厨房',
叶:真的,
},{
名称:画图卧室',
儿:[{
名称:'天花板',
叶:真正的
},{
名称:'墙',
iconCls:名称,
}]
},
{
名称:其他,
叶:真正的
}]
}]
},
{
名称:'杂项,
叶:真正的
}
]}


解决方案

如你挂钩的例子中,有两个主要任务。首先,我们需要从字典中的数据放入一个分层的形式。有一次,我们做到了这一点,我们可以不用担心它序列化到JSON。



所以第一件事情,我们需要一个节点类来表示层次结构:

 类节点
{
公共节点()
{
=儿童新的List<节点>();
}

公共字符串名称{;组; }
公开名单<节点>儿童{搞定;组; }
}



一旦我们有了这一点,我们可以去翻翻字典,并建立树。 (注:在您需要的JSON,你看油漆寝室其他从属于重塑,而在你的榜样字典数据,他们都从属于购物。我假设的JSON在这种情况下正确的,所以我改变了字典数据因此,如下图所示)

 词典<字符串,字符串>字典=新词典<字符串,字符串>(); 
dict.Add(厨房用品,购物/家居用品);
dict.Add(杂货,购物/家居用品);
dict.Add(清洁用品,购物/家居用品);
dict.Add(办公用品,购物/家居用品);
dict.Add(Retile厨房,购物/重塑);
dict.Add(天花板,购物/改造/油漆寝室);
dict.Add(墙,购物/改造/油漆寝室);
dict.Add(杂项,NULL);
dict.Add(其他,购物/重塑);

节点的root =新节点();
的foreach(KeyValuePair<字符串,字符串> KVP在字典)
{
节点父=根;
如果
{
节点子= NULL(string.IsNullOrEmpty(kvp.Value)!);
的foreach(在kvp.Value.Split字符串部分(新的char [] {'/'},StringSplitOptions.RemoveEmptyEntries))
{
字符串名称= part.Trim();
=子parent.Children.Find(N => n.Name ==名);
如果(孩子== NULL)
{
=子节点的新名称{=名};
parent.Children.Add(小孩);
}
父=子;
}
}
parent.Children.Add(新节点{名称= kvp.Key});
}

现在,我们有我们的树,我们可以将其序列化。然而,我们需要一些特殊的处理,因为你的叶子节点都在你的JSON呈现不同于非叶节点:叶节点有一个属性但没有孩子属性,而相反的是用于非叶节点如此。为了处理这个逻辑,我们需要一个自定义的 JsonConverter 。 (只是为了澄清,我使用 Json.Net 这里 - 你的问题没有提及具体的JSON序列。)

 类NodeConverter:JsonConverter 
{
公众覆盖布尔CanConvert(类型的objectType)
{
回报率(的objectType == typeof运算(节点));
}

公共覆盖无效WriteJson(JsonWriter作家,对象的值,JsonSerializer串行)
{
节点node =(节点)值;
JObject乔=新JObject();
jo.Add(名,node.Name);
如果(node.Children.Count == 0)
{
jo.Add(叶,真正的);
}
,否则
{
jo.Add(孩子,JArray.FromObject(node.Children,序列化));
}
jo.WriteTo(作家);
}

公众覆盖对象ReadJson(JsonReader读者,类型的objectType,对象existingValue,JsonSerializer串行)
{
抛出新NotImplementedException();
}
}

我们可以使用JsonConverter序列化树JSON像这样的:

  JsonSerializerSettings设置=新JsonSerializerSettings 
{
转换器=新的List< JsonConverter> {新NodeConverter()},
格式化= Formatting.Indented
};

JSON字符串= JsonConvert.SerializeObject(根,设置);

Console.WriteLine(JSON);

下面是输出:

  {
名,
孩子:
{
名:购物,
孩子:[
{
名:家庭用品,
孩子:
{
名:厨房用品
叶子:真正的
},
{
名:杂货,
叶子:真正的
},
{
名:清洁用品,
叶子:真正的
},
{
名:办公用品,
叶子:真正的
}
]
},
{
名:重塑,
孩子:[
{
名:Retile厨房,
叶子:真正的
},
{
名:画图寝室,
孩子:
{
名:天花板,
叶子:真正的
},
{
名:墙,
叶子:真正的
}
]
},
{
名:其他,
叶子:真正的
}
]
}
]
},
{
名:杂项,
叶子:真正的
}
]
}

另外一个未成年人注:以上所需的JSON,你展示了文本属性,而不是一个名称相同的根节点属性,它与所有其他节点不一致。我假定这是一个错误。如果不是,你需要改变JsonConverter使之具有逻辑输出文本属性代替名称如果名字是一个点()。



希望这有助于。


I have a C# dictionary object which contains name of file and folder under which that file is available. I want to convert the data into hierarchical tree. Below is the data. How can I convert it into tree structured JSON.

i looked into this example but I am not able to get the desired output.

+-----------------------------------------------+|
|  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                  | 
+-----------------------------------------------+|

Should Generate output like:

   {"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
    }
]}

解决方案

As in the example you linked to, there are two main tasks. First, we need to get the data from the dictionary into a hierarchical form. Once, we've done that, we can worry about serializing it to JSON.

So first thing, we need a Node class to represent the hierarchy:

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

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

Once we have that, we can go through the dictionary and build the tree. (Note: in your desired JSON, you show Paint bedroom and Other as subordinate to Remodeling, while in your example dictionary data they are subordinate to Shopping. I am assuming the JSON is correct in this case, so I changed the dictionary data accordingly as shown below.)

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 });
}

Now that we have our tree, we can serialize it. However, we need some special handling because your leaf nodes are rendered differently than non-leaf nodes in your JSON: leaf nodes have a leaf property and no children property, while the reverse is true for non-leaf nodes. To handle this logic, we will need a custom JsonConverter. (Just to clarify, I am using Json.Net here-- your question did not mention a specific JSON serializer.)

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();
    }
}

We can use the JsonConverter to serialize the tree to JSON like this:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new NodeConverter() },
    Formatting = Formatting.Indented
};

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

Console.WriteLine(json);

Here is the output:

{
  "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
    }
  ]
}

One other minor note: in your desired JSON above, you show the root node with a text property instead of a name property, which is inconsistent with all the other nodes. I am assuming this was a mistake. If it wasn't, you'll need to change the JsonConverter so that it has logic to output a text property in place of the name if the name is a dot (.).

Hope this helps.

这篇关于转换扁平分层数据为结构化JSON树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆