anoopb
anoopb

Reputation: 543

How to tell if JSON result has object or array?

sorry folks. I'm pretty new to writing code...

I'm writing a powershell cmdlet in c# and it reaches out to an API and gets JSON as a response.

Depending on the call I make to an API, a JSON array or a single JSON object is returned

Sometiems, it can be

{"result": [
{
"id": "24095",
"hostid": "24094",
"name": "host1.fqdn.com",
"clustered": "false",
"type": "VM",
"ipaddress" : "192.168.1.184"
},
{
"id": "24097",
"hostid": "24096",
"name": "host2.fqdn.com",
"clustered": "true",
"type": "VM",
"ipaddress" : "192.168.1.185"
}
]
}

and sometimes it can be

{"result": {
"id": "24095",
"hostid": "24094",
"name": "host1.fqdn.com",
"clustered": "false",
"type": "VM",
"ipaddress" : "192.168.1.184"
}
}

I'm trying to figure out how using JSON.NET, i can figure out if the json returned has an object for "result" or an array for "result".

Based on the check,I'd like to call a method that prints out the object or array in a CSV format

I'm hoping to write a generic method that will print out all the keys as the CSV header and the values as rows for the CSV.

But the first thing I'm having trouble with is figuring out whether my JSON object has an Array or just an Object

I tried

JObject jsonres = JObject.Parse(strResponse);
JObject appobj = (JObject)jsonres.SelectToken("result");

Console.WriteLine(appobj.Type.ToString());

results in

Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.

when appobj["result"] is an array and works just fine and prints "Object" when appobj["result"] is a single object.

Upvotes: 5

Views: 11440

Answers (4)

dea
dea

Reputation: 21

This is quite an old question, but I've got an answer for the System.Text.Json namespace in case you do not want to use the Newtonsoft.Json namesapce. There is also a Parse method within JsonDocument where you can determine the class of the root element.

var JDocument = System.Text.Json.JsonDocument.Parse(json);
if (JDocument.RootElement.ValueKind == JsonValueKind.Object)
{
    //Object
}

if (JDocument.RootElement.ValueKind == JsonValueKind.Array)
{
    //Array or List
}

Upvotes: 2

zhuber
zhuber

Reputation: 5524

You could create JsonConverter for that e.g.

public class SingleOrListJsonConverter : JsonConverter
{
    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.ReadFrom(reader);
        switch (token.Type)
        {
            case JTokenType.Object:
                var item = token.ToObject<MyResultType>();
                return new List<MyResultType>(new[] {item});
            case JTokenType.Array:
                return token.ToObject<List<MyResultType>>();
            default:
                return new List<MyResultType>();
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(List<MyResultType>) || objectType == typeof(MyResultType);
    }
}

and then just decorate your property with this converter

public class MyClass
{
    [TypeConverter(typeof(SingleOrListJsonConverter))]
    public MyResultType Result { get; set; }
}

I guess we could even make this converter generic, but this is just a simple example.

Upvotes: 0

Tyress
Tyress

Reputation: 3653

This will work:

   JObject jsonres = JObject.Parse(json);
   Console.WriteLine(jsonres["result"].Type);

To find out whether it's an Object or Array. You can use a switch-case on the enum:

            switch(jsonres["result"].Type)
            {
                case JTokenType.Object:
               //Do something if it's an object
                    break;
                case JTokenType.Array:
                //Do something if it's an array
                    break;
            }

Upvotes: 4

bit
bit

Reputation: 4487

Not sure if this the optimum way to handle it, but you could use something like this:

if ( jsonres.SelectToken("result") is JObject )
{ ... }
else if ( jsonres.SelectToken("result") is JArray)
{ ... }
else
{ ...some exception perhaps }

Edit: Slight improvisation

if ( jsonres.SelectToken("result") is JObject )
{ //Create JArray with the lone "result" in it }

//Use the JArray 

Upvotes: 7

Related Questions