将平面JSON数组转换为嵌套JSON的通用方法

时间:2017-05-12 15:09:32

标签: c# arrays json generics

我有一个JSON对象,如下所示

[
  {
    "Id": 7,
    "Name": "Colocation Folder",
    "ParentId": 1,
    "depth": 0
  },
  {
    "Id": 8,
    "Name": "CoLo Real Estate",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 10,
    "Name": "CoLo: Burst",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 34,
    "Name": "CoLo Dedicated Bandwidth",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 10035,
    "Name": "Infrastructure as a Service",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 10037,
    "Name": "Software as a Service",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 10038,
    "Name": "IaaS Component Upgrade",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 668,
    "Name": "CoLo Misc Folder",
    "ParentId": 7,
    "depth": 1
  },
  {
    "Id": 758,
    "Name": "CoLo: Conduit Fee",
    "ParentId": 668,
    "depth": 2
  },
  {
    "Id": 765,
    "Name": "CoLo: Private VLAN",
    "ParentId": 668,
    "depth": 2
  }
]

IdParentId字段显示项目之间的关系。我需要使用C#将其作为嵌套的JSON。 由于会有很多这样的模型,我不想为每个模型创建单独的类。在C#中是否存在采用平面JSON数组的通用方法,将IDParentId字段作为输入,然后返回一个嵌套的JSON以及数组中的所有其他字段?例如,我正在寻找嵌套JSON的输出,如下所示:

[
  {
    "Id": 7,
    "Name": "Colocation Folder",
    "items": [
      {
        "Id": 8,
        "Name": "CoLo Real Estate",
        "ParentId": 7
      },
      {
        "Id": 10,
        "Name": "CoLo: Burst",
        "ParentId": 7
      },
      {
        "Id": 34,
        "Name": "CoLo Dedicated Bandwidth",
        "ParentId": 7
      },
      {
        "Id": 10035,
        "Name": "Infrastructure as a Service",
        "ParentId": 7
      },
      {
        "Id": 10037,
        "Name": "Software as a Service",
        "ParentId": 7
      },
      {
        "Id": 10038,
        "Name": "IaaS Component Upgrade",
        "ParentId": 7
      },
      {
        "Id": 668,
        "Name": "CoLo Misc Folder",
        "ParentId": 7,
        "items": [
          {
            "Id": 758,
            "Name": "CoLo: Conduit Fee",
            "ParentId": 668
          },
          {
            "Id": 765,
            "Name": "CoLo: Private VLAN",
            "ParentId": 668
          }
        ]
      }
    ]
  }
]

3 个答案:

答案 0 :(得分:0)

如果您使用Json.Net,则可以使用LINQ-to-JSON API(JObjects)以通用方式执行此转换。我们的想法是解析JSON数组并将所有单独的项添加到由Id键入的字典中。然后,循环遍历字典项,并为每个项目尝试查找父项。如果找到父项,请将项添加到父项items数组中(如果需要,可以创建它)。否则,将项添加到root数组。在此过程中,从每个项目中删除depth属性,因为您似乎不希望在输出中使用该属性。最后,只需将root数组转储到字符串即可获得最终结果。

var dict = JArray.Parse(json)
    .Children<JObject>()
    .ToDictionary(jo => (string)jo["Id"], jo => new JObject(jo));

var root = new JArray();

foreach (JObject obj in dict.Values)
{
    JObject parent;
    string parentId = (string)obj["ParentId"];
    if (parentId != null && dict.TryGetValue(parentId, out parent))
    {
        JArray items = (JArray)parent["items"];
        if (items == null)
        {
            items = new JArray();
            parent.Add("items", items);
        }
        items.Add(obj);
    }
    else
    {
        root.Add(obj);
    }

    JProperty depth = obj.Property("depth");
    if (depth != null) depth.Remove();
}

Console.WriteLine(root.ToString());

小提琴:https://dotnetfiddle.net/Buza6T

答案 1 :(得分:0)

您可以使用JSON.Net这样的动态对象来动态检测您的属性,然后您可以使用所需的嵌套构建一个新的json对象:                 使用Newtonsoft.Json;                 使用Newtonsoft.Json.Linq;

            dynamic d = JArray.Parse(stringy);
            foreach(var ob in d)
            {
                if(ob.ParentID != ob.Id)
                {
                    string debug = "oh snapple, it's a child object";
                }
            }

答案 2 :(得分:0)

jsFiddle full source code上为您分享我的工作代码

递归函数是:

  function getNestedChildren(arr, parent) {
var out = []
for(var i in arr) {
    if(arr[i].parent == parent) {
        var children = getNestedChildren(arr, arr[i].id)

        if(children.length) {
            arr[i].children = children
        }
        out.push(arr[i])
    }
  }
 return out
}

完整的源代码:

        function getNestedChildren(arr, parent) {
        var out = []
        for(var i in arr) {
            if(arr[i].ParentId == parent) {
                var items = getNestedChildren(arr, arr[i].Id)

                if(items.length) {
                    arr[i].items = items
                }
                out.push(arr[i])
            }
        }
        return out
    }


    var flat_array = [
      {
        "Id": 7,
        "Name": "Colocation Folder",
        "ParentId": 1,
        "depth": 0
      },
      {
        "Id": 8,
        "Name": "CoLo Real Estate",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 10,
        "Name": "CoLo: Burst",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 34,
        "Name": "CoLo Dedicated Bandwidth",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 10035,
        "Name": "Infrastructure as a Service",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 10037,
        "Name": "Software as a Service",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 10038,
        "Name": "IaaS Component Upgrade",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 668,
        "Name": "CoLo Misc Folder",
        "ParentId": 7,
        "depth": 1
      },
      {
        "Id": 758,
        "Name": "CoLo: Conduit Fee",
        "ParentId": 668,
        "depth": 2
      },
      {
        "Id": 765,
        "Name": "CoLo: Private VLAN",
        "ParentId": 668,
        "depth": 2
      }
    ]


    var nested = getNestedChildren(flat_array, 1)

    console.log(nested)