Looping through JObject nested array - c#

I can not figure out exactly how to did through this JObject in order to retrieve the id property under runs.
I have this following code which will successfully give me the id property that is under entries, but how can I nest this again to go into the runs sections and get those ID's?
JSON:
{
"id": 168,
"name": "section 1",
"entries": [
{
"id": "908-9876-908",
"suite_id": 15,
"name": "List 1",
"runs": [
{
"id": 169,
"suite_id": 15
}
]
},
{
"id": "998-4344-439",
"suite_id": 16,
"name": "List 2",
"runs": [
{
"id": 170,
"suite_id": 16
}
]
}
]
}
C# Code:
JObject obj = JsonConvert.DeserializeObject<JObject>(response);
foreach (JObject id in obj["entries"])
{
string returnable = (string)id["id"];
Console.WriteLine(returnable);
}
I have tried looking at ["entries"]["runs"] but that also was not working.
The print out of this is:
908-9876-908
998-4344-439
What I would like is
169
170

You can achieve it using the following code
var jsonObject = JObject.Parse(json);
foreach (var entry in jsonObject["entries"])
{
foreach (var run in entry["runs"])
{
string returnable = (string)run["id"];
Console.WriteLine(returnable);
}
}
You would like to see
169
170
They are an id values from runs array, therefore you should enumerate them in the inner loop. You've also missed a comma after "name": "section 1"

You can use SelectTokens() to query for nested data inside a JToken hierarchy. It provides support for JSONPath queries including wildcards [*] for arrays:
var ids = obj.SelectTokens("entries[*].runs[*].id").Select(i => (long)i).ToList();
See: Querying JSON with complex JSON Path.
Demo fiddle here.

Related

How to access inner properties of a Json Object?

I am learning C# and I am trying to parse json/xml responses and check each and every key and value pair. For xml I am converting to json so I have only one function/script to work with both cases. My issue is that I am working with a wide range of json responses which are not similar and there may be arrays in some of the json response. I have tried accessing the "Count" of the json object as a way to check for arrays.
Note: The responses will vary. This example is for Products > Product > name, quantity and category. The next response will change and can be like Country > State > Cities and so on. I cannot rely on creating classes since all responses are going to be different. Plus I am working on automating it so it should be able to handle anything thrown at it.
Sample Json I am working with:
{
"products": {
"product": [
{
"name": "Dom quixote de La Mancha",
"quantity": "12",
"category": "Book"
},
{
"name": "Hamlet",
"quantity": "3",
"category": "Book"
},
{
"name": "War and Peace",
"quantity": "7",
"category": "Book"
},
{
"name": "Moby Dick",
"quantity": "14",
"category": "Book"
},
{
"name": "Forrest Gump",
"quantity": "16",
"category": "DVD"
}
]
}
The way I am accessing the count, name and value is as follows:
dynamic dyn = JsonConvert.DeserializeObject<dynamic>(jsonText);
foreach (JProperty property in dyn.Properties())
{
string propname = property.Name;
var propvalue = property.Value;
int count = property.Count;
}
Is there a way to access these without going through the foreach loop like int count = dyn.Count ? All I am getting from this is null instead of actual values.
For the above example my end result will be like:
This responses contains products> product> 5 x (name, quantity, category)
The QuickWatch for the object:
QuickWatch for dyn object
Try to deserialize your JSON into JObject like below:
var jObject = JsonConvert.DeserializeObject<JObject>(jsonText);

C# How to combine multiple JSON arrays that are part of a List?

What has been done so far?
I am working on dividing up the number of records into 3 batches and processing them in parallel to increase the performance. However, after processing the batches in parallel I would also like to save the outcome (JSON string) of the processed records in a variable.
As you can see below, I first initialize the variable as List of string and then run the foreach loop which saves the processed outcome as mentioned below.
List<string> responseOutcome = new List<string>();
Parallel.ForEach(recordBatches, batch => {
responseOutcome.Add(response1.Content);
});
Result in List responseOutcome comes as:
responseOutcome[0]
[
{
"Name": "Sample1",
"ID": "123"
},
{
"Name": "Sample2",
"ID": "394"
}
],
responseOutcome[1]
[
{
"Name": "Sample5",
"ID": "384"
},
{
"Name": "Sample6",
"ID": "495"
}
],
responseOutcome[2]
[
{
"Name": "Sample3",
"ID": "473"
},
{
"Name": "Sample4",
"ID": "264"
}
]
What I would like to achieve?
Now I would like to take the value of responseOutcome which is multiple arrays of JSON string and merge them into one big JSON string.
Final Output
[
{
"Name": "Sample1",
"ID": "123"
},
{
"Name": "Sample2",
"ID": "394"
},
{
"Name": "Sample5",
"ID": "384"
},
{
"Name": "Sample6",
"ID": "495"
},
{
"Name": "Sample3",
"ID": "473"
},
{
"Name": "Sample4",
"ID": "264"
}
]
I looked into several similar cases but they weren't nearly similar. Like:
How do I merge multiple json objects
How do I combine two arrays from two JObjects in Newtonsoft JSON.Net?
Any help/guidance will be great!!
Using Newtonsoft, you can create a JArray from each of your responses. Then you can flatten the hierarchy using linq's SelectMany method and re-serialize the object.
Try this:
var obj = responses.Select(r => JArray.Parse(r.Trim(','))).SelectMany(token => token);
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
There are probably more efficient ways to do this if you want to do pure string manipulation, but using Newtonsoft, I would deserialize, merge and then re-serialize.
Create a small POCO model:
public class ResponseOutcomeModel
{
public string ID { get; set; }
public string Name { get; set; }
}
Then deserialize to this model, merge and reserialize to JSON as a single list.
var outcomeList = new List<ResponseOutcomeModel>();
foreach (var i in responseOutcome)
{
outcomeList.AddRange(JsonConvert.DeserializeObject<List<ResponseOutcomeModel>>(i.Trim().TrimEnd(',')));
}
var finalJson = JsonConvert.SerializeObject(outcomeList);
Note, the Time/TrimEnd is used if the trailing commas in your example are really there in your responseOutcome array (at the end of each element in the array). The call to DeserializeObject will complain if you leave the commas in there.

JObject parse returns extra curly braces

I have a variable projectData that contains a valid json string that is stored in a database.
After doing the following:
JObject obj = new JObject();
obj = JObject.Parse(projectData);
Instead of getting
{
"devices": {
"device_A": {
"id": "12345",
"name": "test",
"enabled": true
}
}
}
I get this instead:
{{
"devices": {
"device_A": {
"id": "12345",
"name": "test",
"enabled": true
}
}
}}
So basically an aditional { and } were added to my json string.
I have also tried the following:
obj = JsonConvert.DeserializeObject<JObject>(projectData);
and it didnt work.
Why is this a problem to me?
I want to iterate over the obj["devices"] array, and when I do the following
foreach(var d in obj["devices"])
It simply doesnt work because of the double curly braces.
Is there a solution to my problem?
Thank you
{
"devices": {
"device_A": {
"id": "12345",
"name": "test",
"enabled": true
}
}
}
Your json shows devices as a json object and not an array. You cannot iterate over it with a for loop.
You can access the data by parsing it first and then accessing the properties by using the [] brackets.
var obj = JObject.Parse(jsonString);
Console.WriteLine(obj["devices"]["device_A"]["id"].Value<string>());
//prints
12345
// To Loop through multiple devices... you can use this.
foreach (var device in ((JObject)obj["devices"]).Properties())
Console.WriteLine(obj["devices"][device.Name]["id"]);
Also, when you are using the debug mode, the watch or locals will show {{ }} because the braces are escaped.
Array version of Json
If your json looked like below, then you can use the for loop to access the elements of the JArray.
{
"devices": [
{
"device_A": {
"id": "12345",
"name": "test",
"enabled": true
}
}
]
}
with the above json, you can use the for loop in the following way,
var obj = JObject.Parse(json);
foreach (var device in obj["devices"])
Console.WriteLine(device["device_A"]["id"]);
// Prints
12345

Linq query to Json string

starting from a JObject I can get the array that interests me:
JArray partial = (JArray)rssAlbumMetadata["tracks"]["items"];
First question: "partial" contains a lot of attributes I'm not interested on.
How can I get only what I need?
Second question: once succeeded in the first task I'll get a JArray of duplicated items. How can I get only the unique ones ?
The result should be something like
{
'composer': [
{
'id': '51523',
'name': 'Modest Mussorgsky'
},
{
'id': '228918',
'name': 'Sergey Prokofiev'
},
]
}
Let me start from something like:
[
{
"id": 32837732,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Of Thee I Sing: Overture (radio version)"
},
{
"id": 32837735,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Concerto in F : I. Allegro"
},
{
"id": 32837739,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Concerto in F : II. Adagio"
}
]
First question:
How can I get only what I need?
There is no magic, you need to read the whole JSON string and then query the object to find what you are looking for. It is not possible to read part of the JSON if that is what you need. You have not provided an example of what the data looks like so not possible to specify how to query.
Second question which I guess is: How to de-duplicate contents of an array of object?
Again, I do not have full view of your objects but this example should be able to show you - using Linq as you requested:
var items = new []{new {id=1, name="ali"}, new {id=2, name="ostad"}, new {id=1, name="ali"}};
var dedup = items.GroupBy(x=> x.id).Select(y => y.First()).ToList();
Console.WriteLine(dedup);

Merge 3 different json arrays in one object

I have three different arrays which I want to merge them into a single object.
array 1 : [{"Id":1,"Number":"1234","Category":"Chocalte", "Status": "Error"}]
heatingissues: [{"myId":3,"Id":"5801"}]
problemissue: [{"myId":1,"Id":2,"Name":"Desktop"}]
I want result to be like this:
{
"Id": 3,
"Number": "1190042293",
"Category": "Chocalte",
"heatingissues": [
{
"myId": 3,
"id": "5801"
}
],
"problemissue": [
{
"myId": 1,
"name": "Desktop"
}
]
}
After deserializing all the arrays individually (respectively to the results and problemissueresults variables) I try:
var j = JsonConvert.SerializeObject(new{
results,
heatingissues= problemissueresults,
problemissue= problemissueresults
});
Which generates the following output:
{
"results": [
{
"id": 3,
"Number": "1190042293",
"category": "Chocalte"
}
],
"heatingissues": [
{
"myId": 3,
"id": "5801"
}
],
"problemissue": [
{
"myId": 1,
"name": "Desktop"
}
]
}
How can I avoid these results?
In this case, you need to declare explicitly the properties of the object you are serializing to match the format you want.
In words of the documentation for C# Anonymous Types:
If you do not specify member names in the anonymous type, the compiler gives the anonymous type members the same name as the property being used to initialize them
So your result was being serialized as an array with a json key of the same name.
Try this:
var obj =
new
{
id = results[0].id,
number = results[0].number,
category = results[0].category,
heatingissues= problemissueresults,
problemissue= problemissueresults
};
var j = JsonConvert.SerializeObject(obj);
Newtonsoft json library support merging operation.
http://www.newtonsoft.com/json/help/html/MergeJson.htm

Categories