What is the best way to map a JSON object that has a structure whereby it contains a list of objects whose names are dynamically created through incrementation?
e.g.
{"data":
{
"object-0":[{"id":"1","name":"John"},{"id":"2","name":"Mary"}],
"object-1":[{"id":"3","name":"Gary"},{"id":"4","name":"Mark"}]
}
}
Assuming you've got a class like
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
You could deserialize this into a Dictionary<string, IEnumerable<User>> like so
Dictionary<string, IEnumerable<User>> values =
JsonConvert.DeserializeObject<Dictionary<string, IEnumerable<User>>>(json);
This also assumes the use of json.net
You can use Json.NET library to transform any JSON string to arbitrary dynamic object in .NET. This should do:
dynamic jsonObject = JsonConvert.DeserializeObject(jsonString);
In your case I suppose you need object-0, object-1 etc in a list/array (since they are incrementally generated by the looks of it) and not as typed properties as such, in which case you can trivially transform the obtained dynamic object to whatever you want. For an e.g.
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Data
{
public Dictionary<string, List<User>> Objects { get; set; }
}
string jsonString = '...';
dynamic jsonObject = JsonConvert.DeserializeObject(jsonString);
// could have made use of LINQ to shorten this bit of code
// but unfortunately dynamic doesn't play well with extension methods
var data = new Data { Objects = new Dictionary<string, List<User>>() };
foreach (var obj in jsonObject.data)
data.Objects[obj.Name] = obj.Value.ToObject<List<User>>();
// now you have everything in `data` instance.
To replicate the exact json structure, you can have a root class to hold the data. Something like:
class Root { public Data data { get; set; } }
var root = new Root { data = data };
If you need the entire user objects in one flat structure, you can flatten it too:
var users = data.Objects.SelectMany(kv => kv.Value);
Related
I have the following JSON
{"KeyValuePairs":{"Gender":"Male","IsDeveloper":true,"Language":"English"},"PreferredLanguage":"C#","PreferredIDE":"Visual Studio","PreferredSourceControl":"Team Foundation Server (TFS)"}
and it is based on the class of:
public class DataModel
{
public Dictionary<string, object> KeyValuePairs { get; set; }
public string PreferredLanguage { get; set; }
public string PreferredIDE { get; set; }
public string PreferredSourceControl { get; set; }
public DataModel()
{
KeyValuePairs = new Dictionary<string, object>();
}
}
I would like to make it like the following when I serialize the class object of DataModel:
{"Gender":"Male","IsDeveloper":true,"Language":"English","PreferredLanguage":"C#","PreferredIDE":"Visual Studio","PreferredSourceControl":"Team Foundation Server (TFS)"}
The reason on why I put "Gender", "IsDeveloper", or so on inside the KeyValuePairs, as because it is being generated dynamically from JSON file (it could contains anything other than "Gender", "IsDeveloper"), while the other properties like "PreferredLanguage", "PreferredIDE" and "PreferredSourceControl" does not
Also, if the above being achieved, how can I put back into KeyValuePairs for the "Gender", "IsDeveloper" or any other properties inside KeyValuePairs previously when doing the deserialization?
Basically I would like to convert all properties inside the DataModel class to the Dictionary<string, object> pairs, which Newtonsoft.Json did it perfectly when there is only primitive type for the return type of the property, but for my case, I would like to set the KeyValuePairs into Dictionary<string, object> instead of KeyValuePairs: Dictionary<string, object>, and also when doing the deserialization, system will detect if there is no name of the property inside DataModel class, it will go add directly into KeyValuePairs (for example, "Gender" not exists in DataModel class, then it will be added into KeyValuePairs when doing the deserialization)
Or is there any way that I can achieve the same?
Thank you very much
you can use JsonExtensionData - Instructs the JsonSerializer to deserialize properties with no matching class member into the specified collection and write values during serialization.
var json="{\"Gender\":\"Male\",\"IsDeveloper\":true,\"Language\":\"English\",\"PreferredLanguage\":\"C#\",\"PreferredIDE\":\"Visual Studio\",\"PreferredSourceControl\":\"Team Foundation Server (TFS)\"}";
DataModel dataModel= JsonConvert.DeserializeObject<DataModel>(json);
Test
json=JsonConvert.SerializeObject(dataModel);
creates the same json
class
public class DataModel
{
[JsonExtensionData]
public Dictionary<string, object> KeyValuePairs { get; set; }
public string PreferredLanguage { get; set; }
public string PreferredIDE { get; set; }
public string PreferredSourceControl { get; set; }
public DataModel()
{
KeyValuePairs = new Dictionary<string, object>();
}
}
UPDATE
if you want at first convert your json to normalized one you can do it this way:
var json = "{\"KeyValuePairs\":{\"Gender\":\"Male\",\"IsDeveloper\":true,\"Language\":\"English\"},\"PreferredLanguage\":\"C#\",\"PreferredIDE\":\"Visual Studio\",\"PreferredSourceControl\":\"Team Foundation Server (TFS)\"}";
var jsonParsed = JObject.Parse(json);
foreach (var item in ((JObject)jsonParsed["KeyValuePairs"]).Properties())
jsonParsed.Add(item.Name, item.Value);
jsonParsed.Property("KeyValuePairs").Remove();
json = jsonParsed.ToString();
or you can deserialize jsonParsed as well instead of creating a new json
DataModel dataModel =jsonParsed.ToObject<DataModel>();
I am trying to get data from a Mixpanel API. The JSON result looks like this:
{"computed_at": "2019-11-19T10:36:33.908802+00:00", "legend_size": 1, "data": {"series": ["2019-11-11", "2019-11-12", "2019-11-13"], "values": {"page views": {"2019-11-12": 111, "2019-11-11": 573, "2019-11-13": 209}}}}
I am struggling with nested JSON (despite looking at a fair few StackOverflow articles on this) and I want to try and get the values 111,573 and 209 for the page views. How do I access these values?
I've tried the following:
var result = {"computed_at": "2019-11-19T10:36:33.908802+00:00", "legend_size": 1, "data": {"series": ["2019-11-11", "2019-11-12", "2019-11-13"], "values": {"page views": {"2019-11-12": 111, "2019-11-11": 573, "2019-11-13": 209}}}}
var rawData = result["data"]["values"]["page views"][0]
but this doesn't work and I can't figure out how to access the individual values. Can anyone help please?
EDIT:
When using the json to C# converter (as suggested in the comments to this post) the outcome is as follows:
public class PageViews
{
public int __invalid_name__2019-11-20 { get; set; }
public int __invalid_name__2019-11-19 { get; set; }
}
public class Values
{
public PageViews __invalid_name__page views { get; set; }
}
public class Data
{
public List<string> series { get; set; }
public Values values { get; set; }
}
public class RootObject
{
public DateTime computed_at { get; set; }
public int legend_size { get; set; }
public Data data { get; set; }
}
and I am still unsure how to get the numbers from this?
There are two approaches you could take. First, I'd deserialize the json string using this library - Newtonsoft.
You can then go through the json using JObjects, or you can create a C#-Class that represents your json data and then deserialize it into a corresponding object.
Via a class:
To create the json class there is this website, which creates the classes (also nested) just as the json needs them to be: http://json2csharp.com/
Then you use:
var myObject = JsonConvert.DeserializeObject<MyClass>(jsonString);
and then simply go through your object properties.
Via JObject
JObjects allow you to search through the json string easily as such:
JObject myObject = JObject.Parse(json);
var results = myObject["data"]["values"]["page views"].First();
Edit:
Since your Json contains keys, which begin with a number (and are not valid c# variable names) its a bit more tricky but doable. The automatic converter failed on this.
string json = "{\"computed_at\": \"2019 - 11 - 19T10: 36:33.908802 + 00:00\", \"legend_size\": 1, \"data\": {\"series\": [\"2019 - 11 - 11\", \"2019 - 11 - 12\", \"2019 - 11 - 13\"], \"values\": {\"page views\": {\"2019 - 11 - 12\": 111, \"2019 - 11 - 11\": 573, \"2019 - 11 - 13\": 209}}}}";
var myObject = JsonConvert.DeserializeObject<RootObject>(json);
foreach (var view in myObject.data.series)
{
int number = myObject.data.values.page_views[view];
Console.WriteLine($"{number} views on {view}");
}
With the RootObject class being:
public class Values
{
[JsonProperty("page views")]
public Dictionary<string, int> page_views { get; set; }
}
public class Data
{
public List<string> series { get; set; }
public Values values { get; set; }
}
public class RootObject
{
public string computed_at { get; set; }
public int legend_size { get; set; }
public Data data { get; set; }
}
The trick was to use a Dictionary<string, int> type for the date-values, and rename the property to a valid c# name. The JsonDeserializer still finds the data, because we told it to look for "page views" using the JsonProperty attribute. This way the class is also flexible for multiple entries in your "page views" field.
Hope this helps
You were close. In the line
var rawData = result["data"]["values"]["page views"][0]
you are attempting to access index 0 of an object. This doesn't really make sense because objects are basically dictionaries or hash tables, which means they are unordered and must be accessed by a key rather than an index (See Retrieving a property of a JSON object by index?).
What you want looks like
var rawData = result["data"]["values"]["page views"]['2019-11-12'] to access the number of page views (which is 111) for the date 2019-11-12.
You can then loop through the object and get each number of page views as follows:
var pageViews = [];
for (var key of Object.keys(result.data.values['page views'])) {
pageViews.push(result.data.values['page views'][key]);
}
I'm trying to get the data from a website RSS converting it to JSON. I got this JSON string:
http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http%3A%2F%2Frss.tecmundo.com.br%2Ffeed
I'm using lists to get the values but I got this error "Cannot create an instance of the abstract class or interface" and I don't know how to solve it. It happens in this line.
IList<News> content = new IList<News>();
Here is my code.
public class News
{
public string author { get; set; }
public string title { get; set; }
public string content { get; set; }
public string contentSnippet { get; set; }
public string link { get; set; }
public string publishedDate { get; set; }
public string[] getFeed(string Website)
{
string path = #"http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=" + Website;
var json = new WebClient().DownloadString(path);
JObject jsonObject = JObject.Parse((string)json);
IList<JToken> jsonData = jsonObject["responseData"]["feed"]["entries"]["0"].Children().ToList();
IList<News> content = new IList<News>();
foreach(JToken data in jsonData)
{
News finalData1 = JsonConvert.DeserializeObject<News>(jsonData.ToString());
content.Add(finalData1);
}
return new string[] { "I must return something here." };
}
}
Here is the tool I'm using to visualize better the JSON string: http://jsonschema.net/#/
The error you're getting has nothing to do with JSON. It is because you're trying to create an instance of an interface. You could just fix that by giving it the concrete List<T> class:
IList<News> content = new List<News>();
However, the simpler way of converting the IList<JToken> to an IList<News> is probably to use LINQ again - you can do all of this in one step pretty easily:
IList<News> content = jsonObject["responseData"]["feed"]["entries"]["0"]
.Children()
.Select(token => JsonConvert.DeserializeObject<News>(token.ToString())
.ToList();
That compiles, but isn't actually want due to the data you've got. entries is an array, so you probably want:
JArray array = (JArray) jsonObject["responseData"]["feed"]["entries"];
var content = array
.Select(token => JsonConvert.DeserializeObject<News>(token.ToString())
.ToList();
Your problem has nothing to do with the json, but with trying to create an instance of an interface which is not possible in c#. You need to create an instance of a concrete class that implements the IList interface. List would be one example. There are others, including arrays.
I have a JSON string that I am trying to parse, using C#. I have used JsonConvert to serialize my data into a JSON string.
Here is my sample JSON string:
{"names": ["John", "Joe", "Jack"], "nationality": "American"}
I am able to deserialize this string into an object using JsonConvert.DeserializeObject(x);
The problem is, I dont know how to read from the object, using C#. Can someone help me out?
public class People
{
[JsonProperty("names")]
public List<string> Names;
[JsonProperty("nationality")]
public string Nationality;
}
Other answers are technically correct, but using JsonPropertyAttribute is a universally accepted convention. Then use JsonConvert:
var people = JsonConvert.DeserializeObject<People>(x);
A better approach would be to define a class with the expected structure, then using JavaScriptSerializer to deserialize it:
class NameSet
{
public IList<string> names { get; set; }
public string nationality { get; set; }
}
var serializer = new JavaScriptSerializer();
var nameset = serializer.Deserialize<NameSet>(jsonString);
Create a custom class like this:
public class CustomData
{
public string[] Names { get; set; }
public string Nationality { get; set; }
public CustomData() { }
}
And use JsonConvert to deserialize yo an object of this type:
CustomData data = JsonConvert.DeserializeObject<CustomData>(x);
The following should suffice:
public class PeopleGroup {
public string[] names { get; set; }
public string nationality { get; set }
}
var myObject = JsonConvert.DeserializeObject<PeopleGroup>(x);
Basically, you create a strongly typed object, and deserialise directly into it.
If you don't want to actually define a class, you can use an anonymous type:
string json = "{\"names\": [\"John\", \"Joe\", \"Jack\"], \"nationality\": \"American\"}";
// Just defining the structure of the anonymous type
var x = new { names = new string[0], nationality = string.Empty };
x = JsonConvert.DeserializeAnonymousType(json, x);
You should use dataContractJsonSerializer class, it is faster and most important is it is inbuilt class of .Net Framework. I will post solution in my next commment, in that How can we use DataContractJsonSerializer class.Now I cant post solution because in my end net is too slow :(, but I will post today.
I need to deserialize the following Json, which according to Jsonlint.com is valid, but ive not come across this before or cannot find examples of similar Json and how to deal with it?
[1,"Bellegrove / Sherwood ","76705","486","Bexleyheath Ctr",1354565507000]
My current system with like this:
Data class:
[DataContract]
public class TFLCollection
{ [DataMember(Name = "arrivals")]
public IEnumerable<TFLB> TFLB { get; set; }
}
[DataContract]
public class TFLB
{
[DataMember]
public string routeName { get; set; }
[DataMember]
public string destination { get; set; }
[DataMember]
public string estimatedWait { get; set; }
}
Deserializer:
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TFLCollection));
using (var stream = new MemoryStream(Encoding.Unicode.GetBytes(result)))
{ var buses = (TFLCollection)serializer.ReadObject(stream);
foreach (var bus in buses.TFLBuses)
{
StopFeed _item = new StopFeed();
_item.Route = bus.routeName;
_item.Direction = bus.destination;
_item.Time = bus.estimatedWait;
listBox1.Items.Add(_item);
My exsiting deserializer works with a full Json stream and iterates through it, but in my new Json I need to deserialize, it only have 1 item, so I wont need to iterate through it.
So is it possible to deserialize my Json example using a similar method than I currently do?
I would say that you are attempting to overcomplicate things. What you have is a perfectly formed json array of strings. If I were you I would deserialize that to an .net array first, and then write a 'mapper' function to copy the values across:
public TFLB BusRouteMapper(string[] input)
{
return new TFLB {
Route = input[x],
Direction = input[y],
};
}
And so on. Of course this assumes that you know what order your json is going to be in, but if you are attempting this in the first place then you must do!