转换扁平分层数据为结构化JSON树 [英] Converting flattened hierarchical data into a tree structured 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使之具有逻辑输出文本
属性代替名称的code>如果名字是一个点(
。
)。
希望这有助于。
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屋!