Access child objects from nested JSON - c#

I have a JSON string, which is srtuctered as per the below.
"total": 5,
"filtered": 5,
"items": [
{
"assignedProducts": [
"antivirus"
],
"cloned": false,
"device_encryption_status_unmanaged": false,
"java_id": "2408cf5b-669c-434e-ac4c-a08d93c40e6a",
"last_activity": "2019-09-20T12:36:22.175Z",
"last_user_id": "5c6bc52305f05316ba18db06",
"heartbeat_utm_name": null,
"group_full_name": null,
"is_adsync_group": false,
"is_caching_proxy": false,
"info": {
"processor_architecture": "x64",
"osMajorVersion": 10,
"computer_name": "INDPC01",
"isServer": false,
"osInstallationType": "Client",
"fqdn": "INDPC01",
"osName": "Windows 10 Pro N",
"id": "4280fcb5-66c9-34e4-cac4-0ad8394ce0a6",
"name": "INDPC01"
},
I am using the following code to get values from a JSON string.
var resultObjects = AllChildren(JObject.Parse(response.Content))
.First(c => c.Type == JTokenType.Array && c.Path.Contains("items"))
.Children<JObject>();
foreach (JObject result in resultObjects)
{
foreach (JProperty property in result.Properties())
{
ListBox1.Items.Add(property.Name.ToString() + " - " + property.Value.ToString());
}
}
}
private static IEnumerable<JToken> AllChildren(JToken json)
{
foreach (var c in json.Children())
{
yield return c;
foreach (var cc in AllChildren(c))
{
yield return cc;
}
}
}
I am able to get all the values for everything within "Items", however I am not sure how to access the child JSON objects, for example the information under "info"

You can access childs using indexer, e.g.:
// ...
foreach (JObject result in resultObjects)
{
var architecture = result["info"]["processor_architecture"].ToString();
// ...
}
Note that it might be an easier approach to convert the JSON to an object, e.g. using JsonConvert, instead using JObject.Parse.

Related

C# If a condition is met, use the result and run it through the same method

I am polling APIs that return different types of JSON strings in the same formats that contain lists, within lists, within lists. Here is an example:
[
{
"name": "string",
"production": true,
"start_timestamp": "string",
"end_timestamp": "string",
"width": 0,
"height": 0,
"scale": 0,
"floors": [
{
"number": 0,
"display_name": "string",
"map_image_url": "string",
"inside_image_url": "string",
"zone_maps": [
{
"name": "string",
"display_name": "string",
"zone_image_url": "string",
"zones": [
{
"name": "string",
"display_name": "string",
"color": "string"
}
]
}
]
}
]
}
]
I am trying to create a dynamic method that I can us for all APIs that get the values of all the properties of the first list and concatenate them into a string for csv. Then if another list is found within these properties, go through the same method again until there are no more lists. Here is my current example code:
public static string DelimetedString(object obj)
{
List<string> lineItem = new List<string>();
Type myObject = obj.GetType();
foreach (var v in myObject.GetProperties())
{
var objType = v.PropertyType.Name;
if (objType.Contains("List"))
{
DelimetedString(v); //It is here where I would like to loop through the next list
}
else
{
var value = v.GetValue(obj, null);
if (value == null)
{
lineItem.Add("");
}
else
{
lineItem.Add(value.ToString());
}
}
}
return string.Join(",", lineItem);
}
The end goal is to have column headers that contain the property names, and the data for each property under this in a delimited format. Thanks in advance for any help!
EDIT: Sorry, I should have expanded on this. I do use Newtonsoft to deserialize into a json object.
MyClass _myObject = JsonConvert.DeserializeObject<MyClass>(responseJson);
I then send that object to the DelimetedString() function.
For a problem like this you can do two things:
Create a data model for the incoming json object, or
use a object of type "dynamic"
I strongly recommend using Json.NET by Newtonsoft for deserializing json.
https://www.newtonsoft.com/json
How about this?:
public static string GetCsvFromJson(JToken node)
{
var result = "";
if (!node.HasValues)
return node.ToString();
foreach (var child in node.Children())
{
result += GetCsvFromJson(child) + ",";
}
return result.TrimEnd(',');
}
calling it:
string commaSeparatedValues = GetCsvFromJson(JToken.Parse(yourJsonString));
If you already serialized the json value, I will try to edit your function then. Instead of checking the type name if it contains list, it is not safe btw, you can go further until the object is value type or string (string is a reference type):
public static string DelimetedString(object obj)
{
var result = "";
if (obj.GetType().IsValueType || obj is string)
return obj.ToString();
if (obj is IEnumerable)
{
foreach (var item in (IEnumerable)obj)
{
result += DelimetedString(item) + ",";
}
}
else
{
foreach (var prop in type.GetProperties())
{
result += DelimetedString(prop.GetValue(obj)) + ",";
}
}
return result.TrimEnd(',');
}

Get chrome bookmarks from json

I want to scrape chrome bookmarks using json object. What I want to do is get all bookmarks from 1 folder. That is the structure of the json:
{
"checksum": "d499848083c2c2e3a38f547da4cbad7c",
"roots": {
"bookmark_bar": {
"children": [ {
"children": [ {
"url": "https://www.example.com/"
}, {
"url": "https://www.another-example.com/"
} ],
"name": "foo",
} ],
"name": "Menu bookmarks",
},
"other": {
"name": "Another bookmarks",
},
"synced": {
"name": "Phone bookmarks",
}
},
"version": 1
}
In this case I want to get urls from folder foo. I am using Json.NET to convert string into object. This code:
string input = File.ReadAllText(bookmarksLocation);
using (StringReader reader = new StringReader(input))
using (JsonReader jsonReader = new JsonTextReader(reader)) {
JsonSerializer serializer = new JsonSerializer();
var o = (JToken)serializer.Deserialize(jsonReader);
var allChildrens = o["roots"]["bookmark_bar"]["children"];
var fooFolder = allChildrens.Where(x => x["name"].ToString() == "foo");
foreach (var item in fooFolder["children"]) {
Console.WriteLine(item["url"].ToString());
}
Console.ReadKey();
}
Is giving me an error:
Cannot apply indexing with [] to an expression of type 'IEnumerable<JToken>'
Can you tell me what I did wrong?
there is 1 loop is missing:
var fooFolder = allChildrens.Where(x => x["name"].ToString() == "foo");
foreach (var folder in fooFolder)
{
foreach (var item in folder["children"])
{
Console.WriteLine(item["url"].ToString());
}
}

Read json without knowing the key in c#

I want to parse the below mentioned JSON and get all values of screenshot.thumbnailUrl. But below are my constraints:
Not all nodes have screenshot. In this example only "weather" and "entities" have it.
I do not know the node names. In this example I didn't know that there would be a node named "weather" or "entities". These nodes are auto generated based on the query i made to get the json.
There are two possible places where screenshot can be present. (1) In the child of rootobject e.g. weather.screenshot (2) In all values of child of rootobject e.g. entities.value[0].screenshot, entities.value[1].screenshot etc.
{ "_type": "SearchResponse", "queryContext": {}, "webPages": {}, "entities": {
"queryScenario": "DominantEntity",
"value": [
{
"_type": "Place",
"id": "https://www.someapi.com/api/v6/#Entities.0",
"screenshot": {
"thumbnailUrl": "http://Screenshot_URL_I_Want",
"width": 285
},
"name": "Seattle",
"entityPresentationInfo": {},
"bingId": "5fbba6b8-85e1-4d41-9444-d9055436e473",
"boundingBox": [],
"weather": {},
"timeZone": "Pacific Standard Time"
}
] }, "images": {}, "weather": {
"id": "https://www.someapi.com/api/v6/#Weather",
"screenshot": {
"thumbnailUrl": "http://Screenshot_URL_I_Want",
"width": 285
},
"location": {},
"currentWeather": {},
"dailyForecast": [] }, "rankingResponse": {} }
This is what worked for me... I am looking for a cleaner solution though...
static async void getJobject(string jsonstring)
{
JObject response = await JObject.Parse(jsonstring);
foreach (var node in response.Children())
{
Console.WriteLine(node.Path);
string propertyPath = node.Path + ".screenshot.thumbnailUrl";
var token = response.SelectToken(propertyPath);
if (token != null)
{
Console.WriteLine("Check this=> " + token.ToString()); //Prints screenshot URL from weather
}
else
{
propertyPath = node.Path + ".value";
token = response.SelectToken(propertyPath);
if (token != null)
{
int count = token.Children().Count();
for (int i = 0; i < count; i++)
{
propertyPath = node.Path + ".value" + "[" + i.ToString() + "]" + ".screenshot.thumbnailUrl";
var mytoken = response.SelectToken(propertyPath);
if (mytoken != null)
{
Console.WriteLine("Check this=> " + mytoken.ToString()); //Prints screenshot URL from entities
}
}
}
}
}
}
You could use code like this to parse the JSon and recursively iterate through it. You will have to probably refine the logic in the lambda of the call to RecursiveDescent to make it correct and robust for your type of JSON:
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string json = #"....your JSON ....";
var node = JToken.Parse(json);
RecursiveDescent(node, n =>
{
JToken url = n["thumbnailUrl"];
if (url != null && url.Type == JTokenType.String)
{
var nodeWeWant = url?.Parent?.Parent?.Parent?.Parent;
Console.WriteLine(nodeWeWant.ToString());
}
});
}
static void RecursiveDescent(JToken node, Action<JObject> action)
{
if (node.Type == JTokenType.Object)
{
action((JObject)node);
foreach (JProperty child in node.Children<JProperty>())
RecursiveDescent(child.Value, action);
}
else if (node.Type == JTokenType.Array)
{
foreach (JToken child in node.Children())
RecursiveDescent(child, action);
}
}
}
}

Looping through multiple JObject levels and gathering information as a string

I'm using the following code to gather Json data from a URL.
var json = new WebClient().DownloadString("http://steamcommunity.com/id/tryhardhusky/inventory/json/753/6");
JObject jo = JObject.Parse(json);
JObject ja = (JObject)jo["rgDescriptions"];
int cCount = 0;
int bCount = 0;
int eCount = 0;
foreach(var x in ja){
// I'm stuck here.
string type = (Object)x["type"];
}
CUAI.sendMessage("I found: " + ja.Count.ToString());
Everything is working well until I get to the foreach statement.
Here is a snippet of the JSON Data.
{
"success": true,
"rgInventory": {
"Blah other stuff"
},
"rgDescriptions": {
"637390365_0": {
"appid": "753",
"background_color": "",
"type": "0RBITALIS Trading Card"
"175240190_0": {
"appid": "753",
"background_color": "",
"type": "Awesomenauts Trading Card"
},
"195930139_0": {
"appid": "753",
"background_color": "",
"type": "CONSORTIUM Emoticon"
}
}
}
I'm wanting to loop through each item in rgDescriptions and get the type data as a string, Then check if it contains either background, emoticon or trading card.
I know I can use the if(type.Contains("background")) to check what the item type is, But I'm having trouble with the foreach loop.
If I use foreach(JObject x in ja) I get a cannot convert type Error.
If I use foreach(Object x in ja) It comes up with a Cannot apply indexing of type object.
This error also happens when I use foreach(var x in ja) and string type = (JObject)x["type"];
Can anyone tell me what I'm doing wrong, Please?
You have some errors in your JSON. Check it with jsonlint.com. I think it should look something like this:
{
"success": true,
"rgInventory": {
"Blah other stuff": ""
},
"rgDescriptions": {
"637390365_0": {
"appid": "753",
"background_color": "",
"type": "0RBITALIS Trading Card"
},
"175240190_0": {
"appid": "753",
"background_color": "",
"type": "Awesomenauts Trading Card"
},
"195930139_0": {
"appid": "753",
"background_color": "",
"type": "CONSORTIUM Emoticon"
}
}
}
You can use the JProperty, JToken and the SelectToken Method to get the type:
var json = new WebClient().DownloadString("http://steamcommunity.com/id/tryhardhusky/inventory/json/753/6");
JObject jo = JObject.Parse(json);
foreach (JProperty x in jo.SelectToken("rgDescriptions"))
{
JToken type = x.Value.SelectToken("type");
string typeStr = type.ToString().ToLower();
if (typeStr.Contains("background"))
{
Console.WriteLine("Contains 'background'");
}
if (typeStr.Contains("emoticon"))
{
Console.WriteLine("Contains 'emoticon'");
}
if (typeStr.Contains("trading card"))
{
Console.WriteLine("Contains 'trading card'");
}
}

Unable to get data from Json Object

I am fetching some data from external Webservice and parsing it to json using Newtonsoft.Json.Linq
like this
JObject o = JObject.Parse(json);
JArray sizes = (JArray) o["data"];
Now the Sizes looks like this
{
[
{
"post_id": "13334556777742_6456",
"message": "messagecomes her",
"attachment": {
"media": [
{
"href": "http://onurl.html",
"alt": "",
"type": "link",
"src": "http://myurl.jpg"
}
],
"name": "come to my name",
"href": "http://mydeeplink.html",
"description": "",
"properties": [],
},
}
]
}
I need to get "src": "http://myurl.jpg"element from this Json array.
I have tried:
foreach (JObject obj in sizes)
{
JArray media = (JArray)obj["attachment"];
foreach (JObject obj1 in media)
{
var src = obj1["src"];
}
}
But it's throwing an error:
Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Newtonsoft.Json.Linq.JArray'.
at this line
JArray media = (JArray)obj["attachment"];
Can any one give me a hand on this?
Try fix line
JArray media = (JArray)(obj["attachment"]);
to
JArray media = (JArray)(obj["attachment"]["media"]);
This is how I handled a scenario that sounds just like yours:
public static IList<Entity> DeserializeJson(JToken inputObject)
{
IList<Entity> deserializedObject = new List<Entity>();
foreach (JToken iListValue in (JArray)inputObject["root"])
{
Entity entity = new Entity();
entity.DeserializeJson(iListValue);
deserializedObject.Add(entity);
}
return deserializedObject;
}
public virtual void DeserializeJson(JToken inputObject)
{
if (inputObject == null || inputObject.Type == JTokenType.Null)
{
return;
}
inputObject = inputObject["entity"];
JToken assertions = inputObject["assertions"];
if (assertionsValue != null && assertionsValue.Type != JTokenType.Null)
{
Assertions assertions = new Assertions();
assertions.DeserializeJson(assertionsValue);
this.Assertions = assertions;
}
// Continue Parsing
}

Categories

Resources