Reputation: 543
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
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
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
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
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