如何使用 Newtonsoft.Json 将复杂的 json 响应反序列化为易于反序列化的结构?
How can I deserialize complex json repsonse into easy-to-deserialize structure using Newtonsoft.Json?
出现这种看起来很奇怪的 json 回复:
{
"invoices":{
"0":{
"invoice":{
"id":"420",
"invoicecontents":{
"0":{
"invoicecontent":{
"name":"Here's the name of the content 0"
}
},
"1":{
"invoicecontent":{
"name":"Here's the name of the content 1"
}
}
}
}
},
"1":{
"invoice":{
"id":"420",
"invoicecontents":{
"0":{
"invoicecontent":{
"name":"Here's the name of the content 0"
}
}
}
}
},
"parameters":{
"limit":"3",
"page":"1",
"total":"420"
}
},
"status":{
"code":"OK"
}
}
如何将结构更改为这种易于反序列化的结构?
{
"invoices":[
{
"id":"420",
"invoicecontents":[
{
"name":"Here's the name of the content 0"
},
{
"name":"Here's the name of the content 1"
}
]
},
{
"id":"420",
"invoicecontents":[
{
"name":"Here's the name of the content 0"
}
]
}
]
}
我想反序列化为如下发票列表
class Invoice {
public string Id { get; set; }
[JsonProperty("invoicecontents")]
public InvoiceContent[] Contents { get; set; }
class InvoiceContent {
public string Name { get; set; }
}
}
获取状态码或者参数都没有问题,我就这么干:
var parsed = JObject.Parse(jsonInvoices);
var statusCode = parsed?["status"]?["code"]?.ToString();
var parameters = parsed?["invoices"]?["parameters"]?;
当我试图实现我之前提到的易于反序列化的 json 结构时,真正的问题就出现了。我试过这样的事情:
var testInvoices = parsed?["invoices"]?
.SkipLast(1)
.Select(x => x.First?["invoice"]);
但我无法设法“修复”invoicecontents/invoicecontent 零件。
我的目标是反序列化和存储数据。
试试这个
var jsonParsed = JObject.Parse(json);
var invoices = ((JObject) jsonParsed["invoices"]).Properties()
.Select(x => (JObject) x.Value["invoice"] ).Where(x => x != null)
.Select(s => new Invoice
{
Id = s.Properties().First(x => x.Name == "id").Value.ToString(),
Contents = ((JObject)s.Properties().First(x => x.Name == "invoicecontents").Value).Properties()
.Select(x => (string) x.Value["invoicecontent"]["name"]).ToList()
}).ToList();
我也简化了你的 class,我认为用一个字符串保留 classes 数组没有任何意义,我认为它应该只是字符串数组
public class Invoice
{
public string Id { get; set; }
public List<string> Contents { get; set; }
}
结果
[
{
"Id": "420",
"Contents": [
"Here's the name of the content 0",
"Here's the name of the content 1"
]
},
{
"Id": "420",
"Contents": [
"Here's the name of the content 0"
]
}
]
这不是 JSON。
JavaScript Object Notation 从字面上描述了 Objects。你在这里看到的是一个笑话的妙语,开头是:“一个 SQL JOIN、一个 StringBuilder 和几个 for 循环走进酒吧......”
正如其他人所证明的那样,JObject 非常适合与 JSON 一起工作,而将其定义为 类 是不切实际的。您可以使用 Linq 来浏览它,但 JSON路径表达式 可以简单得多。
示例 1:让我们获取状态码。
var status = parsed.SelectToken(".status.code").Value<string>();
示例 2:我们 'deserialize' 我们的发票。
public string Invoice
{
public string Id { get; set; }
public List<string> Content { get; set; }
}
public List<Invoice> GetInvoices(string badJson)
{
var invoices = JObject.Parse(badJson).SelectTokens(".invoices.*.invoice");
var results = new List<Invoice>();
foreach (var invoice in invoices)
{
results.Add(new Invoice()
{
Id = invoice.Value<string>("id"),
Contents = invoice.SelectTokens(".invoicecontents.*.invoicecontent.name")
.Values<string>().ToList()
// Note: JToken.Value<T> & .Values<T>() return nullable types
});
}
return results;
}
出现这种看起来很奇怪的 json 回复:
{
"invoices":{
"0":{
"invoice":{
"id":"420",
"invoicecontents":{
"0":{
"invoicecontent":{
"name":"Here's the name of the content 0"
}
},
"1":{
"invoicecontent":{
"name":"Here's the name of the content 1"
}
}
}
}
},
"1":{
"invoice":{
"id":"420",
"invoicecontents":{
"0":{
"invoicecontent":{
"name":"Here's the name of the content 0"
}
}
}
}
},
"parameters":{
"limit":"3",
"page":"1",
"total":"420"
}
},
"status":{
"code":"OK"
}
}
如何将结构更改为这种易于反序列化的结构?
{
"invoices":[
{
"id":"420",
"invoicecontents":[
{
"name":"Here's the name of the content 0"
},
{
"name":"Here's the name of the content 1"
}
]
},
{
"id":"420",
"invoicecontents":[
{
"name":"Here's the name of the content 0"
}
]
}
]
}
我想反序列化为如下发票列表
class Invoice {
public string Id { get; set; }
[JsonProperty("invoicecontents")]
public InvoiceContent[] Contents { get; set; }
class InvoiceContent {
public string Name { get; set; }
}
}
获取状态码或者参数都没有问题,我就这么干:
var parsed = JObject.Parse(jsonInvoices);
var statusCode = parsed?["status"]?["code"]?.ToString();
var parameters = parsed?["invoices"]?["parameters"]?;
当我试图实现我之前提到的易于反序列化的 json 结构时,真正的问题就出现了。我试过这样的事情:
var testInvoices = parsed?["invoices"]?
.SkipLast(1)
.Select(x => x.First?["invoice"]);
但我无法设法“修复”invoicecontents/invoicecontent 零件。 我的目标是反序列化和存储数据。
试试这个
var jsonParsed = JObject.Parse(json);
var invoices = ((JObject) jsonParsed["invoices"]).Properties()
.Select(x => (JObject) x.Value["invoice"] ).Where(x => x != null)
.Select(s => new Invoice
{
Id = s.Properties().First(x => x.Name == "id").Value.ToString(),
Contents = ((JObject)s.Properties().First(x => x.Name == "invoicecontents").Value).Properties()
.Select(x => (string) x.Value["invoicecontent"]["name"]).ToList()
}).ToList();
我也简化了你的 class,我认为用一个字符串保留 classes 数组没有任何意义,我认为它应该只是字符串数组
public class Invoice
{
public string Id { get; set; }
public List<string> Contents { get; set; }
}
结果
[
{
"Id": "420",
"Contents": [
"Here's the name of the content 0",
"Here's the name of the content 1"
]
},
{
"Id": "420",
"Contents": [
"Here's the name of the content 0"
]
}
]
这不是 JSON。
JavaScript Object Notation 从字面上描述了 Objects。你在这里看到的是一个笑话的妙语,开头是:“一个 SQL JOIN、一个 StringBuilder 和几个 for 循环走进酒吧......”
正如其他人所证明的那样,JObject 非常适合与 JSON 一起工作,而将其定义为 类 是不切实际的。您可以使用 Linq 来浏览它,但 JSON路径表达式 可以简单得多。
示例 1:让我们获取状态码。
var status = parsed.SelectToken(".status.code").Value<string>();
示例 2:我们 'deserialize' 我们的发票。
public string Invoice
{
public string Id { get; set; }
public List<string> Content { get; set; }
}
public List<Invoice> GetInvoices(string badJson)
{
var invoices = JObject.Parse(badJson).SelectTokens(".invoices.*.invoice");
var results = new List<Invoice>();
foreach (var invoice in invoices)
{
results.Add(new Invoice()
{
Id = invoice.Value<string>("id"),
Contents = invoice.SelectTokens(".invoicecontents.*.invoicecontent.name")
.Values<string>().ToList()
// Note: JToken.Value<T> & .Values<T>() return nullable types
});
}
return results;
}