反序列化 JSON 字符串,它是数组并且具有非法的 属性 名称
Deserialize JSON string which is array and has illegal property names
我正在使用 JSON.NET 反序列化来自 HTTP 查询的 JSON 响应,但我在反序列化时遇到问题。
来源JSON是这样的:
[
{
"type": "rpc",
"tid": 18,
"action": "TaskSystem",
"method": "createTask",
"result": {
"0": {
"success": true,
"successes": [
[
"Task successfuly created with S/N #22920"
]
]
},
"1": {
"success": true,
"successes": [
[
"Task successfuly created with S/N #22921"
],
"Task #22921 marked as urgent"
]
},
"records": [
{
"id": 22920
},
{
"id": 22921
}
],
"success": true
}
}
]
我一直在使用这些 classes 进行反序列化:
Private Sub Deserialize()
Dim Jobj = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Response())(Jstring)
End Sub
Public Class Record
Public Property id As Integer
End Class
Public Class Result
Public Property records As Record()
Public Property success As Boolean
End Class
Public Class Response
Public Property type As String
Public Property tid As Integer
Public Property action As String
Public Property method As String
Public Property result As Result
End Class
但是我丢失了查询返回的 success/failure 消息
我应该如何编写 class Result 以收集属性 records As Record(), succes As Boolean and also 那些名为“0”、“1”等的对象...?
非常感谢您的帮助。
您可以将 JSON 复制到剪贴板并使用
编辑 -> 选择性粘贴 -> 粘贴 JSon 为 类
从 classes 中获取粗略信息。所有机器人都弄错了部分内容,例如:
' wrong
Public Property successes()() As String
' correct:
Public Property successes As String()()
这似乎有效:
Public Class StatusS ' string()() version
Public Property success As Boolean
Public Property successes As List(Of List(Of String))
End Class
Public Class StatusO ' Object() version
Public Property success As Boolean
Public Property successes As List(Of Object)
End Class
机器人也很难使用非法的 属性 名称,尤其是 VB,那里有很多关键字(End
和 Error
很常见)。使用 JsonProperty
创建别名(将“0”或“1”映射到合法的内容):
Public Class Result
<JsonProperty("0")>
Public Property StatusA As StatusS
<JsonProperty("1")>
Public Property StatusB As StatusO
Public Property records As List(Of Record)
Public Property success As Boolean
End Class
只要他们提供数组,您就可以使用 List(Of T)
。
Dim jData = JsonConvert.DeserializeObject(Of Response())(jstr)
Console.WriteLine(jData(0).action)
Console.WriteLine(jData(0).result.records(0).id)
Console.WriteLine(jData(0).result.StatusA.success)
Console.WriteLine(jData(0).result.StatusA.successes(0)(0).ToString)
Console.WriteLine(jData(0).result.StatusB.successes(0).ToString)
结果:
TaskSystem
22920
True
Task successfuly created with S/N #22920
[
"Task successfuly created with S/N #22921"
]
很难发现,但是 [ "Task successfuly ... #22920" ]
之后的 missing/extra 逗号导致 Object
版本与 String()()
一个或另一个可能是错字。如果没有,您可以为这两者编写一个转换器,或者为 Q+D 的 StatusO
class 添加一个方法来删除括号:
Friend Function GetSuccessMsg(ndx As Int32) As String
If ndx < successes.Count Then
Return successes(ndx).ToString().
Replace("[", "").Replace("]", "").
Replace("""", "").Trim()
End If
Return String.Empty
End Function
Console.WriteLine(jData(0).result.StatusA.GetSuccessMsg(0))
Task successfuly created with S/N #22921
这里有两个不相关的问题:
您的 Result
class 由一组固定属性和一组可变属性组成,这些属性具有递增的数字名称和标准化的值架构。您希望自动反序列化标准属性并捕获和反序列化自定义属性。
这可以使用 JsonExtensionData
. With this attribute, you can temporarily deserialize the custom properties to a Dictionary(of String, JToken)
then later convert to a Dictionary(Of String, Success)
in an [OnDeserialized]
回调来完成。这里 Success
是一种旨在捕获 JSON 的类型,如下所示:
{
"success": true,
"successes": [ [ "Task successfuly created with S/N #22920" ] ]
}
有关文档,请参阅 Deserialize ExtensionData。
在上述 Success
类型中,"successes"
数组包含字符串数组和单个字符串。
如果您定义 successes
属性 如下:
Public Property successes As List(Of List(Of String))
然后可以使用 How to handle both a single item and an array for the same property using JSON.net, setting it as the item converter 的 SingleOrArrayConverter(Of String)
变体通过 <JsonProperty(ItemConverterType := GetType(SingleOrArrayConverter(Of String)))>
.
来处理
因此你的最终 classes 看起来像:
Public Class Success
Public Property success As Boolean
<JsonProperty(ItemConverterType := GetType(SingleOrArrayConverter(Of String)))> _
Public Property successes As List(Of List(Of String))
End Class
Public Class Record
Public Property id As Integer
End Class
Public Class Result
Public Property records As Record()
Public Property success As Boolean
<JsonIgnore> _
Public Property successes as Dictionary(Of string, Success)
<JsonExtensionData> _
Private _additionalData as Dictionary(Of string, JToken)
<System.Runtime.Serialization.OnSerializing> _
Sub OnSerializing(ByVal context as System.Runtime.Serialization.StreamingContext)
If successes IsNot Nothing
_additionalData = successes.ToDictionary(Function(p) p.Key, Function(p) JToken.FromObject(p.Value))
Else
_additionalData = Nothing
End If
End Sub
<System.Runtime.Serialization.OnSerialized> _
Sub OnSerialized(ByVal context as System.Runtime.Serialization.StreamingContext)
_additionalData = Nothing
End Sub
<System.Runtime.Serialization.OnDeserializing> _
Sub OnDeserializing(ByVal context as System.Runtime.Serialization.StreamingContext)
_additionalData = Nothing
End Sub
<System.Runtime.Serialization.OnDeserialized>
Sub OnDeserialized(ByVal context as System.Runtime.Serialization.StreamingContext)
If _additionalData IsNot Nothing
successes = _additionalData.ToDictionary(Function(p) p.Key, Function(p) p.Value.ToObject(Of Success)())
End If
_additionalData = Nothing
End Sub
End Class
Public Class Response
Public Property type As String
Public Property tid As Integer
Public Property action As String
Public Property method As String
Public Property result As Result
End Class
Public Class SingleOrArrayConverter(Of T)
Inherits JsonConverter
Public Overrides ReadOnly Property CanWrite() As Boolean
Get
Return false
End Get
End Property
Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
Throw New NotImplementedException()
End Sub
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
Dim retVal As Object = New List(Of T)()
If reader.TokenType = JsonToken.StartArray Then
serializer.Populate(reader, retVal)
Else
Dim instance As T = DirectCast(serializer.Deserialize(reader, GetType(T)), T)
retVal.Add(instance)
End If
Return retVal
End Function
Public Overrides Function CanConvert(objectType As Type) As Boolean
Return objectType = GetType(List(Of T))
End Function
End Class
原型fiddle.
我正在使用 JSON.NET 反序列化来自 HTTP 查询的 JSON 响应,但我在反序列化时遇到问题。
来源JSON是这样的:
[
{
"type": "rpc",
"tid": 18,
"action": "TaskSystem",
"method": "createTask",
"result": {
"0": {
"success": true,
"successes": [
[
"Task successfuly created with S/N #22920"
]
]
},
"1": {
"success": true,
"successes": [
[
"Task successfuly created with S/N #22921"
],
"Task #22921 marked as urgent"
]
},
"records": [
{
"id": 22920
},
{
"id": 22921
}
],
"success": true
}
}
]
我一直在使用这些 classes 进行反序列化:
Private Sub Deserialize()
Dim Jobj = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Response())(Jstring)
End Sub
Public Class Record
Public Property id As Integer
End Class
Public Class Result
Public Property records As Record()
Public Property success As Boolean
End Class
Public Class Response
Public Property type As String
Public Property tid As Integer
Public Property action As String
Public Property method As String
Public Property result As Result
End Class
但是我丢失了查询返回的 success/failure 消息
我应该如何编写 class Result 以收集属性 records As Record(), succes As Boolean and also 那些名为“0”、“1”等的对象...?
非常感谢您的帮助。
您可以将 JSON 复制到剪贴板并使用
编辑 -> 选择性粘贴 -> 粘贴 JSon 为 类
从 classes 中获取粗略信息。所有机器人都弄错了部分内容,例如:
' wrong
Public Property successes()() As String
' correct:
Public Property successes As String()()
这似乎有效:
Public Class StatusS ' string()() version
Public Property success As Boolean
Public Property successes As List(Of List(Of String))
End Class
Public Class StatusO ' Object() version
Public Property success As Boolean
Public Property successes As List(Of Object)
End Class
机器人也很难使用非法的 属性 名称,尤其是 VB,那里有很多关键字(End
和 Error
很常见)。使用 JsonProperty
创建别名(将“0”或“1”映射到合法的内容):
Public Class Result
<JsonProperty("0")>
Public Property StatusA As StatusS
<JsonProperty("1")>
Public Property StatusB As StatusO
Public Property records As List(Of Record)
Public Property success As Boolean
End Class
只要他们提供数组,您就可以使用 List(Of T)
。
Dim jData = JsonConvert.DeserializeObject(Of Response())(jstr)
Console.WriteLine(jData(0).action)
Console.WriteLine(jData(0).result.records(0).id)
Console.WriteLine(jData(0).result.StatusA.success)
Console.WriteLine(jData(0).result.StatusA.successes(0)(0).ToString)
Console.WriteLine(jData(0).result.StatusB.successes(0).ToString)
结果:
TaskSystem
22920
True
Task successfuly created with S/N #22920
[
"Task successfuly created with S/N #22921"
]
很难发现,但是 [ "Task successfuly ... #22920" ]
之后的 missing/extra 逗号导致 Object
版本与 String()()
一个或另一个可能是错字。如果没有,您可以为这两者编写一个转换器,或者为 Q+D 的 StatusO
class 添加一个方法来删除括号:
Friend Function GetSuccessMsg(ndx As Int32) As String
If ndx < successes.Count Then
Return successes(ndx).ToString().
Replace("[", "").Replace("]", "").
Replace("""", "").Trim()
End If
Return String.Empty
End Function
Console.WriteLine(jData(0).result.StatusA.GetSuccessMsg(0))
Task successfuly created with S/N #22921
这里有两个不相关的问题:
您的
Result
class 由一组固定属性和一组可变属性组成,这些属性具有递增的数字名称和标准化的值架构。您希望自动反序列化标准属性并捕获和反序列化自定义属性。这可以使用
JsonExtensionData
. With this attribute, you can temporarily deserialize the custom properties to aDictionary(of String, JToken)
then later convert to aDictionary(Of String, Success)
in an[OnDeserialized]
回调来完成。这里Success
是一种旨在捕获 JSON 的类型,如下所示:{ "success": true, "successes": [ [ "Task successfuly created with S/N #22920" ] ] }
有关文档,请参阅 Deserialize ExtensionData。
在上述
Success
类型中,"successes"
数组包含字符串数组和单个字符串。如果您定义
successes
属性 如下:Public Property successes As List(Of List(Of String))
然后可以使用 How to handle both a single item and an array for the same property using JSON.net, setting it as the item converter 的
SingleOrArrayConverter(Of String)
变体通过<JsonProperty(ItemConverterType := GetType(SingleOrArrayConverter(Of String)))>
. 来处理
因此你的最终 classes 看起来像:
Public Class Success
Public Property success As Boolean
<JsonProperty(ItemConverterType := GetType(SingleOrArrayConverter(Of String)))> _
Public Property successes As List(Of List(Of String))
End Class
Public Class Record
Public Property id As Integer
End Class
Public Class Result
Public Property records As Record()
Public Property success As Boolean
<JsonIgnore> _
Public Property successes as Dictionary(Of string, Success)
<JsonExtensionData> _
Private _additionalData as Dictionary(Of string, JToken)
<System.Runtime.Serialization.OnSerializing> _
Sub OnSerializing(ByVal context as System.Runtime.Serialization.StreamingContext)
If successes IsNot Nothing
_additionalData = successes.ToDictionary(Function(p) p.Key, Function(p) JToken.FromObject(p.Value))
Else
_additionalData = Nothing
End If
End Sub
<System.Runtime.Serialization.OnSerialized> _
Sub OnSerialized(ByVal context as System.Runtime.Serialization.StreamingContext)
_additionalData = Nothing
End Sub
<System.Runtime.Serialization.OnDeserializing> _
Sub OnDeserializing(ByVal context as System.Runtime.Serialization.StreamingContext)
_additionalData = Nothing
End Sub
<System.Runtime.Serialization.OnDeserialized>
Sub OnDeserialized(ByVal context as System.Runtime.Serialization.StreamingContext)
If _additionalData IsNot Nothing
successes = _additionalData.ToDictionary(Function(p) p.Key, Function(p) p.Value.ToObject(Of Success)())
End If
_additionalData = Nothing
End Sub
End Class
Public Class Response
Public Property type As String
Public Property tid As Integer
Public Property action As String
Public Property method As String
Public Property result As Result
End Class
Public Class SingleOrArrayConverter(Of T)
Inherits JsonConverter
Public Overrides ReadOnly Property CanWrite() As Boolean
Get
Return false
End Get
End Property
Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
Throw New NotImplementedException()
End Sub
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
Dim retVal As Object = New List(Of T)()
If reader.TokenType = JsonToken.StartArray Then
serializer.Populate(reader, retVal)
Else
Dim instance As T = DirectCast(serializer.Deserialize(reader, GetType(T)), T)
retVal.Add(instance)
End If
Return retVal
End Function
Public Overrides Function CanConvert(objectType As Type) As Boolean
Return objectType = GetType(List(Of T))
End Function
End Class
原型fiddle.