Building json from tabular hierarchical data
假设我有一些数据,如下所示:
1 2 3 4 5 6 7 8 9 10 | { "Menu": { "aaa":"aaa", "bbb": { "ccc":"ccc", "ddd":"ddd" }, "eee":"eee" } } |
我可以将这种类型的分层数据以这样的关系方式保存到数据库中:
1 | http://i.stack.imgur.com/lmuq1.jpg |
样品清单:
1 2 3 4 5 6 7 | 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 }); |
因此,当我从 db 获取关系数据作为 MenuItem 对象列表时,如何将其转换回 json?
1 2 3 4 5 6 7 8 9 10 11 12 | 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; } } |
我必须使用 Dictionary 或 ExpandoObject 之类的吗?我想要与开始时完全相同的格式。
使用 Json.net,我们可以编写一个自定义转换器来从
列表中生成我们想要的 json
注意:我省略了转换器的读者部分以使其简洁(因为它与问题没有真正相关)但逻辑将类似于作者部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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()); } } |
这里是直接使用示例:
1 2 3 4 5 6 7 8 9 | 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()); |
或者我们可以从
1 2 3 4 |
然后简单地使用它:
1 2 3 4 5 6 7 8 9 | 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); |
您可以为此目的创建 KeyValuePair 对象:
1 |
然后,您可以添加元素,如下所示:
1 |
要为此添加复合内容,您可以执行以下操作:
1 2 3 4 |
构建对象后,您可以使用 NewtonSoft\\'s JsonConvert.SerializeObject 方法。
你也可以创建一个辅助类来帮助你。
编辑:创建动态数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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; } } |
代码未经测试,如果您遇到错误,请告诉我,而不仅仅是投反对票,我相信我会在这里努力提供帮助。
你可以像这样实例化这个类:
1 |
当你打算添加一个新的
当你打算添加一个新的
当你打算在内部列表中添加一些东西时,你可以这样做:
如果您可以使用 NewtonSoft,请使用反序列化您的 JSON 内容并查看结果对象的外观。然后,创建一个与反序列化结果结构匹配的类。逆向工程...
使用这个方法:
1 | var obj = JsonConvert.DeserializeObject("{"menu": {"aaa":"aaa"......} }"); |
让我知道你的发现。