簡體   English   中英

如何將分層數據從DataTable轉換為JSON

[英]How to convert hierarchical data from a DataTable to JSON

我有一個如下的分層數據表,它生成一個菜單及其子菜單。 主菜單的ParentId0 每個子菜單都有一個ParentId引用表中另一行的ResourceId

ResourceId  DisplayName    ParentId    Url
-----------------------------------------------
1           Home           0           Some Url
2           Student        0           Some Url
3           Staff          0           Some Url
4           Library        0           Some Url
6           StudentAtt     1           Some Url
7           TimeTable      1           Some Url
8           Staff Att      2           Some Url
9           Book Issue     3           Some Url
10          Book Return    3           Some Url
11          Fee Payment    4           Some Url
12          Book fine      10          Some Url

我需要將數據轉換為JSON。 下面是我試過的代碼。 我試圖檢查子菜單的ParentId是否等於主菜單的ResourceId 但是不顯示子菜單。 (變量tableDataTable 。)

    var rows = table.Rows.Cast<DataRow>().ToList();
    var result = rows
        .Where(x => x["ParentId"].ToString() == "0")
        .GroupBy(r => new { x = r["ResourceId"] })
        .Select(g => new
        {
            //MenuLevel = g.Key.x,
            MenuDetails = g
                .GroupBy(r => new
                {
                    a = r["DisplayName"],
                    b = r["Url"]
                })
                .Select(detail => new
                {
                    DisplayName = detail.Key.a,
                    Url = detail.Key.b,
                    SubMenu = detail
                        .Where(y => g.Key.x.ToString() == y["ParentId"].ToString())
                        .GroupBy(r => new 
                        { 
                            f = r["DisplayName"] 
                        })
                        .Select(subMenu => new
                        {
                            SubMenuDisplayName = subMenu.Key.f
                        })
                })
        });

我得到的結果如下:

[
    {
        "MenuDetails": [
            {
                "DisplayName": "Home",
                "Url": null,
                "SubMenu": []
            }
        ]
    },
    {
        "MenuDetails": [
            {
                "DisplayName": "Student",
                "Url": null,
                "SubMenu": []
            }
        ]
    },
    {
        "MenuDetails": [
            {
                "DisplayName": "Staff",
                "Url": null,
                "SubMenu": []
            }
        ]
    },
    {
        "MenuDetails": [
            {
                "DisplayName": "Library",
                "Url": null,
                "SubMenu": []
            }
        ]
    }
]

但預期的結果是:

[
    {
        "MenuDetails": [
            {
                "DisplayName": "Home",
                "Url": null,
                "SubMenu": [
                    {
                        "SubMenuDisplayName": "StudentAtt"
                    },
                    {
                        "SubMenuDisplayName": "TimeTable"
                    }
                ]
            }
        ]
    },
    {
        "MenuDetails": [
            {
                "DisplayName": "Student",
                "Url": null,
                "SubMenu": [
                    {
                        "SubMenuDisplayName": "Staff Att"
                    }
                ]
            }
        ]
    },
    {
        "MenuDetails": [
            {
                "DisplayName": "Staff",
                "Url": null,
                "SubMenu": [
                    {
                        "SubMenuDisplayName": "Book Issue"
                    },
                    {
                        "SubMenuDisplayName": "Book Return"
                    }
                ]
            }
        ]
    },
    {
        "MenuDetails": [
            {
                "DisplayName": "Library",
                "Url": null,
                "SubMenu": [
                    {
                        "SubMenuDisplayName": "Fee Payment "
                    }
                ]
            }
        ]
    }
]

我還需要顯示子子菜單(其ParentId指向子菜單的ResourceId )。

您在問題中發布的“預期”JSON不是完全遞歸的結構,因為它在級別之間不一致:子菜單項使用與頂級菜單項不同的顯示名稱屬性,並且它們沒有URL或子菜單集合本身。 此外,我認為您的JSON比它需要的更復雜:您不需要介入的“MenuDetails”數組,它們總是只有一個元素。 相反,我會建議一個更簡單的結構:

[
    {
        "DisplayName" : "Top Menu 1",
        "Url" : "/Top1",
        "SubMenu" : 
        [
            {
                "DisplayName" : "SubMenu Item 1",
                "Url" : "/Top1/Sub1",
                "SubMenu" : 
                [
                   ...
                ]
            },
            {
                "DisplayName" : "SubMenu Item 2",
                "Url" : "/Top1/Sub2",
                "SubMenu" : 
                [
                   ...
                ]
            },
            ...
        ]
    },
    {
        "DisplayName" : "Top Menu 2",
        "Url" : "/Top2",
        "SubMenu" : 
        [
            ...
        ]
    },
    ...
]

請注意JSON在每個級別的一致性:每個菜單項都有一個DisplayName,一個Url和一個SubMenu,它是一個(可能是空的)更多菜單項列表。 級別之間的一致性是遞歸結構的關鍵。

要制作這個JSON,我們首先需要一個類來表示一個菜單項:

class MenuItem
{
    public MenuItem()
    {
        SubMenu = new List<MenuItem>();
    }

    [JsonIgnore]
    public int Id { get; set; }
    [JsonIgnore]
    public int ParentId { get; set; }
    public string DisplayName { get; set; }
    public string Url { get; set; }
    public List<MenuItem> SubMenu { get; set; }
}

下一步是將您的平面DataTable轉換為分層結構。 為此,我首先從數據表構建一個MenuItems字典,用Id鍵入:

DataTable table = new DataTable();

table.Columns.Add("ResourceId", typeof(int));
table.Columns.Add("DisplayName", typeof(string));
table.Columns.Add("ParentId", typeof(int));
table.Columns.Add("Url", typeof(string));

table.Rows.Add(1, "Home", 0, "/Home");
table.Rows.Add(2, "Student", 0, "/Student");
table.Rows.Add(3, "Staff", 0, "/Staff");
table.Rows.Add(4, "Library", 0, "/Library");
table.Rows.Add(6, "StudentAtt", 2, "/Student/StudentAtt");
table.Rows.Add(7, "TimeTable", 1, "/Home/TimeTable");
table.Rows.Add(8, "Staff Att", 3, "/Staff/StaffAtt");
table.Rows.Add(9, "Book Issue", 4, "/Library/BookIssue");
table.Rows.Add(10, "Book Return", 4, "/Library/BookReturn");
table.Rows.Add(12, "Fee Payment", 11, "/Library/BookFine/FeePayment");
table.Rows.Add(11, "Book Fine", 4, "/Library/BookFine");

Dictionary<int, MenuItem> dict =
    table.Rows.Cast<DataRow>()
              .Select(r => new MenuItem
              {
                  Id = r.Field<int>("ResourceId"),
                  ParentId = r.Field<int>("ParentId"),
                  DisplayName = r.Field<string>("DisplayName"),
                  Url = r.Field<string>("Url")
              })
             .ToDictionary(m => m.Id);

然后循環遍歷字典,並為每個菜單項查找其父項並將該項添加到父項的子項中。 如果項目沒有父項(其ParentId0 ),則將該項目添加到根菜單項列表中。 它只需要通過字典一次就能以這種方式構建層次結構。

List<MenuItem> rootMenu = new List<MenuItem>();

foreach (var kvp in dict)
{
    List<MenuItem> menu = rootMenu;
    MenuItem item = kvp.Value;
    if (item.ParentId > 0)
    {
        menu = dict[item.ParentId].SubMenu;
    }
    menu.Add(item);
}

既然我們已經擁有了層次結構,那么使用Json.Net對它進行序列化是微不足道的。 (注意, MenuItem類中的[JsonIgnore]屬性會阻止將IdParentId值添加到JSON中。)

string json = JsonConvert.SerializeObject(rootMenu, Formatting.Indented);
Console.WriteLine(json);

這是上面代碼生成的最終JSON:

[
  {
    "DisplayName": "Home",
    "Url": "/Home",
    "SubMenu": [
      {
        "DisplayName": "TimeTable",
        "Url": "/Home/TimeTable",
        "SubMenu": []
      }
    ]
  },
  {
    "DisplayName": "Student",
    "Url": "/Student",
    "SubMenu": [
      {
        "DisplayName": "StudentAtt",
        "Url": "/Student/StudentAtt",
        "SubMenu": []
      }
    ]
  },
  {
    "DisplayName": "Staff",
    "Url": "/Staff",
    "SubMenu": [
      {
        "DisplayName": "Staff Att",
        "Url": "/Staff/StaffAtt",
        "SubMenu": []
      }
    ]
  },
  {
    "DisplayName": "Library",
    "Url": "/Library",
    "SubMenu": [
      {
        "DisplayName": "Book Issue",
        "Url": "/Library/BookIssue",
        "SubMenu": []
      },
      {
        "DisplayName": "Book Return",
        "Url": "/Library/BookReturn",
        "SubMenu": []
      },
      {
        "DisplayName": "Book Fine",
        "Url": "/Library/BookFine",
        "SubMenu": [
          {
            "DisplayName": "Fee Payment",
            "Url": "/Library/BookFine/FeePayment",
            "SubMenu": []
          }
        ]
      }
    ]
  }
]

暫無
暫無

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

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