使用 Newtonsoft Json.NET 使用动态对象 ID 遍历非数组 JSON
Loop through non-array JSON with dynamic object IDs using Newtonsoft Json.NET
我正在使用 Newtonsoft JSON library。我想遍历 JSON 结果集 而 如果可能的话不必创建一个单独的 class,因为 JSON 对象扩展得更多显示在这里。
我已经看了here and 。
我的JSON(在post底部美化):
Dim json As String = "{""result"":{""a326f402f18ab1cd2c4489b07cc3e8f4"":{""id"":""a326f402f18ab1cd2c4489b07cc3e8f4"",""client_id"":30,""broker"":[{""broker_id"": 30,""name"": ""Andrew"",""emailaddress"": ""andrew@homes.com""}],""photos"":[{""small"":""https://www.example.com/30/photos/small/66.1427790195-976.jpg"",""middle"":""https://www.example.com/30/photos/middle/66.1427790195-976.jpg""},{""small"":""https://www.example.com/30/photos/small/31382.1508417843-454.JPG"",""middle"":""https://www.example.com/30/photos/middle/31382.1508417843-454.JPG""}]},""18aec266ec0c01d126e9715bc17124e2"":{""id"":""18aec266ec0c01d126e9715bc17124e2"",""client_id"":30,""broker"":[{""broker_id"": 30,""name"": ""Andrew"",""emailaddress"": ""andrew@homes.com""}],""photos"":[{""small"":""https://www.example.com/30/photos/small/10.1298385655.jpg"",""middle"":""https://www.example.com/30/photos/middle/10.1298385655.jpg""},{""small"":""https://www.example.com/30/photos/small/10.1298385646.jpg"",""middle"":""https://www.example.com/30/photos/middle/10.1298385646.jpg""}]}}}"
我首先尝试使用 JsonTextReader
,但在尝试快速访问各个属性方面似乎太麻烦了:
Dim sBuilder As New StringBuilder
Dim reader As JsonTextReader = New JsonTextReader(New StringReader(json))
While reader.Read
If reader.Value IsNot Nothing Then
sBuilder.Append(String.Format("Token: {0}, Value: {1}", reader.TokenType.ToString, reader.Value.ToString))
Else
sBuilder.Append(String.Format("Token: {0}", reader.TokenType.ToString))
End If
sBuilder.Append("<br/>")
End While
然后我尝试使用 JObject
和 JArray
。问题是 JSON 响应是由第三方生成的,IMO 格式不正确,因为 result
对象实际上应该是一个数组。结果还包含动态 ID(a326f402f18ab1cd2c4489b07cc3e8f4
和 18aec266ec0c01d126e9715bc17124e2
)
所以,我现在面临着:当 result
不是数组并且每个结果也由动态 ID 标识时,我如何遍历所有结果?
伪代码:
- 遍历结果数(在本例中为 2:
a326f402f18ab1cd2c4489b07cc3e8f4
和 18aec266ec0c01d126e9715bc17124e2
)
- 对于这些结果中的每一个,我都想 select 属性。这不一定必须是强类型的(
json.photos(j).small
),我可以接受 json(i)("photos")(j)("small")
这样的东西
_
Dim photoSmall As String
Dim clientId As Integer
For i As Integer = 0 To json.count - 1
With json(i)
clientId = json.client_id
For J As Integer= 0 To json.photos.count - 1
photoSmall = json.photos(j).small
Next J
End With
Next i
美化了JSON
{
"result": {
"a326f402f18ab1cd2c4489b07cc3e8f4": {
"id": "a326f402f18ab1cd2c4489b07cc3e8f4",
"client_id": 30,
"broker": [
{
"broker_id": 30,
"name": "Andrew",
"emailaddress": "andrew@homes.com"
}
],
"photos": [
{
"small": "https://www.example.com/30/photos/small/66.1427790195-976.jpg",
"middle": "https://www.example.com/30/photos/middle/66.1427790195-976.jpg"
},
{
"small": "https://www.example.com/30/photos/small/31382.1508417843-454.JPG",
"middle": "https://www.example.com/30/photos/middle/31382.1508417843-454.JPG"
}
]
},
"18aec266ec0c01d126e9715bc17124e2": {
"id": "18aec266ec0c01d126e9715bc17124e2",
"client_id": 30,
"broker": [
{
"broker_id": 30,
"name": "Andrew",
"emailaddress": "andrew@homes.com"
}
],
"photos": [
{
"small": "https://www.example.com/30/photos/small/10.1298385655.jpg",
"middle": "https://www.example.com/30/photos/middle/10.1298385655.jpg"
},
{
"small": "https://www.example.com/30/photos/small/10.1298385646.jpg",
"middle": "https://www.example.com/30/photos/middle/10.1298385646.jpg"
}
]
}
}
}
更新 2
这段代码returns一个数组
Dim photosTEST As JArray = DirectCast(item("photos"), JArray)
Log("photosTEST length", photosTEST.Count.ToString)
但是这段代码抛出错误:Object reference not set to an instance of an object
Dim brokers As JArray = DirectCast(item("broker"), JArray)
Log("brokers length", brokers.Count.ToString)
我不明白,因为 broker
只是一个长度为 1 的数组,对吗?
您可以将 result
JToken
转换为 JObject
并循环遍历其 Properties()
集合。每个属性的 Value
是另一个包含您感兴趣的数据(例如 id
、client_id
、photos
等)的 JObject
。
这是一个例子:
Dim obj As JObject = JObject.Parse(json)
Dim result As JObject = DirectCast(obj("result"), JObject)
For Each prop As JProperty In result.Properties()
Dim item As JObject = DirectCast(prop.Value, JObject)
Dim id As String = item("id").Value(Of String)
Dim clientId As Integer = item("client_id").Value(Of Integer)
Console.WriteLine("id: " & id)
Console.WriteLine("client id: " & clientId.ToString())
Dim brokers As JArray = DirectCast(item("broker"), JArray)
For i As Integer = 0 To brokers.Count - 1
Dim broker As JObject = DirectCast(brokers(i), JObject)
Dim brokerId As Integer = broker("broker_id").Value(Of Integer)
Dim name As String = broker("name").Value(Of String)
Dim email As String = broker("emailaddress").Value(Of String)
Console.WriteLine("broker " & i.ToString() & " id: " & brokerId)
Console.WriteLine("broker " & i.ToString() & " name: " & name)
Console.WriteLine("broker " & i.ToString() & " email: " & email)
Next
Dim photos As JArray = DirectCast(item("photos"), JArray)
For i As Integer = 0 To photos.Count - 1
Dim photo As JObject = DirectCast(photos(i), JObject)
Dim small As String = photo("small").Value(Of String)
Dim middle As String = photo("middle").Value(Of String)
Console.WriteLine("photo " & i.ToString() & " small: " & small)
Console.WriteLine("photo " & i.ToString() & " middle: " & middle)
Next
Console.WriteLine()
Next
Fiddle: https://dotnetfiddle.net/ALeiX8
请注意,上面的代码假设您的示例 JSON 中的所有对象属性将始终存在。如果某个特定的 属性 可能不会出现,那么在尝试使用它的值之前,您需要检查 属性 上的 Nothing
。例如,您提到在尝试访问 broker
计数时出现 Object reference not set to an instance of an object
错误。这告诉我,对于您的某些结果项,JSON 中没有 broker
属性。在这种情况下,您需要更改代码以检查 Nothing
,如下所示:
Dim brokers As JArray = DirectCast(item("broker"), JArray)
If brokers IsNot Nothing Then
For i As Integer = 0 To brokers.Count - 1
Dim broker As JObject = DirectCast(brokers(i), JObject)
Dim brokerId As Integer = broker("broker_id").Value(Of Integer)
Dim name As String = broker("name").Value(Of String)
Dim email As String = broker("emailaddress").Value(Of String)
Console.WriteLine("broker " & i.ToString() & " id: " & brokerId)
Console.WriteLine("broker " & i.ToString() & " name: " & name)
Console.WriteLine("broker " & i.ToString() & " email: " & email)
Next
End If
同样,如果经纪人可能没有电子邮件地址,那么您需要执行以下操作:
Dim email As String = ""
If broker("emailaddress") IsNot Nothing Then
email = broker("emailaddress").Value(Of String)
End If
事实上,如果您发现 JSON 中有许多属性不能指望一直存在,您可以编写一些扩展方法来帮助简化代码。此方法将允许您提供一个默认值来代替特定的 JToken
,如果结果是 Nothing
:
Imports System.Runtime.CompilerServices
Imports Newtonsoft.Json.Linq
Module JsonExtensions
<Extension()>
Public Function ValueOrDefault(Of T)(token As JToken, defaultValue As T) As T
If token IsNot Nothing AndAlso token.Type <> JTokenType.Null Then
Return token.Value(Of T)
Else
Return defaultValue
End If
End Function
End Module
然后您可以在您当前在 JToken
上使用 Value(Of T)
或 DirectCast
的任何地方使用它。例如:
Dim brokers As JArray = item("broker").ValueOrDefault(new JArray())
或:
Dim email As String = broker("emailaddress").ValueOrDefault("")
我正在使用 Newtonsoft JSON library。我想遍历 JSON 结果集 而 如果可能的话不必创建一个单独的 class,因为 JSON 对象扩展得更多显示在这里。
我已经看了here and
我的JSON(在post底部美化):
Dim json As String = "{""result"":{""a326f402f18ab1cd2c4489b07cc3e8f4"":{""id"":""a326f402f18ab1cd2c4489b07cc3e8f4"",""client_id"":30,""broker"":[{""broker_id"": 30,""name"": ""Andrew"",""emailaddress"": ""andrew@homes.com""}],""photos"":[{""small"":""https://www.example.com/30/photos/small/66.1427790195-976.jpg"",""middle"":""https://www.example.com/30/photos/middle/66.1427790195-976.jpg""},{""small"":""https://www.example.com/30/photos/small/31382.1508417843-454.JPG"",""middle"":""https://www.example.com/30/photos/middle/31382.1508417843-454.JPG""}]},""18aec266ec0c01d126e9715bc17124e2"":{""id"":""18aec266ec0c01d126e9715bc17124e2"",""client_id"":30,""broker"":[{""broker_id"": 30,""name"": ""Andrew"",""emailaddress"": ""andrew@homes.com""}],""photos"":[{""small"":""https://www.example.com/30/photos/small/10.1298385655.jpg"",""middle"":""https://www.example.com/30/photos/middle/10.1298385655.jpg""},{""small"":""https://www.example.com/30/photos/small/10.1298385646.jpg"",""middle"":""https://www.example.com/30/photos/middle/10.1298385646.jpg""}]}}}"
我首先尝试使用 JsonTextReader
,但在尝试快速访问各个属性方面似乎太麻烦了:
Dim sBuilder As New StringBuilder
Dim reader As JsonTextReader = New JsonTextReader(New StringReader(json))
While reader.Read
If reader.Value IsNot Nothing Then
sBuilder.Append(String.Format("Token: {0}, Value: {1}", reader.TokenType.ToString, reader.Value.ToString))
Else
sBuilder.Append(String.Format("Token: {0}", reader.TokenType.ToString))
End If
sBuilder.Append("<br/>")
End While
然后我尝试使用 JObject
和 JArray
。问题是 JSON 响应是由第三方生成的,IMO 格式不正确,因为 result
对象实际上应该是一个数组。结果还包含动态 ID(a326f402f18ab1cd2c4489b07cc3e8f4
和 18aec266ec0c01d126e9715bc17124e2
)
所以,我现在面临着:当 result
不是数组并且每个结果也由动态 ID 标识时,我如何遍历所有结果?
伪代码:
- 遍历结果数(在本例中为 2:
a326f402f18ab1cd2c4489b07cc3e8f4
和18aec266ec0c01d126e9715bc17124e2
) - 对于这些结果中的每一个,我都想 select 属性。这不一定必须是强类型的(
json.photos(j).small
),我可以接受json(i)("photos")(j)("small")
这样的东西
_
Dim photoSmall As String
Dim clientId As Integer
For i As Integer = 0 To json.count - 1
With json(i)
clientId = json.client_id
For J As Integer= 0 To json.photos.count - 1
photoSmall = json.photos(j).small
Next J
End With
Next i
美化了JSON
{
"result": {
"a326f402f18ab1cd2c4489b07cc3e8f4": {
"id": "a326f402f18ab1cd2c4489b07cc3e8f4",
"client_id": 30,
"broker": [
{
"broker_id": 30,
"name": "Andrew",
"emailaddress": "andrew@homes.com"
}
],
"photos": [
{
"small": "https://www.example.com/30/photos/small/66.1427790195-976.jpg",
"middle": "https://www.example.com/30/photos/middle/66.1427790195-976.jpg"
},
{
"small": "https://www.example.com/30/photos/small/31382.1508417843-454.JPG",
"middle": "https://www.example.com/30/photos/middle/31382.1508417843-454.JPG"
}
]
},
"18aec266ec0c01d126e9715bc17124e2": {
"id": "18aec266ec0c01d126e9715bc17124e2",
"client_id": 30,
"broker": [
{
"broker_id": 30,
"name": "Andrew",
"emailaddress": "andrew@homes.com"
}
],
"photos": [
{
"small": "https://www.example.com/30/photos/small/10.1298385655.jpg",
"middle": "https://www.example.com/30/photos/middle/10.1298385655.jpg"
},
{
"small": "https://www.example.com/30/photos/small/10.1298385646.jpg",
"middle": "https://www.example.com/30/photos/middle/10.1298385646.jpg"
}
]
}
}
}
更新 2
这段代码returns一个数组
Dim photosTEST As JArray = DirectCast(item("photos"), JArray)
Log("photosTEST length", photosTEST.Count.ToString)
但是这段代码抛出错误:Object reference not set to an instance of an object
Dim brokers As JArray = DirectCast(item("broker"), JArray)
Log("brokers length", brokers.Count.ToString)
我不明白,因为 broker
只是一个长度为 1 的数组,对吗?
您可以将 result
JToken
转换为 JObject
并循环遍历其 Properties()
集合。每个属性的 Value
是另一个包含您感兴趣的数据(例如 id
、client_id
、photos
等)的 JObject
。
这是一个例子:
Dim obj As JObject = JObject.Parse(json)
Dim result As JObject = DirectCast(obj("result"), JObject)
For Each prop As JProperty In result.Properties()
Dim item As JObject = DirectCast(prop.Value, JObject)
Dim id As String = item("id").Value(Of String)
Dim clientId As Integer = item("client_id").Value(Of Integer)
Console.WriteLine("id: " & id)
Console.WriteLine("client id: " & clientId.ToString())
Dim brokers As JArray = DirectCast(item("broker"), JArray)
For i As Integer = 0 To brokers.Count - 1
Dim broker As JObject = DirectCast(brokers(i), JObject)
Dim brokerId As Integer = broker("broker_id").Value(Of Integer)
Dim name As String = broker("name").Value(Of String)
Dim email As String = broker("emailaddress").Value(Of String)
Console.WriteLine("broker " & i.ToString() & " id: " & brokerId)
Console.WriteLine("broker " & i.ToString() & " name: " & name)
Console.WriteLine("broker " & i.ToString() & " email: " & email)
Next
Dim photos As JArray = DirectCast(item("photos"), JArray)
For i As Integer = 0 To photos.Count - 1
Dim photo As JObject = DirectCast(photos(i), JObject)
Dim small As String = photo("small").Value(Of String)
Dim middle As String = photo("middle").Value(Of String)
Console.WriteLine("photo " & i.ToString() & " small: " & small)
Console.WriteLine("photo " & i.ToString() & " middle: " & middle)
Next
Console.WriteLine()
Next
Fiddle: https://dotnetfiddle.net/ALeiX8
请注意,上面的代码假设您的示例 JSON 中的所有对象属性将始终存在。如果某个特定的 属性 可能不会出现,那么在尝试使用它的值之前,您需要检查 属性 上的 Nothing
。例如,您提到在尝试访问 broker
计数时出现 Object reference not set to an instance of an object
错误。这告诉我,对于您的某些结果项,JSON 中没有 broker
属性。在这种情况下,您需要更改代码以检查 Nothing
,如下所示:
Dim brokers As JArray = DirectCast(item("broker"), JArray)
If brokers IsNot Nothing Then
For i As Integer = 0 To brokers.Count - 1
Dim broker As JObject = DirectCast(brokers(i), JObject)
Dim brokerId As Integer = broker("broker_id").Value(Of Integer)
Dim name As String = broker("name").Value(Of String)
Dim email As String = broker("emailaddress").Value(Of String)
Console.WriteLine("broker " & i.ToString() & " id: " & brokerId)
Console.WriteLine("broker " & i.ToString() & " name: " & name)
Console.WriteLine("broker " & i.ToString() & " email: " & email)
Next
End If
同样,如果经纪人可能没有电子邮件地址,那么您需要执行以下操作:
Dim email As String = ""
If broker("emailaddress") IsNot Nothing Then
email = broker("emailaddress").Value(Of String)
End If
事实上,如果您发现 JSON 中有许多属性不能指望一直存在,您可以编写一些扩展方法来帮助简化代码。此方法将允许您提供一个默认值来代替特定的 JToken
,如果结果是 Nothing
:
Imports System.Runtime.CompilerServices
Imports Newtonsoft.Json.Linq
Module JsonExtensions
<Extension()>
Public Function ValueOrDefault(Of T)(token As JToken, defaultValue As T) As T
If token IsNot Nothing AndAlso token.Type <> JTokenType.Null Then
Return token.Value(Of T)
Else
Return defaultValue
End If
End Function
End Module
然后您可以在您当前在 JToken
上使用 Value(Of T)
或 DirectCast
的任何地方使用它。例如:
Dim brokers As JArray = item("broker").ValueOrDefault(new JArray())
或:
Dim email As String = broker("emailaddress").ValueOrDefault("")