[英]Building json from tabular hierarchical data
Let's say I have some data as you see below: 假设我有一些数据,如下所示:
{
"Menu": {
"aaa": "aaa",
"bbb": {
"ccc": "ccc",
"ddd": "ddd"
},
"eee": "eee"
}
}
I can save this type of hierarchical data to database in a relational way like that: 我可以通过这种关系方式将这种类型的分层数据保存到数据库中:
http://i.stack.imgur.com/lmuq1.jpg
Sample list: 样本清单:
List<MenuItem> menuItems = new List<MenuItem>();
menuItems.Add(new MenuItem() { SiteMenuId = 1, ParentId = null, MenuName = "Menu", Url = null, SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 2, ParentId = 1, MenuName = "aaa", Url = "aaa", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 3, ParentId = 1, MenuName = "bbb", Url = null, SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 4, ParentId = 3, MenuName = "ccc", Url = "ccc", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 5, ParentId = 3, MenuName = "ddd", Url = "ddd", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 6, ParentId = 1, MenuName = "eee", Url = "eee", SiteId = 1 });
So when I get the relational data from db as a List of MenuItem objects, how can I tranlate it back to json? 因此,当我从db获得作为MenuItem对象列表的关系数据时,如何将其转换回json?
public partial class MenuItem
{
public int SiteMenuId { get; set; }
public int SiteId { get; set; }
public string MenuName { get; set; }
public string Url { get; set; }
public Nullable<int> ParentId { get; set; }
public int CreatedUser { get; set; }
public System.DateTime CreatedDate { get; set; }
public Nullable<int> ModifiedUser { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
}
Do I have to use Dictionary or ExpandoObject or something? 我必须使用Dictionary或ExpandoObject或其他东西吗? I want to have the the exact same format as I have at the begining.
我想拥有与开始时完全相同的格式。
You can create KeyValuePair object for that purpose: 您可以为此创建KeyValuePair对象:
KeyValuePair<string, List<Object>> toExport = new KeyValuePair<int, int>("Menu", new List<Object>());
Then, you can add elements, like this: 然后,您可以添加元素,如下所示:
toExport.Value.Add(new KeyValuePair<string, string>("aaa", "aaa"));
To add composite things to this, you can do something like that: 要向其中添加复合内容,您可以执行以下操作:
KeyValuePair<string, List<Object>> bbb = new KeyValuePair<string, List<Object>>("bbb", new List<Object>());
bbb.Value.Add(new KeyValuePair<string, string>("ccc", "ccc"));
bbb.Value.Add(new KeyValuePair<string, string>("ddd", "ddd"));
toExport.Value.Add(bbb);
When you have built your object, you can use NewtonSoft's JsonConvert.SerializeObject method. 构建对象后,可以使用NewtonSoft的JsonConvert.SerializeObject方法。
You can also create a helper class to help you. 您还可以创建一个帮助器类来帮助您。
EDIT: Creation of dynamic data. 编辑:动态数据的创建。
public class DynamicKeyValueBuilder {
private KeyValuePair<string, List<Object>> toExport;
public DynamicKeyValueBuilder(string mainKey) {
toExport = new KeyValuePair<string, List<Object>>(mainKey, new List<Object>());
}
public string getJSON() {
return JsonConvert.SerializeObject(this.toExport);
}
private KeyValuePair<string, List<Object>> searchParent(List<string> path) {
KeyValuePair<string, List<Object>> temp = (KeyValuePair<string, List<Object>>)this.toExport;
int index = 0;
while (index < path.Count) {
try {
temp = (KeyValuePair<string, List<Object>>)temp.First(item => item.Key == path.ElementAt(index)); //throws exception if value is not list or the element was not found
index++;
} catch (Exception exception) {
//handle exceptions
return null;
}
}
return temp;
}
//If value == null, we create a list
public boolean addElement(List<string> path, string key, string value) {
KeyValuePair<string, Object> parent = this.searchParent(path);
//failure
if (parent == null) {
return false;
}
parent.Value.Add((value == null) ? (new KeyValuePair<string, List<Object>>(key, new List<Object>())) : (new KeyValuePair<string, string>(key, value)));
return true;
}
}
Code is untested, if you encounter errors, please, let me know instead of just down-voting, I believe I am putting an effort here to help. 代码未经测试,如果遇到错误,请告诉我,而不仅仅是拒绝投票,我相信我会在这里提供帮助。
You can instantiate the class like this: 您可以像这样实例化该类:
DynamicKeyValueBuilder myBuilder = new DynamicKeyValueBuilder("Menu");
When you intend to add a new <string, string>
element, you can do it like this: 当您打算添加新的
<string, string>
元素时,可以这样进行:
myBuilder.Add(new List<string>(new string[] {"Menu"}), "aaa", "aaa");
When you intend to add a new <string, List<Object>>
element, you can do it like this: 当您打算添加新的
<string, List<Object>>
元素时,可以这样进行:
myBuilder.Add(new List<string>(new string[] {"Menu"}), "bbb", null);
When you intend to add something inside an inner list, you can do it like this: 当您打算在内部列表中添加内容时,可以这样进行:
myBuilder.Add(new List<string>(new string[] {"Menu", "bbb"}), "ccc", "ccc");
using Json.net , we can write a custom converter to generate our desired json from list of MenuItem
. 使用Json.net ,我们可以编写一个自定义转换器,以从
MenuItem
列表生成所需的json。
NOTE: I omitted the reader part for the converter to make it concise (as its not really related to the question) but the logic would be similar to the writer part. 注意:我省略了转换器的阅读器部分,以使其简洁(因为它实际上与问题无关),但是其逻辑与编写器部分相似。
class MenuItemJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof (MenuItemCollection) || objectType==typeof(List<MenuItem>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var map=new Dictionary<int,JObject>();
var collection = (List<MenuItem>) value;
var root=new JObject();
var nestedItems=collection.GroupBy(i => i.ParentId).ToLookup(g=>g.Key); //or we can simply check for item.Url==null but I believe this approach is more flexible
foreach (var item in collection)
{
if (item.ParentId == null)
{
var firstObj=new JObject();
root.Add(item.MenuName,firstObj);
map.Add(item.SiteMenuId,firstObj);
continue;
}
var parent = map[item.ParentId.Value];
if (!nestedItems.Contains(item.SiteMenuId))
{
parent.Add(item.MenuName,item.Url);
continue;
}
var jObj = new JObject();
parent.Add(item.MenuName, jObj);
map.Add(item.SiteMenuId, jObj);
}
writer.WriteRaw(root.ToString());
}
}
here is direct usage example: 这是直接的用法示例:
var menuItems = new List<MenuItem>();
menuItems.Add(new MenuItem() { SiteMenuId = 1, ParentId = null, MenuName = "Menu", Url = null, SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 2, ParentId = 1, MenuName = "aaa", Url = "aaa", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 3, ParentId = 1, MenuName = "bbb", Url = null, SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 4, ParentId = 3, MenuName = "ccc", Url = "ccc", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 5, ParentId = 3, MenuName = "ddd", Url = "ddd", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 6, ParentId = 1, MenuName = "eee", Url = "eee", SiteId = 1 });
var json = JsonConvert.SerializeObject(menuItems,Formatting.Indented,new MenuItemJsonConverter());
or we can derive from List<>
and decorate it with [JsonConverter(typeof(MenuItemJsonConverter))]
for more convenience: 或者我们可以从
List<>
派生,并用[JsonConverter(typeof(MenuItemJsonConverter))]
装饰它,以方便使用:
[JsonConverter(typeof(MenuItemJsonConverter))]
class MenuItemCollection : List<MenuItem>
{
}
then simply use it like: 然后像这样简单地使用它:
var menuItems = new MenuItemCollection();
menuItems.Add(new MenuItem() { SiteMenuId = 1, ParentId = null, MenuName = "Menu", Url = null, SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 2, ParentId = 1, MenuName = "aaa", Url = "aaa", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 3, ParentId = 1, MenuName = "bbb", Url = null, SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 4, ParentId = 3, MenuName = "ccc", Url = "ccc", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 5, ParentId = 3, MenuName = "ddd", Url = "ddd", SiteId = 1 });
menuItems.Add(new MenuItem() { SiteMenuId = 6, ParentId = 1, MenuName = "eee", Url = "eee", SiteId = 1 });
var json = JsonConvert.SerializeObject(menuItems,Formatting.Indented);
If you can use NewtonSoft, use to deserialize your JSON content and see how the resulting object looks like. 如果可以使用NewtonSoft,请使用来反序列化JSON内容,并查看生成的对象的外观。 Then, create a class that matches the resulting structure of the deserialization.
然后,创建一个与反序列化的结果结构匹配的类。 Reverse engineering...
逆向工程...
Use this method: 使用此方法:
var obj = JsonConvert.DeserializeObject("{ "menu": { "aaa": "aaa"......} }");
Let me know your findings. 让我知道你的发现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.