使用 LINQ 查询嵌套 JSON

Query nested JSON with LINQ

我有以下 JSON:

{
  "rooms": [
    {
      "roomId": 1,
      "lightsPreset": [
        {
          "lightsPresetId": 1,
          "loadValues": [ 1, 2, 3 ]
        }, 
        {
          "lightsPresetId": 2,
          "loadValues": [ 11, 12, 13 ]
        }]
    },
    {
      "roomId": 2,
      "lightsPreset": [
        {
          "lightsPresetId": 1,
          "loadValues": [ 21, 22, 23 ]
        }, 
        {
          "lightsPresetId": 2,
          "loadValues": [ 211, 212, 213 ]
        }]
    }
  ]
}

我需要从中获取 loadValues(比如 roomId = 1 和 lightsPresetId = 1)

我设法使用 JSONPath

做到了
IEnumerable<JToken> loadValues = o.SelectTokens("$.rooms[?(@.roomId == 1)].lightsPreset[?(@.lightsPresetId == 1)].loadValues[*]"); 

但我的目标是让它在 .Net Framework 3.5 中工作,其中 JSONPath 不起作用。

使用 LINQ 尝试此操作为我提供了 roomId = 1 的所有内容,但我不知道如何查询嵌套数组。

JObject o = JObject.Parse(rawJson);
var itemList = from values in o["rooms"].Children()
where (decimal)values["roomId"] == 1
select values;

谢谢。

试试这个

var rooms = (JArray) JObject.Parse(json)["rooms"]; 

var roomId=1;
var lightsPresetId =1;

int[] values = rooms.Where(r => (int)r["roomId"] == roomId)
    .Select(r=> r["lightsPreset"]).FirstOrDefault() 
    .FirstOrDefault(x => (int)x["lightsPresetId"] == lightsPresetId)["loadValues"]
    .ToObject<int[]>().ToArray();

现在在 PC 上,所以我可以 post 将其作为答案而不是来自 phone

的评论

如果您访问 https://quicktype.io,您可以使用它从您的 JSON:

生成 类
// <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
//    using SomeNamespace;
//
//    var someRootClassName = SomeRootClassName.FromJson(jsonString);

namespace SomeNamespace
{
    using System;
    using System.Collections.Generic;

    using System.Globalization;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;

    public partial class SomeRootClassName
    {
        [JsonProperty("rooms")]
        public List<Room> Rooms { get; set; }
    }

    public partial class Room
    {
        [JsonProperty("roomId")]
        public long RoomId { get; set; }

        [JsonProperty("lightsPreset")]
        public List<LightsPreset> LightsPresets { get; set; }
    }

    public partial class LightsPreset
    {
        [JsonProperty("lightsPresetId")]
        public long LightsPresetId { get; set; }

        [JsonProperty("loadValues")]
        public List<long> LoadValues { get; set; }
    }

    public partial class SomeRootClassName
    {
        public static SomeRootClassName FromJson(string json) => JsonConvert.DeserializeObject<SomeRootClassName>(json, SomeNamespace.Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this SomeRootClassName self) => JsonConvert.SerializeObject(self, SomeNamespace.Converter.Settings);
    }

    internal static class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters =
            {
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
            },
        };
    }
}

然后您可以将 JSON 转换为这样的对象:

var root = SomeRootClassName.FromJson(rawJson);

你可以这样查询:

var array = root.Rooms.First(r => r.RoomId == 1).LightsPresets.First(lp => lp.LightsPresetId == 1).LoadValues;

或者如果这些 ID 可能不存在:

var array = root.Rooms.FirstOrDefault(r => r.RoomId == 1)?.LightsPresets.First(lp => lp.LightsPresetId == 1)?.LoadValues;
if(array != null) ....

在使用 LINQ 时,确保 collection/array 的任何名称都具有复数名称会有所帮助。然后你可以很容易地知道你是否可以只访问它的 属性 (如果它是单数)或者必须使用一些方法,如 First、Last、Single、Any、Where 等,如果它有一个复数名称:

root.Rooms                             //plural, collection
  .First(r => r.RoomId == 1)           //.First on a plural results in a singular, a room object
  .LightsPresets                       //access a plural property of the single room above
  .First(lp => lp.LightsPresetId == 1) //first lightpresent in many LightPresets in the room
  .LoadValues                          //plural again; it's an array. The LINQ query resolves to an array output

也给你的 lambda 参数起个合理的名字——不要对所有东西都使用 x;我使用 r 表示“房间集合中的一个房间”,lp 表示“lightpresets 集合中的一个 lightpreset”