使用 newtonsoft 反序列化 JSON Object/Array 时出错
Error Deserializing JSON Object/Array using newtonsoft
我有一个 json 字符串,其中包含以下数据
"air:FlightOptionsList": {
"air:FlightOption": [{
"LegRef": "hx5kk+3R2BKABGzqAAAAAA==",
"Destination": "LHE",
"Origin": "DXB",
"air:Option": {
"Key": "hx5kk+3R2BKA/FzqAAAAAA==",
"TravelTime": "P0DT3H0M0S",
"air:BookingInfo": {
"BookingCode": "I",
"BookingCount": "7",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKAzFzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAtFzqAAAAAA=="
}
}
}, {
"LegRef": "hx5kk+3R2BKAFGzqAAAAAA==",
"Destination": "DXB",
"Origin": "LHE",
"air:Option": {
"Key": "hx5kk+3R2BKACGzqAAAAAA==",
"TravelTime": "P0DT11H30M0S",
"air:BookingInfo": [{
"BookingCode": "U",
"BookingCount": "7",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAvFzqAAAAAA=="
}, {
"BookingCode": "Y",
"BookingCount": "9",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAxFzqAAAAAA=="
}
],
"air:Connection": {
"SegmentIndex": "0"
}
}
}
]
}
我的Class结构如下:
public class FlightOptionsList
{
public List<FlightOption> FlightOption { get; set; }
}
public class FlightOption
{
public string LegRef { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
public Option Option { get; set; }
}
public class Option
{
public string Key { get; set; }
public string TravelTime { get; set; }
public List<BookingInfo> BookingInfo { get; set; }
public Connection Connection { get; set; }
}
public class BookingInfo
{
public string BookingCode { get; set; }
public string BookingCount { get; set; }
public string CabinClass { get; set; }
public string FareInfoRef { get; set; }
public string SegmentRef { get; set; }
}
我想反序列化它,但它给我一个错误如下:
无法将当前 JSON 对象(例如 {"name":"value"})反序列化为类型 'System.Collections.Generic.List`1[ParseSoapEnveloperReqRes.BookingInfo]',因为该类型需要 JSON 数组(例如 [1,2,3])以正确反序列化。
要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,使其成为普通的 .NET 类型(例如,不是原始类型像整数,而不是像数组或列表这样的集合类型),可以从 JSON 对象反序列化。 JsonObjectAttribute 也可以添加到类型以强制它从 JSON 对象反序列化。
路径 'FlightOptionsList.FlightOption[0].Option.BookingInfo.BookingCode',第 394 行,位置 59。
这是因为,就像您看到 json 字符串一样,FlightOptionsList.FlightOption[0].Option.BookingInfo 是一个 object 但在 FlightOptionsList.FlightOption[1].Option.BookingInfo 中是一个 array,如您所见。
如何设置这个问题...我正在使用以下代码将 json 字符串反序列化为 class 对象
var AirTravelResultModel = JsonConvert.DeserializeObject<AirTravelResultModel>(xmlInputData);
查看 Camilo Martinez 对此讨论的回答:
Deserializing JSON when sometimes array and sometimes object
基本上,您需要将 JsonConverter
属性添加到 BookingInfo
属性 并在 JsonConverter
实现中处理转换。
public class FlightOptionsList
{
public List<FlightOption> FlightOption { get; set; }
}
public class FlightOption
{
public string LegRef { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
public Option Option { get; set; }
}
public class Option
{
public string Key { get; set; }
public string TravelTime { get; set; }
[JsonConverter(typeof(SingleValueArrayConverter<BookingInfo>))]
public List<BookingInfo> BookingInfo { get; set; }
public Connection Connection { get; set; }
}
public class BookingInfo
{
public string BookingCode { get; set; }
public string BookingCount { get; set; }
public string CabinClass { get; set; }
public string FareInfoRef { get; set; }
public string SegmentRef { get; set; }
}
public class Connection
{
public string SegmentIndex { get; set; }
}
这是转换器:
public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object retVal = new Object();
if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T>() { instance };
}
else if (reader.TokenType == JsonToken.StartArray)
{
retVal = serializer.Deserialize(reader, objectType);
}
return retVal;
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
此答案中的大部分文字是您问题中的文字,并进行了一些调整。你需要做的就是修复你的 JSON 结构,并用 JsonProperty
属性装饰 classes 因为你的 JSON 属性 名字有 air:
和 :
在 C# 中是不允许的。就这些了。
步骤 1
您需要做的第一件事是修复您的 JSON,因为在一种情况下 air:BookingInfo
是一个对象,而在另一种情况下,它是一个数组。因此,它的模式是不一致的。正确的 JSON 应该是这样的:
{
"air:FlightOption": [{
"LegRef": "hx5kk+3R2BKABGzqAAAAAA==",
"Destination": "LHE",
"Origin": "DXB",
"air:Option": {
"Key": "hx5kk+3R2BKA/FzqAAAAAA==",
"TravelTime": "P0DT3H0M0S",
"air:BookingInfo": [{
"BookingCode": "I",
"BookingCount": "7",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKAzFzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAtFzqAAAAAA=="
}]
}
},
{
"LegRef": "hx5kk+3R2BKAFGzqAAAAAA==",
"Destination": "DXB",
"Origin": "LHE",
"air:Option": {
"Key": "hx5kk+3R2BKACGzqAAAAAA==",
"TravelTime": "P0DT11H30M0S",
"air:BookingInfo": [{
"BookingCode": "U",
"BookingCount": "7",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAvFzqAAAAAA=="
},
{
"BookingCode": "Y",
"BookingCount": "9",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAxFzqAAAAAA=="
}
],
"air:Connection": {
"SegmentIndex": "0"
}
}
}
]
}
步骤 2
您可以使用 Visual Studio 轻松地为您的 JSON 创建 classes,正如我在此 .
中所示
步骤 3
您需要稍微帮助序列化程序并告诉它如何将 JSON 属性映射到您的 class 的属性,为此您可以使用 JsonPropertyAttribute
属性作为如下所示:
public class FlightOptionsList
{
[JsonProperty("air:FlightOption")]
public AirFlightoption[] airFlightOption { get; set; }
}
public class AirFlightoption
{
public string LegRef { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
[JsonProperty("air:Option")]
public AirOption airOption { get; set; }
}
public class AirOption
{
public string Key { get; set; }
public string TravelTime { get; set; }
[JsonProperty("air:BookingInfo")]
public AirBookingInfo[] airBookingInfo { get; set; }
[JsonProperty("air:Connection")]
public AirConnection airConnection { get; set; }
}
public class AirBookingInfo
{
public string BookingCode { get; set; }
public string BookingCount { get; set; }
public string CabinClass { get; set; }
public string FareInfoRef { get; set; }
public string SegmentRef { get; set; }
}
public class AirConnection
{
public string SegmentIndex { get; set; }
}
步骤 4
您唯一需要的代码是:
var fol = JsonConvert.DeserializeObject<FlightOptionsList>("YourJSON");
对于发布两次的冗余,我深表歉意......不幸的是,这个问题在其前身中得到了一定程度的解决:Deserializing JSON when sometimes array and sometimes object。我不会使用你的对象。确保您的对象格式正确。有时公司可能会将对象存储为数组或对象,具体取决于是一个还是多个。您可能 运行 喜欢它。确保您的转换器正在 return 正在等待您的对象类型的列表或数组。在我的例子中,我需要 return 一个数组。
阐述 Martinez 和 mfanto 对 Newtonsoft 的回答。他们的答案确实适用于 Newtonsoft:
这是一个使用数组而不是列表(并且命名正确)的示例。
public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartObject
|| reader.TokenType == JsonToken.String
|| reader.TokenType == JsonToken.Integer)
{
return new T[] { serializer.Deserialize<T>(reader) };
}
return serializer.Deserialize<T[]>(reader);
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
然后在属性上写这个:
[JsonProperty("INSURANCE")]
[JsonConverter(typeof(SingleValueArrayConverter<InsuranceInfo>))]
public InsuranceInfo[] InsuranceInfo { get; set; }
Newtonsoft 将为您完成剩下的工作。
return JsonConvert.DeserializeObject<T>(json);
为 Martinez 和 mfanto 干杯!
信不信由你,这将适用于子项目。 (它甚至可能必须。)所以...在我的 InsuranceInfo 中,如果我有另一个 object/array 混合动力车,请在 属性 上再次使用它,如下所示:
[JsonProperty("CLAIM")]
[JsonConverter(typeof(SingleValueArrayConverter<Claim>))]
public Claim[] ClaimInfo { get; set; }
由于实现了 WriteJson,这也将允许在必要时将对象重新序列化回 json,但在这一点上,它将始终是一个数组(耶!)。
我有一个 json 字符串,其中包含以下数据
"air:FlightOptionsList": {
"air:FlightOption": [{
"LegRef": "hx5kk+3R2BKABGzqAAAAAA==",
"Destination": "LHE",
"Origin": "DXB",
"air:Option": {
"Key": "hx5kk+3R2BKA/FzqAAAAAA==",
"TravelTime": "P0DT3H0M0S",
"air:BookingInfo": {
"BookingCode": "I",
"BookingCount": "7",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKAzFzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAtFzqAAAAAA=="
}
}
}, {
"LegRef": "hx5kk+3R2BKAFGzqAAAAAA==",
"Destination": "DXB",
"Origin": "LHE",
"air:Option": {
"Key": "hx5kk+3R2BKACGzqAAAAAA==",
"TravelTime": "P0DT11H30M0S",
"air:BookingInfo": [{
"BookingCode": "U",
"BookingCount": "7",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAvFzqAAAAAA=="
}, {
"BookingCode": "Y",
"BookingCount": "9",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAxFzqAAAAAA=="
}
],
"air:Connection": {
"SegmentIndex": "0"
}
}
}
]
}
我的Class结构如下:
public class FlightOptionsList
{
public List<FlightOption> FlightOption { get; set; }
}
public class FlightOption
{
public string LegRef { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
public Option Option { get; set; }
}
public class Option
{
public string Key { get; set; }
public string TravelTime { get; set; }
public List<BookingInfo> BookingInfo { get; set; }
public Connection Connection { get; set; }
}
public class BookingInfo
{
public string BookingCode { get; set; }
public string BookingCount { get; set; }
public string CabinClass { get; set; }
public string FareInfoRef { get; set; }
public string SegmentRef { get; set; }
}
我想反序列化它,但它给我一个错误如下:
无法将当前 JSON 对象(例如 {"name":"value"})反序列化为类型 'System.Collections.Generic.List`1[ParseSoapEnveloperReqRes.BookingInfo]',因为该类型需要 JSON 数组(例如 [1,2,3])以正确反序列化。 要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,使其成为普通的 .NET 类型(例如,不是原始类型像整数,而不是像数组或列表这样的集合类型),可以从 JSON 对象反序列化。 JsonObjectAttribute 也可以添加到类型以强制它从 JSON 对象反序列化。 路径 'FlightOptionsList.FlightOption[0].Option.BookingInfo.BookingCode',第 394 行,位置 59。
这是因为,就像您看到 json 字符串一样,FlightOptionsList.FlightOption[0].Option.BookingInfo 是一个 object 但在 FlightOptionsList.FlightOption[1].Option.BookingInfo 中是一个 array,如您所见。
如何设置这个问题...我正在使用以下代码将 json 字符串反序列化为 class 对象
var AirTravelResultModel = JsonConvert.DeserializeObject<AirTravelResultModel>(xmlInputData);
查看 Camilo Martinez 对此讨论的回答: Deserializing JSON when sometimes array and sometimes object
基本上,您需要将 JsonConverter
属性添加到 BookingInfo
属性 并在 JsonConverter
实现中处理转换。
public class FlightOptionsList
{
public List<FlightOption> FlightOption { get; set; }
}
public class FlightOption
{
public string LegRef { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
public Option Option { get; set; }
}
public class Option
{
public string Key { get; set; }
public string TravelTime { get; set; }
[JsonConverter(typeof(SingleValueArrayConverter<BookingInfo>))]
public List<BookingInfo> BookingInfo { get; set; }
public Connection Connection { get; set; }
}
public class BookingInfo
{
public string BookingCode { get; set; }
public string BookingCount { get; set; }
public string CabinClass { get; set; }
public string FareInfoRef { get; set; }
public string SegmentRef { get; set; }
}
public class Connection
{
public string SegmentIndex { get; set; }
}
这是转换器:
public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object retVal = new Object();
if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T>() { instance };
}
else if (reader.TokenType == JsonToken.StartArray)
{
retVal = serializer.Deserialize(reader, objectType);
}
return retVal;
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
此答案中的大部分文字是您问题中的文字,并进行了一些调整。你需要做的就是修复你的 JSON 结构,并用 JsonProperty
属性装饰 classes 因为你的 JSON 属性 名字有 air:
和 :
在 C# 中是不允许的。就这些了。
步骤 1
您需要做的第一件事是修复您的 JSON,因为在一种情况下 air:BookingInfo
是一个对象,而在另一种情况下,它是一个数组。因此,它的模式是不一致的。正确的 JSON 应该是这样的:
{
"air:FlightOption": [{
"LegRef": "hx5kk+3R2BKABGzqAAAAAA==",
"Destination": "LHE",
"Origin": "DXB",
"air:Option": {
"Key": "hx5kk+3R2BKA/FzqAAAAAA==",
"TravelTime": "P0DT3H0M0S",
"air:BookingInfo": [{
"BookingCode": "I",
"BookingCount": "7",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKAzFzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAtFzqAAAAAA=="
}]
}
},
{
"LegRef": "hx5kk+3R2BKAFGzqAAAAAA==",
"Destination": "DXB",
"Origin": "LHE",
"air:Option": {
"Key": "hx5kk+3R2BKACGzqAAAAAA==",
"TravelTime": "P0DT11H30M0S",
"air:BookingInfo": [{
"BookingCode": "U",
"BookingCount": "7",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAvFzqAAAAAA=="
},
{
"BookingCode": "Y",
"BookingCount": "9",
"CabinClass": "Economy",
"FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
"SegmentRef": "hx5kk+3R2BKAxFzqAAAAAA=="
}
],
"air:Connection": {
"SegmentIndex": "0"
}
}
}
]
}
步骤 2
您可以使用 Visual Studio 轻松地为您的 JSON 创建 classes,正如我在此
步骤 3
您需要稍微帮助序列化程序并告诉它如何将 JSON 属性映射到您的 class 的属性,为此您可以使用 JsonPropertyAttribute
属性作为如下所示:
public class FlightOptionsList
{
[JsonProperty("air:FlightOption")]
public AirFlightoption[] airFlightOption { get; set; }
}
public class AirFlightoption
{
public string LegRef { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
[JsonProperty("air:Option")]
public AirOption airOption { get; set; }
}
public class AirOption
{
public string Key { get; set; }
public string TravelTime { get; set; }
[JsonProperty("air:BookingInfo")]
public AirBookingInfo[] airBookingInfo { get; set; }
[JsonProperty("air:Connection")]
public AirConnection airConnection { get; set; }
}
public class AirBookingInfo
{
public string BookingCode { get; set; }
public string BookingCount { get; set; }
public string CabinClass { get; set; }
public string FareInfoRef { get; set; }
public string SegmentRef { get; set; }
}
public class AirConnection
{
public string SegmentIndex { get; set; }
}
步骤 4
您唯一需要的代码是:
var fol = JsonConvert.DeserializeObject<FlightOptionsList>("YourJSON");
对于发布两次的冗余,我深表歉意......不幸的是,这个问题在其前身中得到了一定程度的解决:Deserializing JSON when sometimes array and sometimes object。我不会使用你的对象。确保您的对象格式正确。有时公司可能会将对象存储为数组或对象,具体取决于是一个还是多个。您可能 运行 喜欢它。确保您的转换器正在 return 正在等待您的对象类型的列表或数组。在我的例子中,我需要 return 一个数组。
阐述 Martinez 和 mfanto 对 Newtonsoft 的回答。他们的答案确实适用于 Newtonsoft:
这是一个使用数组而不是列表(并且命名正确)的示例。
public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartObject
|| reader.TokenType == JsonToken.String
|| reader.TokenType == JsonToken.Integer)
{
return new T[] { serializer.Deserialize<T>(reader) };
}
return serializer.Deserialize<T[]>(reader);
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
然后在属性上写这个:
[JsonProperty("INSURANCE")]
[JsonConverter(typeof(SingleValueArrayConverter<InsuranceInfo>))]
public InsuranceInfo[] InsuranceInfo { get; set; }
Newtonsoft 将为您完成剩下的工作。
return JsonConvert.DeserializeObject<T>(json);
为 Martinez 和 mfanto 干杯!
信不信由你,这将适用于子项目。 (它甚至可能必须。)所以...在我的 InsuranceInfo 中,如果我有另一个 object/array 混合动力车,请在 属性 上再次使用它,如下所示:
[JsonProperty("CLAIM")]
[JsonConverter(typeof(SingleValueArrayConverter<Claim>))]
public Claim[] ClaimInfo { get; set; }
由于实现了 WriteJson,这也将允许在必要时将对象重新序列化回 json,但在这一点上,它将始终是一个数组(耶!)。