使用嵌套的动态 属性 名称反序列化 JSON
Deserializing a JSON with nested dynamic property names
我正在尝试反序列化由外部 REST API 提供的非常丑陋的 JSON,并且想知道“正确”的方法(我正在使用 System.Text.Json 在 .net 6) 中。详情如下:
我有一个数据模型:
class DeviceData{
//lots of properties
}
在对单个实例进行 API 查询时工作正常(即我可以 JsonSerializer.Deserialize<DeviceData>
响应),因为它 returns 一个很好的 JSON预计:
{
"property1_name": value,
"property2_name": value,
...
}
当我使用 API 提供的批处理查询时,问题就开始了,因为对 api_url/batch?=device1,device2,...
的响应看起来好像有人未能创建数组(设备 1 是从 a 中拉出的字母数字字符串数据库)是:
{
"names":[
"device1",
"device2",
...
],
"device1":{
"stuff_i_dont_need": value,
"device1": {
"property1_name": value,
"property2_name": value,
...
}
}
"device2":{
...
}
...
}
动态 属性 名称的双重嵌套意味着我不能将第二个响应反序列化为 <string, myclass>
对的字典。我设法使用 JsonDocument 破解了一些东西,但它非常丑陋,感觉应该有一个很好的简短方法来做到这一点,只需要 JsonSerializer 和一些 reader 覆盖。
使用反序列化 How to use a JSON document, Utf8JsonReader, and Utf8JsonWriter in System.Text.Json 中 JSON 有效负载 的子部分作为模板,您可以执行如下操作:
JsonNode root = JsonNode.Parse(json)!;
Dictionary<string, X> devices = new();
foreach(string name in root["names"]!.AsArray()) {
var o = root[name][name].AsObject();
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
o.WriteTo(writer);
writer.Flush();
X? x = JsonSerializer.Deserialize<X>(stream.ToArray());
var innerJson = root[name][name].ToJsonString();
devices[name] = x;
}
foreach(var d in devices) Console.WriteLine($"{d.Key}: {d.Value}");
这会打印
device1: X { property1_name = 12, property2_name = 13 }
device2: X { property1_name = 22, property2_name = 23 }
我不确定这是 faster/better 还是调用 ToJsonString()
:
JsonNode root = JsonNode.Parse(json)!;
Dictionary<string, X> devices = new();
foreach(string name in root["names"]!.AsArray()) {
var innerJson = root[name][name].ToJsonString();
devices[name] = JsonSerializer.Deserialize<X>(innerJson);
}
foreach(var d in devices) Console.WriteLine($"{d.Key}: {d.Value}")
如果你喜欢,你可以使用完整的 LINQ:
JsonNode root = JsonNode.Parse(json)!;
Dictionary<string, X> devices = root["names"]!.AsArray()
.Select(name => (string)name)
.ToDictionary(
keySelector: name => name,
elementSelector: name => System.Text.Json.JsonSerializer.Deserialize<X>(root[name][name].ToJsonString()));
foreach(var d in devices) Console.WriteLine($"{d.Key}: {d.Value}");
同时打印
我正在尝试反序列化由外部 REST API 提供的非常丑陋的 JSON,并且想知道“正确”的方法(我正在使用 System.Text.Json 在 .net 6) 中。详情如下:
我有一个数据模型:
class DeviceData{
//lots of properties
}
在对单个实例进行 API 查询时工作正常(即我可以 JsonSerializer.Deserialize<DeviceData>
响应),因为它 returns 一个很好的 JSON预计:
{
"property1_name": value,
"property2_name": value,
...
}
当我使用 API 提供的批处理查询时,问题就开始了,因为对 api_url/batch?=device1,device2,...
的响应看起来好像有人未能创建数组(设备 1 是从 a 中拉出的字母数字字符串数据库)是:
{
"names":[
"device1",
"device2",
...
],
"device1":{
"stuff_i_dont_need": value,
"device1": {
"property1_name": value,
"property2_name": value,
...
}
}
"device2":{
...
}
...
}
动态 属性 名称的双重嵌套意味着我不能将第二个响应反序列化为 <string, myclass>
对的字典。我设法使用 JsonDocument 破解了一些东西,但它非常丑陋,感觉应该有一个很好的简短方法来做到这一点,只需要 JsonSerializer 和一些 reader 覆盖。
使用反序列化 How to use a JSON document, Utf8JsonReader, and Utf8JsonWriter in System.Text.Json 中 JSON 有效负载 的子部分作为模板,您可以执行如下操作:
JsonNode root = JsonNode.Parse(json)!;
Dictionary<string, X> devices = new();
foreach(string name in root["names"]!.AsArray()) {
var o = root[name][name].AsObject();
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
o.WriteTo(writer);
writer.Flush();
X? x = JsonSerializer.Deserialize<X>(stream.ToArray());
var innerJson = root[name][name].ToJsonString();
devices[name] = x;
}
foreach(var d in devices) Console.WriteLine($"{d.Key}: {d.Value}");
这会打印
device1: X { property1_name = 12, property2_name = 13 }
device2: X { property1_name = 22, property2_name = 23 }
我不确定这是 faster/better 还是调用 ToJsonString()
:
JsonNode root = JsonNode.Parse(json)!;
Dictionary<string, X> devices = new();
foreach(string name in root["names"]!.AsArray()) {
var innerJson = root[name][name].ToJsonString();
devices[name] = JsonSerializer.Deserialize<X>(innerJson);
}
foreach(var d in devices) Console.WriteLine($"{d.Key}: {d.Value}")
如果你喜欢,你可以使用完整的 LINQ:
JsonNode root = JsonNode.Parse(json)!;
Dictionary<string, X> devices = root["names"]!.AsArray()
.Select(name => (string)name)
.ToDictionary(
keySelector: name => name,
elementSelector: name => System.Text.Json.JsonSerializer.Deserialize<X>(root[name][name].ToJsonString()));
foreach(var d in devices) Console.WriteLine($"{d.Key}: {d.Value}");
同时打印