按字段值对数组内的JObject进行排序

时间:2018-11-15 19:29:35

标签: c# json sorting json.net

我有一个如下所示的JSON字符串:

{
  "MetaData": {
    "ResourcesUsed": 1
  },
  "Result": [
    {
      "locations": [
        {
          "country": "Papua New Guinea",
          "city": "Jacquinot Bay",
          "locTypeAttributes": {
            "localDate": "2018-10-08T04:21:00-07:00",
            "utcDate": "2018-10-08T04:21:00-07:00",
          },
          "point": {
            "coordinates": [
              151.52,
              -5.6
            ],
            "type": "Point"
          }
        },{
          "country": "Papua New Guinea2",
          "city": "Jacquinot Bay2",
          "locTypeAttributes": {
            "localDate": "2018-10-08T04:21:00-07:00",
            "utcDate": "2018-10-02T04:21:00-07:00",
          },
          "point": {
            "coordinates": [
              151.52,
              -5.6
            ],
            "type": "Point"
          }
        }
      ]
    }
  ]
}

我使用Newtonsoft将其转换为JSON对象。我想要做的是按嵌套在每个locations项目中的Result字段对utcDate数组中的locations数组进行排序。我发现以下线程:C# Sort JSON string keys。但是,由于我的对象内部有数组,因此我仍然无法实现它,而该问题仅涉及按属性名称按字母顺序对对象内部的对象进行排序。

这是我到目前为止编写的一段代码:

public string GenerateJson()
{
     var model = (JObject)JsonConvert.DeserializeObject(data);
     Sort(model);
}
private void Sort(JObject jObj)
{
    var props = jObj["Result"][0]["locations"].ToList();
    foreach (var prop in props)
    {
        prop.Remove();
    }

    foreach (var prop in props.OrderBy(p => p.Name))
    {
        jObj.Add(prop);
        if (prop.Value is JObject)
            Sort((JObject)prop.Value);
        if (prop.Value is JArray)
        {
            Int32 iCount = prop.Value.Count();
            for (Int32 iIterator = 0; iIterator < iCount; iIterator++)
                if (prop.Value[iIterator] is JObject)
                    Sort((JObject)prop.Value[iIterator]);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您可以使用LINQ对每个单独的"Result[*].locations"数组进行排序,如下所示:

// Load the JSON without parsing or converting any dates.
var model = JsonConvert.DeserializeObject<JObject>(data, new JsonSerializerSettings{ DateParseHandling = DateParseHandling.None });

// Construct a serializer that converts all DateTime values to UTC
var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings{ DateTimeZoneHandling = DateTimeZoneHandling.Utc });

foreach (var locations in model.SelectTokens("Result[*].locations").OfType<JArray>())
{
    // Then sort the locations by utcDate converting the value to UTC at this time.
    var query = from location in locations
                let utcDate = location.SelectToken("locTypeAttributes.utcDate").ToObject<DateTime>(serializer)
                orderby utcDate
                select location;
    locations.ReplaceAll(query.ToList());
}

注意:

  • 最初使用DateParseHandling.None加载JSON,以防止将"localDate""utcDate"字符串过早地解释为具有统一{{3} }。

    (有关Json.NET如何解释类​​似于日期的字符串的讨论,请参见 DateTime.Kind 。)

  • 然后,我们使用Serializing Dates in JSON遍历所有DateTime数组,其中"locations"SelectTokens("Result[*].locations")通配符,选择[*]数组中的所有条目

  • 然后通过将嵌套的"Results"反序列化为UTC日期,然后使用LINQ进行排序,对每个"locations"数组进行排序。

  • 最后使用JSONPath更新数组。

  • 如果缺少任何locTypeAttributes.utcDate属性,则将引发异常。如果可能,您可以反序列化为locTypeAttributes.utcDate

工作示例.Net小提琴JArray.ReplaceAll()