使用Newtonsoft Json.NET循环使用动态对象ID的非数组JSON

时间:2017-11-23 14:00:26

标签: arrays json vb.net json.net json-deserialization

我正在使用Newtonsoft JSON library。我想循环一个JSON结果集,如果可能的话,必须创建一个单独的类,因为JSON对象在这里显示得更加扩展。

我已查看herehere

我的JSON(在帖子底部美化):

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

然后我尝试使用JObjectJArray。问题在于JSON响应是由第三方生成的,并且IMO格式不正确,因为result对象实际上应该是一个数组。此外,结果还包含动态ID(a326f402f18ab1cd2c4489b07cc3e8f418aec266ec0c01d126e9715bc17124e2

所以,我现在面临的问题是:当result不是数组并且每个结果也是由动态ID标识时,我如何循环遍历所有结果?

伪代码:

  1. 循环显示结果数量(在本例中为2:a326f402f18ab1cd2c4489b07cc3e8f418aec266ec0c01d126e9715bc17124e2
  2. 对于每个结果,我想选择属性。这不一定是强类型的(json.photos(j).small),我可以使用json(i)("photos")(j)("small")
  3. 之类的东西。

    _

    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

    此代码返回一个数组

    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的数组?

1 个答案:

答案 0 :(得分:2)

您可以将result JToken投射到JObject并循环显示其Properties()集合。每个属性的Value是另一个JObject,其中包含您感兴趣的数据(例如idclient_idphotos等)。< / p>

以下是一个例子:

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

小提琴:https://dotnetfiddle.net/ALeiX8

请注意,上面的代码假定示例JSON中的所有对象属性始终存在。如果某个特定属性可能不会出现,那么在尝试使用其值之前,您需要检查该属性上的Nothing。例如,您提到在尝试访问Object reference not set to an instance of an object计数时收到broker错误。这告诉我,对于某些结果项,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

然后,您可以在Value(Of T)上使用DirectCastJToken的任何地方使用它。例如:

Dim brokers As JArray = item("broker").ValueOrDefault(new JArray())

或者:

Dim email As String = broker("emailaddress").ValueOrDefault("")