Deserializing this object in JSON.NET - c#

I have the following object:
{
"pickups": {
"7": [
5,
8
],
"10": [
6,
7,
9
],
"15": [
1
],
"20": [
0,
2
],
"25": [
3,
4
]
}
}
I'd like to de-serialize each pickups element into the following object:
public class Pickups {
public Pickup[] pickups;
}
public class Pickup {
public int Group; // This could be the 7, 10, 15, 20, 25, etc.
public int[] Values; // If this was the "7" grouping, it would contain 5, 8.
}
As you can see from the data its a bit tricky to do this. I've been trying to use a JsonConverter to convert the object with a bit of custom code but its been a nightmare and I haven't been able to get it right. I am wondering if anyone would know the best way to convert this type of object into the correct format I need?

While a converter would be a good choice you can still deserialize the Json and construct the desired object graph
var root = JsonConvert.DeserializeObject<RootObject>(json);
var pickups = new Pickups {
pickups = root.pickups.Select(kvp =>
new Pickup {
Group = int.Parse(kvp.Key),
Values = kvp.Value
}
).ToArray()
};
Where
public class RootObject {
public IDictionary<string, int[]> pickups { get; set; }
}

This is what son2csharp.com says, its gets error because you can not define names with starting number.
public class Pickups
{
public List<int> __invalid_name__7 { get; set; }
public List<int> __invalid_name__10 { get; set; }
public List<int> __invalid_name__15 { get; set; }
public List<int> __invalid_name__20 { get; set; }
public List<int> __invalid_name__25 { get; set; }
}
public class RootObject
{
public Pickups pickups { get; set; }
}
But I think
[DataMember(Name = "Name")]
should work cause its not an error in JSON format side.

If it is a viable option for you to use JObject.Parse(...) instead, you could use the following code (and write it more cleanly, with exception handling and safe casts and so on):
var jsonPickups = JObject.Parse(json);
var myPickups = new Pickups
{
pickups = jsonPickups.First.First.Select(x =>
{
JProperty xProp = x as JProperty;
return new Pickup
{
Group = int.Parse(xProp.Name),
Values = (xProp.Value as JArray).Select(y => int.Parse(y.ToString())).ToArray()
};
}).ToArray()
};

Related

C# Sorting JSON response string

I'm making a HTTP request to gain a response body of JSON. The response body is quite large so I've cut the structure down for convenience. My problem is accessing specific data for later use. Then JSON string looks as follows:
{
"0": { <--- ID number
"vk": { <--- Specific object
"cost": 19, <--- information about object
"count": 1903 <--- information about object
},
"ok": {
"cost": 4,
"count": 2863
},
"wa": {
"cost": 4,
"count": 2210
}
}
}
I'm trying to define some sort of class or structure which would allow me to:
Call the ID to return all the blocks in that ID
Call ID.Object to get the cost and count
Call ID.Object.Count to return the account.
But I'm having trouble even separating the data with JSON. I have tried three methods I found on Stack Overflow to not much success, the closest I got was using a token
JToken token = JObject.Parse(response);
and calling token.root to pull the entire block & token.path to pull the ID number. I've seen suggestions about making each field have its own method but there are over 100 "id" brackets which contain upto 50 objects each so that's not really plausible.
I'm asking for assistance on how I would split the JSON data into organised data, I am planning to just create a class to store the data unless theres some specific JSON storage aspect I'm not aware of.
One way to code it would be to Parse the input and Deserialize the "0" to a class.
var obj = JObject.Parse(jsonDoc);
var something = JsonConvert.DeserializeObject<AllObjects>(obj["0"].ToString());
and your classes would look like this (I know you can name them better :) )
public class ObjInfo
{
public int cost { get; set; }
public int count { get; set; }
}
public class AllObjects
{
public ObjInfo vk { get; set; }
public ObjInfo ok { get; set; }
public ObjInfo wa { get; set; }
}
Reason you might have to do the way i did above is because you cannot have a variable with number... like public AllObjects 0 {get;set;}, but, you CAN do the following
public class MainObj
{
[JsonProperty("0")]
public AllObjects Zero { get; set; }
}
using the following line would deserialize correctly.
var something2 = JsonConvert.DeserializeObject<MainObj>(jsonDoc);
// where jsonDoc is your actual string input.
EDIT:
If your initial json will have a random ID (not a 0), you can use the following code to look up that ID. Then you can query your objects to see which one needs updating.
var obj = JObject.Parse(jsonDoc);
var zeroethElement = ((JProperty)obj.Properties().First()).Name;
I wanted to post an alternative solution where you can serialize the 0 index and any other indexes that follow it to achieve something like this.
The trick is to use a Dictionary. If you expect that the ID number will always be an integer, then you can construct the first part of the dictionary like this to start with.
Dictionary<int, ...>
And if it's a string, just change the int to a string.
If VK, OK and WA are the only 3 elements you expect, you can use the AllObjects class from Jawads answer like this.
// Dictionary<int, AllObjects>>
JsonConvert.DeserializeObject<Dictionary<int, AllObjects>>(json);
I would also modify Jawads AllObjects class to make sure the property names comply with C# conventions by using the JsonProperty attributes to our advantage like this.
public class AllObjects
{
[JsonProperty("vk")]
public CostCountResponse Vk { get; set; }
[JsonProperty("ok")]
public CostCountResponse Ok { get; set; }
[JsonProperty("wa")]
public CostCountResponse Wa { get; set; }
}
The output of deserializing will give us this result.
If however you are expecting more elements than just VK, OK and WA, you can cover this case with another nested dictionary like this.
Dictionary<int, Dictionary<string, ...>>
This string in the nest Dictionary is what will contain vk, ok, etc..
So what we have now is a Dictionary within a Dictionary which accurately represents how the JSON data is nested so far.
The final part is deserializing the JSON element containing the Cost and Count properties, and we can use the class Jawad posted to do that (I'm showing one that's again slightly modified to keep with naming conventions)
public class ObjInfo
{
[JsonProperty("cost")]
public int Cost { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
}
We can now use the ObjInfo class as the final puzzle of the Dictionary we've been defining.
Dictionary<int, Dictionary<string, ObjInfo>>
Which we can use like this (I've included the modified JSON I've been using as well to demonstrate what we can do here)
static void Main()
{
var root = JsonConvert.DeserializeObject<Dictionary<int, Dictionary<string, ObjInfo>>>(testJson);
foreach (var item in root)
{
Console.WriteLine($"Id: {item.Key}");
foreach (var subitem in item.Value)
{
Console.WriteLine($" SubCode: {subitem.Key}");
Console.WriteLine($" Cost: {subitem.Value.Cost}");
Console.WriteLine($" Count: {subitem.Value.Count}\n");
}
}
// Or access individual items by
var zeroVk = root[0]["vk"];
// Console.WriteLine(zeroVk.Cost);
// Console.WriteLine(zeroVk.Count);
}
public class ObjInfo
{
[JsonProperty("cost")]
public int Cost { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
}
const string testJson = #"{
""0"": {
""vk"": {
""cost"": 19,
""count"": 1903
},
""ok"": {
""cost"": 4,
""count"": 2863
},
""wa"": {
""cost"": 4,
""count"": 2210
}
},
""1"": {
""vk"": {
""cost"": 11,
""count"": 942
},
""ok"": {
""cost"": 68,
""count"": 1153
},
""wa"": {
""cost"": 14,
""count"": 7643
}
}
}";
This will spit out a response like this.
Id: 0
SubCode: vk
Cost: 19
Count: 1903
SubCode: ok
Cost: 4
Count: 2863
SubCode: wa
Cost: 4
Count: 2210
Id: 1
SubCode: vk
Cost: 11
Count: 942
SubCode: ok
Cost: 68
Count: 1153
SubCode: wa
Cost: 14
Count: 7643
There was the question about sorting, filtering and querying the list of different stores based on either counts or costs. Following is a list pattern that you can use and use LINQ to do the queries and filtering.
public class ItemInfo
{
[JsonProperty("cost")]
public int Cost { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
}
public class AllProdcuts
{
[JsonProperty("vk")]
public ItemInfo VK { get; set; }
[JsonProperty("ok")]
public ItemInfo OK { get; set; }
[JsonProperty("wa")]
public ItemInfo WA { get; set; }
}
public class Stores
{
[JsonProperty("ID")]
public string StoreID { get; set; }
[JsonProperty("store")]
public AllProdcuts Store { get; set; }
}
and this is how you would call it
string jsonDoc = #"{
""0"": {
""vk"": {
""cost"": 19,
""count"": 1903
},
""ok"": {
""cost"": 4,
""count"": 2863
},
""wa"": {
""cost"": 4,
""count"": 2210
}
},
""1"": {
""vk"": {
""cost"": 9,
""count"": 3
},
""ok"": {
""cost"": 4,
""count"": 63
},
""wa"": {
""cost"": 40,
""count"": 210
}
}
}";
var obj = JObject.Parse(jsonDoc);
List<Stores> allStores = new List<Stores>();
foreach (var property in obj.Properties())
{
string storeNumber = property.Name;
allStores.Add(new Stores() { StoreID = property.Name, Store = JsonConvert.DeserializeObject<AllProdcuts>(obj[property.Name].ToString()) });
}
// If you want to get list of <count, cost> for all stores
List<ItemInfo> totalItemInAllStores = allStores.Select(x => x.Store.OK).ToList();
int totalOKInAllStores = allStores.Sum(x => x.Store.OK.Count);
int totalWAInAllStores = allStores.Sum(x => x.Store.WA.Count);
int totalOkInXStore = allStores.FirstOrDefault(x => x.StoreID.Equals("0")).Store.OK.Count;
string storeWithHighestCountOfOK = allStores.OrderBy(x => x.Store.OK.Count).Last().StoreID;
You can create separate methods for different sorting/queries you want to perform on each of the items for ease of getting the numbers you want.

How can I deserialize a JSON string which has objects from different classes?

I would like to deserialize a JSON string which contains multiple object types. So for instance here are my two POCO classes:
public class Car
{
[Key]
public int Id { get; set; }
public string Color { get; set; }
}
public class Driver
{
[Key]
public int Id { get; set; }
public string Firstname { get; set; }
}
Now I would like to have a JSON string which would have an array of objects from both classes (which are unrelated) and that would get deserialized into their respective POCO classes using the Newtonsoft json package in Visual Studio.
Is this possible and if so, what does the JSON format look like? An example would be appreciated with just 2 objects per class to show the array of objects and the two class types coexisting within a single JSON string which is passed to something like JsonConvert.DeserializeObject.
EDIT: the JSON for these classes and an object within would individually look something like:
for Car...
[
{
"color": "red"
},
{
"color": "blue"
}
]
and for Driver...
[
{
"Firstname": "Fred"
},
{
"Firstname": "Sally"
}
]
But now could those be combined into one string, but with some sort of extra parm to define to which CLASS each set belongs such as:
"Car"
[
{
"color": "red"
},
{
"color": "blue"
}
],
"Driver"
[
{
"Firstname": "Fred"
},
{
"Firstname": "Sally"
}
]
See how this has 2 unrelated classes in a single JSON string? Now I'd like to do a single (if possible) Jsonconvert into the respective classes so that "Car" winds up with 2 objects and "Driver" winds up with 2 (for this example).
Could be done like this:
using System.Collections;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var objArray = new ArrayList
{
new Car {Id = 1, Color = "blue"},
new Driver {Id = 1, Firstname = "John"},
new Car {Id = 2, Color = "blue"},
new Driver {Id = 2, Firstname = "Jane"}
};
var json = JsonConvert.SerializeObject(objArray);
var jArray = JArray.Parse(json);
foreach (var child in jArray.Children())
{
if (child.Children().Any(token => token.Path.Contains("Color")))
{
// we got a Car
var car = ((JObject) child).ToObject<Car>();
}
else if (child.Children().Any(token => token.Path.Contains("Firstname")))
{
// we got a Driver
var driver = ((JObject) child).ToObject<Driver>();
}
}
}
}
public class Car
{
public int Id { get; set; }
public string Color { get; set; }
}
public class Driver
{
public int Id { get; set; }
public string Firstname { get; set; }
}
}

JSON deserialization for polymorphic results

I have the following problem which is driving me crazy to find a proper solution.
I have to consume two RESTful APIs which return the same structure except for the items structure.
Let me give you two examples:
{
"hasmoredata":true,
"current_page": 1,
"page_size": 20,
"total_pages": 5,
"items": [
{
"user_id": "1",
"username": "carl",
"first_name": "carl",
}
]
}
{
"hasmoredata":true,
"current_page": 1,
"page_size": 10,
"total_pages": 2,
"items": [
{
"course_id": "10",
"course_name": "Math",
"duration": "3h",
}
]
}
I'd like to have two classes which extend an abstract one that collect the common properties. Something like this (in C#):
public abstract class CursorResult
{
[JsonProperty("current_page")]
public int CurrentPage { get; set; }
[JsonProperty("page_size")]
public int PageSize { get; set; }
[JsonProperty("total_pages")]
public int TotalPages { get; set; }
[JsonProperty("hasmoredata")]
public bool HasMoreData{ get; set; }
}
public class UsersList : CursorResult
{
[JsonProperty("items")]
List<User> Users { get; set; }
}
public class CoursesList : CursorResult
{
[JsonProperty("items")]
List<Courses> Courses { get; set; }
}
Now the problem is the fact that i have to write a function that collect the entire result (all the pages of items) and merge those results in one:
private CursorResult GetEntireResult(string apiURL)
{
Cursor c = new Cursor(1, pageSize);
CursorResult result = TryDeserializeCursorResult(CallRestFulAPI(apiURL + c.GetCursorParametersString, Method.GET));
c.Hashcode = result.CursorHashCode;
while (result.HasMoreData)
{
c.CurrentPage += 1;
result.AddItems(TryDeserializeCursorResult(CallRestFulAPI(apiURL + c.ParametersString, Method.GET)));
}
return result;
}
but i don't have any idea on how write the AddItem function in order to add Users or Courses depending on the API result.
Thanks in advance for any help!
Lapo
A couple of things:
With your current code, assuming you're using a default serializer, when you deserialize you're not going to capture 'items' because you're deserializing to CursorResult which doesn't have an 'items' property defined. The serializer doesn't automatically know about derived types. Also I would recommend renaming the UserList and CoursesList classes to UserCursorResult/CourseCursorResult. The classes aren't lists, they contain lists.
Here is code that will discriminate between the json serialized (sub)types :
string yourJsonString = #"{ 'hasmoredata':true,'current_page':
1,'page_size': 20,'total_pages': 5,'items': [{'user_id':
'1','username': 'carl','first_name': 'carl'}]}";
JSchemaGenerator generator = new JSchemaGenerator();
JSchema userSchema = generator.Generate(typeof(UsersList));
JSchema courseSchema = generator.Generate(typeof(CoursesList));
JToken jObject = JObject.Parse(yourJsonString);
if (jObject.IsValid(courseSchema))
{
CoursesList courseList = JsonConvert.DeserializeObject<CoursesList>(yourJsonString);
//do stuff with CourseList
}
else if (jObject.IsValid(userSchema))
{
UsersList userList = JsonConvert.DeserializeObject<UsersList>(yourJsonString);
//do stuff with UsersList
}

Serializing JSON Object Array (Json.NET)

I'm learning JSON and was wondering how to create an array of objects. I want my JSON file to look like this
{
"Place": {
"Stores": [{
"Grocery": {
"stock": "fruit",
"distance": 19,
"size": 12
},
"Department": {
"stock": "clothing",
"distance": 21,
"size": 7
}
}]
}
}
Here is what my C# classes looks like
public class RootObject
{
public Place Place { get; set; }
}
public class Place
{
public List<Store> Stores { get; set; }
}
public class Store
{
public Grocery Grocery { get; set; }
public Department Department { get; set; }
}
public class Grocery
{
public string stock { get; set; }
public int distance { get; set; }
public int size { get; set; }
}
public class Department
{
public string stock { get; set; }
public int distance { get; set; }
public int size { get; set; }
}
So far, I have tried coding it like this, similar to how the examples are on the newtonsoft website
Rootobject root = new Rootobject
{
Place = new Place
{
stores = new List<Store>
{
Grocery = new Grocery
{
stock ="fruit",
distance = 19,
size = 12
},
Department = new Department
{
stock ="clothing",
distance = 21,
size = 7
}
}
}
};
string json = JsonConvert.SerializeObject(root,
Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
System.IO.File.WriteAllText(#"C:\Users\Public\TestFolder\output.json", json);
but I'm getting two CS0117 errors at
Grocery = new Grocery
and
Department = new Department
which says that Store does not contain a definition for Grocery/Department
What am I doing wrong here? Did I just make an error in syntax or is there a possibility I am just approaching serializing this the wrong way? Much thanks in advance for your guy's help.
Your object should look like this:
Rootobject root = new Rootobject
{
Place = new Place
{
stores = new List<Store>
{
new Store{
Grocery = new Grocery
{
stock ="fruit",
distance = 19,
size = 12
},
Department = new Department
{
stock ="clothing",
distance = 21,
size = 7
}
}
}
}
};
I wrote it from my head, so I hope syntax is good. But main idea is that you were creating list of stores and not any store inside that list. You should create some Store using new Store

Deserializing JSON with Child and Inner Childs

I am familiar with JSON.net a bit and can Deserialize the JSON with basic structure (upto one child). I am currently in process of Deserializing the JSON that is returned from Netatmo API. The structure of JSON is complicated for me. Following is the basic structure of the JSON,
_id
place
location
Dynamic Value 1
Dynamic Value2
altitude
timezone
mark
measures
Dynamic Value 1
res
Dynamic Value 1
Dynamic Value 1
Dynamic Value 2
type
Dynamic Value 1
Dynamic Value 2
modules
Dynamic Value 1
Dynamic Value 1 and Dynamic Value 2 represents the values that is changed for each id. The complete JSON is given below,
{
"body": [{
"_id": "70:ee:50:02:b4:8c",
"place": {
"location": [-35.174779762001, -5.8918476117544],
"altitude": 52,
"timezone": "America\/Fortaleza"
},
"mark": 0,
"measures": {
"02:00:00:02:ba:2c": {
"res": {
"1464014579": [16.7, 77]
},
"type": ["temperature", "humidity"]
},
"70:ee:50:02:b4:8c": {
"res": {
"1464014622": [1018.1]
},
"type": ["pressure"]
}
},
"modules": ["02:00:00:02:ba:2c"]
}, {
"_id": "70:ee:50:12:40:cc",
"place": {
"location": [-16.074257294385, 11.135715243973],
"altitude": 14,
"timezone": "Africa\/Bissau"
},
"mark": 14,
"measures": {
"02:00:00:06:7b:c8": {
"res": {
"1464015073": [26.6, 78]
},
"type": ["temperature", "humidity"]
},
"70:ee:50:12:40:cc": {
"res": {
"1464015117": [997]
},
"type": ["pressure"]
}
},
"modules": ["02:00:00:06:7b:c8"]
}],
"status": "ok",
"time_exec": 0.010364055633545,
"time_server": 1464015560
}
I am confused by looking at the complex structure of this JSON. For single level of JSON I have used this code in the past,
IList<lstJsonAttributes> lstSearchResults = new List<lstJsonAttributes>();
foreach (JToken objResult in objResults) {
lstJsonAttributes objSearchResult = JsonConvert.DeserializeObject<lstJsonAttributes>(objResult.ToString());
lstSearchResults.Add(objSearchResult);
}
But for so many child I have yet to understand how the object class will be created. Any guidance will highly appreciated.
Update:
This is what I have achieved so far.
I have created a main class as below,
public class PublicDataClass
{
public string _id { get; set; }
public PublicData_Place place { get; set; }
public string mark { get; set; }
public List<string> modules { get; set; }
}
and "Place" class is as follow,
public class PublicData_Place
{
public List<string> location { get; set; }
public string altitude { get; set; }
public string timezone { get; set; }
}
Then I have Deserialized the object in the following code line,
var obj = JsonConvert.DeserializeObject<List<PublicDataClass>>(jsonString);
I can now successfully get all the data except the "measures" which is little bit more complicated.
Using json.net, JSON objects that have arbitrary property names but fixed schemas for their values can be deserialized as a Dictionary<string, T> for an appropriate type T. See Deserialize a Dictionary for details. Thus your "measures" and "res" objects can be modeled as dictionaries.
You also need a root object to encapsulate your List<PublicDataClass>, since your root JSON container is an object like so: { "body": [{ ... }] }.
Thus you can define your classes as follows:
public class RootObject
{
public List<PublicDataClass> body { get; set; }
public string status { get; set; }
public double time_exec { get; set; }
public int time_server { get; set; }
}
public class PublicDataClass
{
public string _id { get; set; }
public PublicData_Place place { get; set; }
public int mark { get; set; }
public List<string> modules { get; set; }
public Dictionary<string, Measure> measures { get; set; }
}
public class PublicData_Place
{
public List<double> location { get; set; } // Changed from string to double
public double altitude { get; set; } // Changed from string to double
public string timezone { get; set; }
}
public class Measure
{
public Measure()
{
this.Results = new Dictionary<string, List<double>>();
this.Types = new List<string>();
}
[JsonProperty("res")]
public Dictionary<string, List<double>> Results { get; set; }
[JsonProperty("type")]
public List<string> Types { get; set; }
}
Then do
var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
var obj = root.body;
I've worked with XML for a few years and my change to JSON structure I've got a little confused too, always that I want to see how an object look like I use this web site jsoneditoronline Just copy and paste your JSON and click on arrow to parse to an object, I hope it helps until you get used to JSON structure.

Categories