在C#中将嵌套JSON递归转换为平面数组

时间:2019-05-01 20:37:57

标签: c# json recursion json.net

我有一个看起来像这样的JSON:

[  
   {  
      "type":"car",
      "types":[  
         {  
            "type":"ferrari",
            "types":[  
               {  
                  "type":"big",
                  "count":5
               },
               {  
                  "type":"small",
                  "count":1
               }
            ]
         },
         {  
            "type":"volvo",
            "types":[  
               {  
                  "type":"big",
                  "count":2
               }
            ]
         }
      ]
   },
   {  
      "type":"bike",
      "types":[  
         {  
            "type":"Ducati",
            "types":[  
               {  
                  "type":"small",
                  "count":1
               }
            ]
         }
      ]
   }
]

这就像一个“分组依据”,但嵌套在一起。我想将其转换为不嵌套的。 像这样:

[  
   {  
      "types":[ "car", "ferrari", "big" ],
      "count":5
   },
   {  
      "types":[ "car", "ferrari", "small" ],
      "count":1
   },
   {  
      "types":[ "car", "volvo", "big" ],
      "count":2
   },
   {  
      "types":[ "bike", "ducati", "small" ],
      "count":1
   }
]

由于它是一个递归函数,所以我陷入了困境,但是由于我需要为每个组合创建一个JObject而变得很复杂。实际上更加复杂,因为我不知道答案的嵌套程度。我知道没有types属性时要停下来。  我正在尝试使用JObjects来做到这一点。

2 个答案:

答案 0 :(得分:4)

这是我的处理方式:

  1. 将JSON解析为JArray,然后将SelectTokens与递归下降操作符..一起使用以查找所有count令牌。每个对象都有一个结果对象。

  2. 创建一个新的JArray来容纳结果对象。

  3. 对于每个count令牌:

    a)沿着祖先链走,从每个级别的type收集JObject值到新的JArray中。 (您将需要颠倒它们的顺序,以便它们从上到下而不是从下到上出现在数组中。)

    b)将计数和类型数组组装到新的JObject中,并将其添加到结果数组中。

  4. 最后,将结果JArray转换回JSON字符串。

这是代码中的样子:

var counts = JArray.Parse(json).SelectTokens("..count");
var array = new JArray();

foreach (var count in counts)
{
    var types = count.Ancestors()
                     .OfType<JObject>()
                     .Select(o => (string)o["type"])
                     .Reverse();

    var result = new JObject(
        new JProperty("types", new JArray(types)),
        new JProperty("count", count)
    );

    array.Add(result);
}

json = array.ToString();

此处的工作演示:https://dotnetfiddle.net/uI2Bzt

如果您喜欢简洁的代码,则可以在“一行”中完成所有操作:

json = new JArray(
    JArray.Parse(json)
          .SelectTokens("..count")
          .Select(c =>
              new JObject(
                  new JProperty("types",
                      new JArray(
                          c.Ancestors()
                           .OfType<JObject>()
                           .Select(o => (string)o["type"])
                           .Reverse()
                      )
                  ),
                  new JProperty("count", c)
              )
          )
).ToString();

提琴:https://dotnetfiddle.net/jltZU5

答案 1 :(得分:0)

首先,您的json无效。

这是有效的:

[
   {
      "type":"car",
      "types":[
         {
            "type":"volvo",
            "types":[
               {
                  "type":"big",
                  "count":2
               }
            ]
         }
      ]
   },
   {
      "type":"bike",
      "types":[
         {
            "type":"Ducati",
            "types":[
               {
                  "type":"small",
                  "count":1
               }
            ]
         }
      ]
   }
]

使用Json.NET将对象反序列化为此类:

public class MasterClass
{
    public TypesClass[] Property1 { get; set; }
}

public class TypesClass
{
    public string type { get; set; }
    public Type[] types { get; set; }
}

public class Type
{
    public string type { get; set; }
    public Types[] types { get; set; }
}

public class Types
{
    public string type { get; set; }
    public int count { get; set; }
}

反序列化:

DataSet dsSalesOrders = JsonConvert.DeserializeObject<DataSet>(response.Content);

然后使用LINQ,您可以在每个子集上使用SelectMany将其添加到结果中。