Deserializing nested JSON array inside nested JSON object in c#? - c#

I have a json file as follows:
{
"container" : {
"cans1" :
[
{
"name" : "sub",
"ids" :
[
"123"
]
},
{
"name" : "Fav",
"ids" :
[
"1245","234"
]
},
{
"name" : "test",
"ids" :
[
"DOC12","DOC1234"
]
}
],
"ids" :
[
"1211","11123122"
],
"cans2" :
[
{
"name" : "sub1",
"ids" :
[
"123"
]
}
],
"ids" :
[
"121","11123"
]
}
I want to fetch name values sub,fav,test and ids for each cans in this json file using c#

Install nuget Newtonsoft.Json. Create next hierarchy:
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public class MyClass
{
[JsonProperty("container")]
public Container Container { get; set; }
}
public class Container
{
[JsonProperty("cans1")]
public Cans[] Cans1 { get; set; }
[JsonProperty("ids")]
[JsonConverter(typeof(DecodeArrayConverter))]
public long[] Ids { get; set; }
[JsonProperty("cans2")]
public Cans[] Cans2 { get; set; }
}
public class Cans
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("ids")]
public string[] Ids { get; set; }
}
And then
JsonConvert.DeserializeObject<MyClass>(yourJsonString);
UPD
Based on comment, try this:
var des = JsonConvert.DeserializeObject<MyClass>(t);
foreach(var arr in des.Container.Where(r => r.Key.StartsWith("cans")))
{
Console.WriteLine($"{arr.Key}");
foreach(var elem in arr.Value)
{
Console.WriteLine($" {elem.Value<string>("name")}");
}
}
public class MyClass
{
[JsonProperty("container")]
public Dictionary<string, JArray> Container { get; set; }
}

Related

Deserialize JSON file with different keys

I have a json like this:
[
{ "Province1" : [
{ "name" : "city-1" },
{ "name" : "city-2" }
]
},
{ "Province2" : [
{ "name" : "city-1" },
{ "name" : "city-2" }
]
}
]
I want to deserialize it using NewtonsoftJson. I have tried this but the result is null:
public class City {
public string Name { get; set; }
}
var cities = JsonConvert.DeserializeObject<IEnumerable<KeyValuePair<string, List<City>>>(File.ReadAllText(#"jsonPath"));
How should I dersialize it to a class?
After fiddling around with it a bit, I've come up with this structure to deserialize it
class MyDeserializer
{
public static void Deserialize()
{
var json = "[{\"Province1\" : [{\"name\" : \"city-1\" }, {\"name\" : \"city-2\" }] }, {\"Province2\" : [{ \"name\" : \"city-1\" }, { \"name\" : \"city-2\" }] } ]";
var cities = JsonConvert.DeserializeObject<List<Dictionary<string, List<City>>>>(json);
Console.WriteLine(cities[0]["Province1"][0].Name);
}
}
class City
{
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
}
That gives you a dictionary for each province which seems a little unintuitive. But that's how your JSON is structured. If you want to combine all the dictionaries into one, you can do it like this
var cities = JsonConvert.DeserializeObject<List<Dictionary<string, List<City>>>>(json).SelectMany(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value);
Console.WriteLine(cities["Province1"][0].Name);
There is probably a more elegant solution to this, however this will give you a dictionary of province name with an array of city name Dictionary<string,string[]>
var dict = JArray
.Parse(input)
.Cast<JObject>()
.Select(x => x.Properties().First())
.ToDictionary(
x => x.Name,
x => x.Values().Values().Select(x => x.First.ToString()).ToArray());
I think your structure should be like this :
[
{ "Name": "Province1",
"Cities": [
{ "name": "city-1" },
{ "name": "city-2" }
]
},
{ "Name": "Province2",
"Cities": [
{ "name": "city-1" },
{ "name": "city-2" }
]
}
]
And to deserilize it :
namespace ConsoleApp2 {
public class Province {
public string Name { get; set; }
public List<City> Cities { get; set; }
}
public class City {
public string Name { get; set; }
}
public class ConsoleApp2 {
public static void Main(string[] args) {
List<Province> provinces = JsonConvert.DeserializeObject<List<Province>>(File.ReadAllText("province.json"));
}
}
}

How to convert JSON to object with C#

I am having trouble accessing the properties in my json file. I need to create a c# object with it too. It is not able to work properly. This requires the need to drill down several classes, where I cannot find any other documentation on it, as most use a very simple json file.
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties":
{
"TYPE": "COASTAL",
"R_STATEFP": "28",
"L_STATEFP": ""
},
"geometry":
{
"type": "LineString",
"coordinates": [
[ -88.453654, 30.196584 ],
[ -88.428301, 30.198511 ],
[ -88.404581, 30.206162 ],
[ -88.401466, 30.210172 ],
[ -88.430332, 30.208548 ],
[ -88.442654, 30.202314 ],
[ -88.453444, 30.201236 ],
[ -88.465713, 30.202540 ],
[ -88.500011, 30.214044 ],
[ -88.506999, 30.214348 ],
[ -88.502752, 30.210506 ],
[ -88.493523, 30.205945 ],
[ -88.453654, 30.196584 ]
]
}
},
//repeated 100+ times
]
}
This is my classes file:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MyApp
{
public class FeatureCollection
{
public string type{ get; set; }
public List<Feature> features{ get; set; }
[JsonConstructor]
public FeatureCollection(JObject i)
{
var typeProp = i.GetType().GetProperty("type");
this.type = typeProp.GetValue(i) as string;
JArray features = (JArray)i.GetValue("features");
this.features = new List<Feature>();
foreach (JObject f in features)
{
this.features.Add(new Feature(f));
Console.Write(features);
}
}
}
public class Feature
{
public string type;
public Property properties;
public Geometry geometry;
[JsonConstructor]
public Feature(JObject i)
{
var typeProp = i.GetType().GetProperty("type");
this.type = typeProp.GetValue(i) as string;
var prop = i.GetValue("properties") as JObject;
this.properties = new Property(prop);
var geo = i.GetValue("geometry") as JObject;
this.geometry = new Geometry(geo);
}
}
public class Property
{
public string TYPE;
public string R_STATEFP;
public string L_STATEFP;
[JsonConstructor]
public Property(JObject i)
{
var typeProp = i.GetType().GetProperty("TYPE");
this.TYPE = typeProp.GetValue(i) as string;
var typeR = i.GetType().GetProperty("type");
this.R_STATEFP = typeR.GetValue(i) as string;
var typeL = i.GetType().GetProperty("type");
this.L_STATEFP = typeL.GetValue(i) as string;
}
}
public class Geometry
{
public string type;
public List<Coord> coordinates;
[JsonConstructor]
public Geometry(JObject i)
{
var typeProp = i.GetType().GetProperty("type");
this.type = typeProp.GetValue(i) as string;
JArray coordinates = (Newtonsoft.Json.Linq.JArray)i.GetValue("coordinates");
this.coordinates = new List<Coord>();
foreach (JArray c in coordinates)
{
this.coordinates.Add(new Coord(c));
}
}
}
public class Coord
{
public double longitude;
public double latitude;
[JsonConstructor]
public Coord(JArray a){
this.longitude = (double)a[0];
this.latitude = (double)a[1];
}
}
}
Also, what is the best way to open such a large file in the main (assume it will be 100+ features) will streamreader be the best route?
Thank you
You can simplify your design quite a bit.
If you make your classes just plain ol' classes that represent your data:
public class Properties
{
public string Type { get; set; }
[JsonProperty(PropertyName = "R_STATEFP")]
public string RState { get; set; }
[JsonProperty(PropertyName = "L_STATEFP")]
public string LState { get; set; }
}
public class Geometry
{
public string Type { get; set; }
public List<List<double>> Coordinates { get; set; }
}
public class Feature
{
public string Type { get; set; }
public Properties Properties { get; set; }
public Geometry Geometry { get; set; }
}
public class RootObject
{
public string Type { get; set; }
public List<Feature> Features { get; set; }
}
You can then use JsonConvert.DeserializeObject<T>() to deserialize (and in the inverse JsonConvert.Serialize() to serialize).
RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(jsonString);
You can see it in action here

JSON Object from C#

I am trying to acheive below JSON Object from c# code
{
"Animals": {
"name": "Animals",
"data": [
[
"Cows",
2
],
[
"Sheep",
3
]
]
},
"Fruits": {
"name": "Fruits",
"data": [
[
"Apples",
5
],
[
"Oranges",
7
],
[
"Bananas",
2
]
]
},
"Cars": {
"name": "Cars",
"data": [
[
"Toyota",
1
],
[
"Volkswagen",
2
],
[
"Opel",
5
]
]
}
}
I tried json2C# link and it gave me this class structure
public class Animals
{
public string name { get; set; }
public List<List<object>> data { get; set; }
}
public class Fruits
{
public string name { get; set; }
public List<List<object>> data { get; set; }
}
public class Cars
{
public string name { get; set; }
public List<List<object>> data { get; set; }
}
public class RootObject
{
public Animals Animals { get; set; }
public Fruits Fruits { get; set; }
public Cars Cars { get; set; }
}
My first problem is the classes generated by code is static (Animals,Fruits,Cars) in reality it could be more and less it is category and it may be some new categories so every time I need to create a new class for each category? how can I handle this?
Second how I populate from these classes the same structure.
Please bear with me as I am very beginner level programmer.
Try this. Create a new console application. You will need the JSON.NET library.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
namespace ConsoleApplication7
{
class Item : List<object>
{
public Item()
{
this.Add(""); // for name;
this.Add(0); // for value;
}
[JsonIgnore]
public string Name { get { return this[0].ToString(); } set { this[0] = value; } }
[JsonIgnore]
public int Value { get { return (int)this[1]; } set { this[1] = value; } }
}
class Category
{
public string name { get; set; }
public List<Item> data { get; set; }
public Category()
{
this.data = new List<Item>();
}
}
class Program
{
static void Main(string[] args)
{
var all = new Dictionary<string, Category>
{
{
"Animals", new Category()
{
name = "Animals",
data =
new List<Item>()
{
new Item() {Name = "Cows", Value = 2},
new Item() {Name = "Sheep", Value = 3}
}
}
//include your other items here
}
};
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(all));
Console.ReadLine();
}
}
}
You don't need separate Animals, Fruits, etc. classes. They can be merged.
public class Category
{
public string name { get; set; }
public List<List<object>> data { get; set; }
}
And since the list of items in the root object can change, you should use a Dictionary<string, Category> instead of the RootObject class you had generated. Your JSON is not valid, (test it with http://jsonlint.com/), but this produces something like the first part of your example:
var dict = new Dictionary<string, Category>
{
{ "Animals", new Category
{
name = "Animals",
data = new List<List<object>>
{
new List<object> { "Cows", 2 },
new List<object> { "Sheep", 3 }
}
}
},
};
string serialized = JsonConvert.SerializeObject(dict, Formatting.Indented);
Produces the following (I'm using Json.NET for the serialization here). The other types would be similar. (see Object and Collection Initializers for more info on the list and dictionary initialization syntax I used, if you're unfamiliar with it; basically just shortcuts for their Add methods)
{
"Animals": {
"name": "Animals",
"data": [
[
"Cows",
2
],
[
"Sheep",
3
]
]
}
}
If you have a choice of what the data types should be, I think it'd be better to replace the List<object> with a class something like this, to be more clear:
public class Item
{
public string name { get; set; }
public int quantity { get; set; }
}
Install the JSON.NET library.
Then with the classes that were created:
string jsonStr = "{'Animals': {name: 'Animals', data: [['Cows', 2], ['Sheep', 3] ] },'Fruits': { name: 'Fruits', data: [['Apples', 5], ['Oranges', 7], ['Bananas', 2] ] }, 'Cars': { name: 'Cars', data: [ ['Toyota', 1], ['Volkswagen', 2], ['Opel', 5] ] } }";
RootObject Myobj = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(jsonStr);

Json.NET: deserialize json arrays

I'm trying to process a JSON structure with Json.NET and encountered some issues:
My classes don't work when a JSON contains an unnamed array.
Json Example:
{
"graph_property" : [{
"name" : "calculation_method",
"value" : "Arithmetic"
}, {
"name" : "graph_type",
"value" : "TIME"
}
],
"measurement" : [{
"id" : "9997666",
"alias" : "Measurement (TxP)[IE]-Home Page - Total Time (seconds)",
"bucket_data" : [{
"name" : "2013-MAR-18 12:00 AM",
"id" : 1,
"perf_data" : {
"value" : "2.244",
"unit" : "seconds"
},
"avail_data" : {
"value" : "99.67",
"unit" : "percent"
},
"data_count" : {
"value" : "299",
"unit" : "#"
}
}
],
"graph_option" : [{
"name" : "perfwarning",
"value" : "-",
"unit" : "seconds"
}, {
"name" : "perfcritical",
"value" : "-",
"unit" : "seconds"
}, {
"name" : "availwarning",
"value" : "-",
"unit" : "percent"
}, {
"name" : "availcritical",
"value" : "-",
"unit" : "percent"
}, {
"name" : "bucketsize",
"value" : "86400",
"unit" : "seconds"
}, {
"name" : "rows",
"value" : "1",
"unit" : "#"
}, {
"name" : "pagecomponent",
"value" : "Total Time",
"unit" : "seconds"
}, {
"name" : "avg_perf",
"value" : "2.244",
"unit" : "seconds"
}, {
"name" : "avg_avail",
"value" : "99.67",
"unit" : "percent"
}, {
"name" : "total_datapoint_count",
"value" : "300",
"unit" : "#"
}, {}
]
}, {
"id" : "9997666",
"alias" : "Measurement (TxP)[IE]-Women - Total Time (seconds)",
"bucket_data" : [{
"name" : "2013-MAR-18 12:00 AM",
"id" : 1,
"perf_data" : {
"value" : "0.979",
"unit" : "seconds"
},
"avail_data" : {
"value" : "100.00",
"unit" : "percent"
},
"data_count" : {
"value" : "299",
"unit" : "#"
}
}
],
"graph_option" : [{
"name" : "perfwarning",
"value" : "-",
"unit" : "seconds"
}, {
"name" : "perfcritical",
"value" : "-",
"unit" : "seconds"
}, {
"name" : "availwarning",
"value" : "-",
"unit" : "percent"
}, {
"name" : "availcritical",
"value" : "-",
"unit" : "percent"
}, {
"name" : "bucketsize",
"value" : "86400",
"unit" : "seconds"
}, {
"name" : "rows",
"value" : "1",
"unit" : "#"
}, {
"name" : "pagecomponent",
"value" : "Total Time",
"unit" : "seconds"
}, {
"name" : "avg_perf",
"value" : "0.979",
"unit" : "seconds"
}, {
"name" : "avg_avail",
"value" : "100.00",
"unit" : "percent"
}, {
"name" : "total_datapoint_count",
"value" : "299",
"unit" : "#"
}, {}
]
}
],
"link" : {
"type" : "application/json",
"href" : "http://api.website.tld?format=json",
"rel" : "slotmetadata"
}
}
Class for Json.NET:
using System;
using System.Collections.Generic;
namespace CAKR.Graph
{
/// <summary>
/// Description of KN_Graph.
/// </summary>
public class GraphProperty
{
public string name { get; set; }
public string value { get; set; }
}
public class PerfData
{
public string value { get; set; }
public string unit { get; set; }
}
public class AvailData
{
public string value { get; set; }
public string unit { get; set; }
}
public class DataCount
{
public string value { get; set; }
public string unit { get; set; }
}
public class BucketData
{
public string name { get; set; }
public int id { get; set; }
public PerfData perf_data { get; set; }
public AvailData avail_data { get; set; }
public DataCount data_count { get; set; }
}
public class GraphOption
{
public string name { get; set; }
public string value { get; set; }
public string unit { get; set; }
}
public class Measurement
{
public string id { get; set; }
public string alias { get; set; }
public List<BucketData> bucket_data { get; set; }
public List<GraphOption> graph_option { get; set; }
}
public class Link
{
public string type { get; set; }
public string href { get; set; }
public string rel { get; set; }
}
public class RootObject
{
public List<GraphProperty> graph_property { get; set; }
public List<Measurement> measurement { get; set; }
public Link link { get; set; }
}
}
My code:
var myObject = JsonConvert.DeserializeObject<CAKR.Graph.Measurement>(MyJsonString);
I'm not sure why I don't get an object containing the data of the "Measurment" child-array.
If I insert named values, it works...
So I was struggling for quite some time to get this working. However in the end the solution is not so difficult. Hopefully with my response I will help some people.
The solution in my case was
Install JSON.net into your project by using nu.get
Make your JSON object including array's in array's, etc. Be sure that the format of the object is correct! Example...
{"ProductDetail":[
{
"ProjectImg" : "http://placehold.it/400x300",
"Category" : "Cars",
"ProjectTitle" : "Cars of the future",
"ProjectDesc" : "Test project",
"GenSpecList" : ["Specs1", "Specs2", "Specs3", "Specs4"],
"OptionList" : [{ "OptionNr" : "1",
"Options" : ["Opt1", "Opt2", "Opt3"]
},
{ "OptionNr" : "2",
"Options" : ["Opt1", "Opt2", "Opt3"]
},
{ "OptionNr" : "3",
"Options" : ["Opt1", "Opt2", "Opt3"]
},
{ "OptionNr" : "4",
"Options" : ["Opt1", "Opt2", "Opt3"]
},
{ "OptionNr" : "5",
"Options" : ["Opt1", "Opt2", "Opt3"]
},
{ "OptionNr" : "6",
"Options" : ["Opt1", "Opt2", "Opt3"]
}
],
"Articles" : [{ "tileImg" : "'Images/Project/1.jpg'",
"tileTit" : "Title1",
"tileArt" : "Article text here..."
},
{
"tileImg" : "'Images/Project/2.jpg'",
"tileTit" : "Title2",
"tileArt" : "Article text here..."
},
{
"tileImg" : "'Images/Project/3.jpg'",
"tileTit" : "Title3",
"tileArt" : "Article text here..."
},
{
"tileImg" : "'Images/Project/4.jpg'",
"tileTit" : "Title4",
"tileArt" : "Article text here..."
}
]
}
]
}
Go to json2csharp.com and copy your JSON object into the input box and click on the generate button. Copy the csharp model (this was actually the key to solve my struggle!) generated into your ViewModel.
In my case the primary class of all generated classes by json2csharp.com was the RootObject and looked like below
public class Article
{
public string tileImg { get; set; }
public string tileTit { get; set; }
public string tileArt { get; set; }
}
public class OptionList
{
public string OptionNr { get; set; }
public List<string> Options { get; set; }
}
public class ProductDetail
{
public string ProjectImg { get; set; }
public string Category { get; set; }
public string ProjectTitle { get; set; }
public string ProjectDesc { get; set; }
public List<string> GenSpecList { get; set; }
public List<OptionList> OptionList { get; set; }
public List<Article> Articles { get; set; }
}
public class RootObject
{
public List<ProductDetail> ProductDetail { get; set; }
}
Then use the following code in the controller (just copied the complete file here)
using Project.Details; //<-- this is my ViewModel namespace name
using Newtonsoft.Json;
using System.IO;
using System.Threading.Tasks;
namespace WebApplication.Controllers
{
public class JSONController : Controller
{
//
// GET: /JSON/
public async Task<ActionResult> Index()
{
StreamReader file = new StreamReader("C:\\Users\\YourName\\etc\\File.json");
String json = await file.ReadToEndAsync();
var Project = JsonConvert.DeserializeObject<RootObject>(json);
return View();
}
}
}
Now everything should work fine, array's in array's etc.
Hope that you found my solution helpful, note I'm not a die hard programmer so if I miss things on efficency I hope to recieve some tips from you to improve this code...
Best regards,
Raymond
You are almost there. Just use
var myObject = JsonConvert.DeserializeObject<CAKR.Graph.RootObject>(MyJsonString);
instead of
var myObject = JsonConvert.DeserializeObject<CAKR.Graph.Measurement>(MyJsonString);
First of all, you do not really need to name all the properties of your Measurement class exactly as they are presented in MyJsonString. You can use JsonProperty attribute and decorate your class properties.
Another thing is if you want to deserialize part of your MyJsonString and extract only array of Measurement, you should provide correct T type for Deserialize method (in your case it's IEnumerable<Measurement>.
The following code should help:
dynamic context = JObject.Parse(MyJsonString);
var myObject = JsonConvert.DeserializeObject<IEnumerable<Measurement>>(context.measurement.ToString());
I use a very simple method to Deserialize Json Arrays. Instead of using a ton of public classes with numerous public variables. I just use a Dynamic object and pass json as an object to JSONConvert.DeserializeObject.
This is how it would work. Say I have the following JSON:
string json = { 'Name': 'John Doe',
'Address': { 'City': 'Atlanta', 'State': 'GA' },
'Age': 30}
I can pass string json to the JSONConvert.DeserializeObject.
dynamic outputArray = JsonConvert.DeserializeObject(json);
Then using the dynamic item that was just created I can collect Json data like so.
string getName = outputArray.Name //This will return "John Doe"
If you have an array inside your Json you can use
string getCity = outputArray.Address.City; //This will return "Atlanta".
It's very easy to change where you pull data from without having a cluster of public variables... You can still save the values to public variables if you want.
The following is how I use the complete method:
using (var client = new WebClient())
{
string json = client.DownloadString(url);
string output = json.ToString();
dynamic outputArray = JsonConvert.DeserializeObject(output);
string _age = outputArray.age;
string appID = outputArray.data.app_id;
Debug.Write(outputArray.Something); //Just match value of json
}

How to deserialize a json array with unfixed name in JSON.NET

I have a question on how to deserialize a json array with unfixed name, for instance I have a json string as below.
[
{
"37414": "MP",
"weight": 1000
},
{
"21253": "Develper",
"weight": 424
},
{
"66344": "APP",
"weight": 1158
},
{
"1622": "API",
"weight": 164
}
]
I also defines a class as below and want to use JSON.NET to deserialize json string to UserTag object. Or should I change the class definition.
public class UserTag
{
// "37414"
public long Id { get; set; }
// MP
public string Name { get; set; }
// 424
public long Weight { get; set; }
}
Thanks in advance!
Are you using correct json format ?
I think you should use:
[
{
"Id" :37414,
"Name" : "MP",
"Weight": 1000
},
{
"Id" :21253,
"Name" : "Develper",
"Weight": 424
},
{
"Id": 66344,
"Name" : "APP",
"Weight": 1158
}
]
It will deserialize to:
public class UserTag
{
public int Id { get; set; }
public string Name { get; set; }
public int Weight { get; set; }
}
var result = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(json);
foreach (var item in result)
{
foreach (var kv in item)
{
Console.WriteLine(kv.Key + ": " + kv.Value);
}
}

Categories