Flo Flo - 11 months ago 127
JSON Question

Loop through non-array JSON with dynamic object IDs using Newtonsoft Json.NET

I'm using the Newtonsoft JSON library. I want to loop through a JSON result set without having to create a separate class if possible, since the JSON object is far more extended that displayed here.

I already looked here and here.

My JSON (beautified at bottom of post):

Dim json As String = "{""result"":{""a326f402f18ab1cd2c4489b07cc3e8f4"":{""id"":""a326f402f18ab1cd2c4489b07cc3e8f4"",""client_id"":30,""broker"":[{""broker_id"": 30,""name"": ""Andrew"",""emailaddress"": ""[email protected]""}],""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"": ""[email protected]""}],""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""}]}}}"


I first tried with
JsonTextReader
, but that seemed too cumbersome in trying to access the individual properties quickly:

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


I then tried to work with
JObject
and
JArray
. The problem there is that the JSON response is generated by a 3rd party and IMO is not formatted well, since the
result
object should actually be an array. Also the results contain dynamic IDs (
a326f402f18ab1cd2c4489b07cc3e8f4
and
18aec266ec0c01d126e9715bc17124e2
)

So, I'm now faced with: how can I loop through all results when
result
is not an array and each result is also identified by a dynamic id?

Pseudo code:


  1. Loop through the number of results (in this case 2:
    a326f402f18ab1cd2c4489b07cc3e8f4
    and
    18aec266ec0c01d126e9715bc17124e2
    )

  2. For each of those results I want to select the attributes. This does not necessarily have to be strongly typed (
    json.photos(j).small
    ), I'd be fine with something like
    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


Beautified JSON

{
"result": {
"a326f402f18ab1cd2c4489b07cc3e8f4": {
"id": "a326f402f18ab1cd2c4489b07cc3e8f4",
"client_id": 30,
"broker": [
{
"broker_id": 30,
"name": "Andrew",
"emailaddress": "[email protected]"
}
],
"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": "[email protected]"
}
],
"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"
}
]
}
}
}


UPDATE 2

This code returns an array

Dim photosTEST As JArray = DirectCast(item("photos"), JArray)
Log("photosTEST length", photosTEST.Count.ToString)


But this code throws error:
Object reference not set to an instance of an object


Dim brokers As JArray = DirectCast(item("broker"), JArray)
Log("brokers length", brokers.Count.ToString)


I don't understand since
broker
is just an array with length of 1 correct?

Answer Source

You can cast the result JToken to a JObject and loop through its Properties() collection. The Value of each of those properties is another JObject containing the data (e.g. id, client_id, photos) you are interested in.

Here is an example:

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 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

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download