使用 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”
我有以下 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”