【问题标题】:Generic method to convert a flat JSON array to nested JSON将平面 JSON 数组转换为嵌套 JSON 的通用方法
【发布时间】:2017-10-11 23:14:31
【问题描述】:

我有一个如下的 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
          }
        ]
      }
    ]
  }
]

【问题讨论】:

  • 举一个你想要的结果的例子。目前尚不清楚您要做什么。
  • 我已经编辑了我的问题以显示所需的结果。谢谢
  • 在您的示例 JSON 中,为什么根对象有 ParentId1?那是指什么?
  • Brian - 这基本上意味着它有一个父级,这里没有显示。基本上,这就像树中的一个分支。我只希望基于 ParentId 嵌套子项

标签: c# arrays json generics


【解决方案1】:

如果您使用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

【讨论】:

  • Brian - 当 ParentId 可用但当 ParentId 为 null 时代码有效,我得到一个异常不能将 Null 转换为 Int32。因此我将字典更改为 object 而不是 int var dict = JArray.Parse(JSONString) .Children() .ToDictionary(jo => (object)jo[IdFieldName], jo => new JObject(jo)) ;
  • 我添加了一个修复程序,在尝试使用之前检查 ParentId 是否有值。
  • 在这种情况下,我只会制作字典键字符串。它也适用于整数。
【解决方案2】:

您可以像这样在 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";
                }
            }

【讨论】:

    【解决方案3】:

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-29
      • 2017-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多