How to extract a specific object from a JSON?

Viewed 307

I would like to know how to extract a specific object from a JSON.
I saw most of the problem solved on Stackoverflow before posting this, but there is no one who already talked about this.

I want need to get the slug value from the JSON objects.
Here is my code Get Users From JSON

Imports System
Imports Newtonsoft.Json.Linq
                
Public Module Module1
    Public Sub Main()
        Dim myJsonString = New System.IO.StreamReader(New System.Net.WebClient().
            OpenRead("https://pastebin.com/raw/z4GZFuF3")).ReadToEnd()
        
        Dim myJObject = JObject.Parse(myJsonString)
        For Each match In myJObject("matches")
        Console.WriteLine(match("id")("slug"))
        Next
    End Sub
End Module

And Here is the Output:

Run-time exception (line -1): Error reading JObject from JsonReader.  
Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.

Stack Trace:

[Newtonsoft.Json.JsonReaderException: Error reading JObject from JsonReader.  
   Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.]
   at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings)
   at Newtonsoft.Json.Linq.JObject.Parse(String json, JsonLoadSettings settings)
   at Newtonsoft.Json.Linq.JObject.Parse(String json)
   at Module1.Main()

What I have reduced since this error is that the object "matches" does not exist in the JSON text, but I have no idea what I should specify in its place to make this work.

2 Answers

The JSON that can be retrieved from the provided address:
(http://www.stginternational.org/wp-json/wp/v2/users)
is an array of Objects.
It can be parsed using JArray.Parse(), but I suggest to deserialize this JSON as .Net classes: it's much easier to handle.

The JSON's base object (each object in the array) is defined like this:

{
  "id": 1,
  "name": "drall",
  "url": "",
  "description": "",
  "link": "http://www.stginternational.org/author/drall/",
  "slug": "drall",
  "avatar_urls": {
    "24": "http://1.gravatar.com/avatar/dc6dd0ef71784957b629e124f19364cb?s=24&d=mm&r=g",
    "48": "http://1.gravatar.com/avatar/dc6dd0ef71784957b629e124f19364cb?s=48&d=mm&r=g",
    "96": "http://1.gravatar.com/avatar/dc6dd0ef71784957b629e124f19364cb?s=96&d=mm&r=g"
  },
  "meta": [],
  "_links": {
    "self": [
      {
        "href": "http://www.stginternational.org/wp-json/wp/v2/users/1"
      }
    ],
    "collection": [
      {
        "href": "http://www.stginternational.org/wp-json/wp/v2/users"
      }
    ]
  }
}

It can be represented by these .Net classes:

Public Class UserObject
    Public Property Id As Long
    Public Property Name As String
    Public Property Url As String
    Public Property Description As String
    Public Property Link As Uri
    Public Property Slug As String
    <JsonProperty("avatar_urls")>
    Public Property AvatarUrls As Dictionary(Of String, Uri)
    Public Property Meta As List(Of Object)
    <JsonProperty("_links")>
    Public Property Links As Links
End Class

Public Class Links
    Public Property Self As List(Of LinkCollection)
    Public Property Collection As List(Of LinkCollection)
End Class

Public Class LinkCollection
    Public property Href As Uri
End Class

With this model, you can simply use JsonConvert.DeserializeObject(), specifying the Type to deserialize to.
As mentioned, this is an Array or List of objects, where the base object is an UserObject, so you can specify a List(Of UserObject) :

Dim json = JsonConvert.DeserializeObject(Of List(Of UserObject))(json)

You can then access the class object as usual:

Imports System.Net
Imports Newtonsoft.Json
        
Dim users As List(Of UserObject) = Nothing

Using client As New WebClient()
    Dim json = client.DownloadString([The URL])
    users = JsonConvert.DeserializeObject(Of List(Of UserObject))(json)
End Using

If users IsNot Nothing Then
    For Each user In users
        Console.WriteLine(user.Slug)
        Console.WriteLine(user.Links.Self(0).Href)
        Console.WriteLine(user.Links.Collection(0).Href)

        For Each avatar In user.AvatarUrls
            Console.WriteLine($"Key: {avatar.Key}, Value: {avatar.Value}")
        Next
    Next
End If

In case you just want one of the properties (slug, in this case), you can use JArray.Parse() to parse the JSON and read the property value directly:

Using client As New WebClient()
    Dim json = client.DownloadString([The URL])
    Dim users = JArray.Parse(json)
    For Each user As JToken In users
        Console.WriteLine(user("slug"))
    Next
End Using

While Jimi's answer is preferable because it deserializes the JSON into a strongly typed object, here is an alternative since you only care about getting a single property from the array of objects.

It does the following three steps:

  1. Get the JSON from the endpoint
  2. Convert the JSON literal into JArray
  3. Use LINQ to get just the Slug item of each object in the array
Dim myJsonString = New System.IO.StreamReader(New System.Net.WebClient().OpenRead("http://www.stginternational.org/wp-json/wp/v2/users")).ReadToEnd
Dim arrayOfObjects = JArray.Parse(myJsonString)
Dim arrayOfSlugs = From jsonObject In arrayOfObjects Select jsonObject.Item("slug")

Example: Live Demo

Related