簡體   English   中英

從表格分層數據構建json

[英]Building json from tabular hierarchical data

假設我有一些數據,如下所示:

{
    "Menu": {
        "aaa": "aaa",
        "bbb": {
             "ccc": "ccc",
             "ddd": "ddd"
        },
        "eee": "eee"
     }
}

我可以通過這種關系方式將這種類型的分層數據保存到數據庫中:

http://i.stack.imgur.com/lmuq1.jpg

樣本清單:

    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?

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或其他東西嗎? 我想擁有與開始時完全相同的格式。

您可以為此創建KeyValuePair對象:

KeyValuePair<string, List<Object>> toExport = new KeyValuePair<int, int>("Menu", new List<Object>());

然后,您可以添加元素,如下所示:

toExport.Value.Add(new KeyValuePair<string, string>("aaa", "aaa"));

要向其中添加復合內容,您可以執行以下操作:

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

構建對象后,可以使用NewtonSoft的JsonConvert.SerializeObject方法。

您還可以創建一個幫助器類來幫助您。

編輯:動態數據的創建。

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

}

代碼未經測試,如果遇到錯誤,請告訴我,而不僅僅是拒絕投票,我相信我會在這里提供幫助。

您可以像這樣實例化該類:

DynamicKeyValueBuilder myBuilder = new DynamicKeyValueBuilder("Menu");

當您打算添加新的<string, string>元素時,可以這樣進行:

myBuilder.Add(new List<string>(new string[] {"Menu"}), "aaa", "aaa");

當您打算添加新的<string, List<Object>>元素時,可以這樣進行:

myBuilder.Add(new List<string>(new string[] {"Menu"}), "bbb", null);

當您打算在內部列表中添加內容時,可以這樣進行:

myBuilder.Add(new List<string>(new string[] {"Menu", "bbb"}), "ccc", "ccc");

使用Json.net ,我們可以編寫一個自定義轉換器,以從MenuItem列表生成所需的json。

注意:我省略了轉換器的閱讀器部分,以使其簡潔(因為它實際上與問題無關),但是其邏輯與編寫器部分相似。

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

這是直接的用法示例:

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

或者我們可以從List<>派生,並用[JsonConverter(typeof(MenuItemJsonConverter))]裝飾它,以方便使用:

[JsonConverter(typeof(MenuItemJsonConverter))]
class MenuItemCollection : List<MenuItem>
{      
}

然后像這樣簡單地使用它:

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

如果可以使用NewtonSoft,請使用來反序列化JSON內容,並查看生成的對象的外觀。 然后,創建一個與反序列化的結果結構匹配的類。 逆向工程...

使用此方法:

var obj = JsonConvert.DeserializeObject("{ "menu": { "aaa": "aaa"......} }");

讓我知道你的發現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM