JSON Deserialize different named object into a Collection c# - c#

I have to read a given JSON string into C# objects. So far so good but this case is kind of special to me. The JSON string contains 2 entities. One is a flat object and the second is a list, logical at least but not really in JSON. I hope you can help me finding a solution to this.
To explain it better i will show you a part of my JSON input:
{
"game":{"GameMode":"1","IsNetworkMode":"1","NbMaxPlayer":"12","GameState":"1"},
"player_56":{"PlayerUserId":"137187","PlayerIALevel":"-1","PlayerObserver":"0"},
"player_7":{"PlayerUserId":"3440","PlayerIALevel":"-1","PlayerObserver":"0"}
}
I want to serialize the Player entities into a collection of objects of this type. The Problem is that they arent really stored as a collection in JSON. They have dynamic names as "player_56" and the number is not in any logical order like "1,2,3".
At the moment I am using the DataContractJsonSerializer for this task.
[DataContract]
public class AlbReplay
{
[DataMember(Name = "game")]
public AlbGame Game { get; set; }
[DataMember(Name = "player")]
public List<AlbPlayer> Players { get; set; }
}
Any suggestions?

I don't know the extent of DataContractJsonSerializer, but there might be an interface you can implement on your class to define how to parse the JSON.
But if you're able to use JSON.Net:
public class Player
{
public int Id { get; set; }
public int PlayerUserId { get; set; }
public int PlayerIALevel { get; set; }
public int PlayerObserver { get; set; }
}
And then you can use Linq-To-JSON:
var data = #"{
""game"":{""GameMode"":""1"",""IsNetworkMode"":""1"",""NbMaxPlayer"":""12"",""GameState"":""1""},
""player_56"":{""PlayerUserId"":""137187"",""PlayerIALevel"":""-1"",""PlayerObserver"":""0""},
""player_7"":{""PlayerUserId"":""3440"",""PlayerIALevel"":""-1"",""PlayerObserver"":""0""}
}";
JObject o = JObject.Parse(data);
IEnumerable<Player> players =
o.Children()
.Where(p => ((JProperty)p).Name.StartsWith("player"))
.Select(p =>
new Player
{
Id = int.Parse(((JProperty)p).Name.Split('_')[1]),
PlayerUserId = int.Parse((string)p.Children<JObject>().First()["PlayerUserId"]),
PlayerIALevel = int.Parse((string)p.Children<JObject>().First()["PlayerIALevel"]),
PlayerObserver = int.Parse((string)p.Children<JObject>().First()["PlayerObserver"]),
});

Mangle your JSON into a collection of player objects.
player_8: {...}
player_99: {...}
to
players: [
{id: 8 ...},
{id: 99 ...}
]
How to mangle your JSON, a RegEx would likely be sufficient.
EDIT Here's code for the string mangling using Regex. A few assumptions were made: there are no objects embedded inside of the game and player objects and the player object list is the last part of the json string.
string json_test = #"{
""game"":{""GameMode"":""1"",""IsNetworkMode"":""1"",""NbMaxPlayer"":""12"",""GameState"":""1""},
""player_56"" : {""PlayerUserId"":""137187"",""PlayerIALevel"":""-1"",""PlayerObserver"":""0""},
""player_2"": {""PlayerUserId"":""137187"",""PlayerIALevel"":""-1"",""PlayerObserver"":""0""}
}";
json_test = new Regex(#"""player_(\d+)""\s*:\s*{").Replace(json_test, #"""player"" : {""Id"": $1,");
Console.WriteLine("player_##:{...} -> player:{id: ##,..}");
Console.WriteLine(json_test);
json_test = new Regex(#"""player""\s*:\s*{").Replace(json_test, #"""players"" : [{", 1);
json_test = new Regex(#"""player""\s*:\s*{").Replace(json_test, #"{");
json_test = new Regex(#"}$").Replace(json_test, #"]}");
Console.WriteLine("player:{...}, -> players: [{...},...]");
Console.WriteLine(json_test);
As with all considerations regarding speed, you'll have to test it out, having the Regex objects as static and reusable would be my first step if I had to optimize the above.

Related

JSON to datatable - How to deserialize

I have this very simple JSON string:
{
"data": {
"id": 33306,
"sport": {
"id1": "FB",
"id2": "HB"
}
}
}
I can't understand how to return a datatable from this string.
I have tried to use this code but it's not working:
DataTable dt = (DataTable)JsonConvert.DeserializeObject(json, (typeof(DataTable)));
you have to flatten all json properties, after this to convert to DataTable
var jObj = (JObject)JObject.Parse(json)["data"];
var properties = jObj.Properties().ToList();
for (var i = 0; i < properties.Count; i++)
{
var prop = properties[i];
if (prop.Value.Type == JTokenType.Object)
{
foreach (var p in ((JObject)prop.Value).Properties())
jObj.Add(new JProperty(prop.Name + " " + p.Name, p.Value));
prop.Remove();
}
}
DataTable dt = new JArray { jObj }.ToObject<DataTable>();
output
[
{
"id": 33306,
"sport id1": "FB",
"sport id2": "HB"
}
]
You need to do this in two steps.
Deserialize into a .net object whose structure matches that of the JSON
Populate a DataTable with the properties of that object
Step 1 - Deserialize
We need to define some classes to receive the deserialized data. The names of the classes aren't particularly important (as long as they're meaningful to you), however the names of the properties of those classes need to match the names of the corresponding elements in the JSON.
First the outermost class, which is the shape of the JSON you want to deserialize.
public class SomeClass
{
public DataElement Data { get; set; }
}
Now we need to define the shape of DataElement.
public class DataElement
{
public int Id { get; set; }
public SportElement Sport { get; set; }
}
And now we need to define the shape of SportElement.
public class SportElement
{
public string Id1 { get; set; }
public string Id2 { get; set; }
}
The implementation above is fairly rigid and assumes that the shape of the JSON doesn't change from one document to the next. If, however, you expect the shape to vary, for example, if the sport element could could contain any number of id1, id2, id3, ... id100 etc elements, then you can throw away the SportElement class and use a dictionary to represent that element instead.
public class DataElement
{
public int Id { get; set; }
public Dictionary<string, string> Sport { get; set; }
}
Which of those two approaches to use will depend on how predictable the structure of the JSON is (or whether or not it's under your control). I find that using a dictionary is a good way of coping with JSON produced by 3rd party applications which aren't under my control, but the resulting objects aren't as easy to work with as those where I know exactly what shape the JSON will always be and can create a strongly-typed class structure representing that shape.
Whichever approach you choose, the usage is the same:
var deserialized = JsonConvert.DeserializeObject<SomeClass>(json);
Step 2 - Populate the DataTable from the object
How to do this step will depend on what you want the DataTable to look like (which is not clear from the question). For example, you might want it to look like this (which I think is what Serge's answer would return).
id
sport id1
sport id2
33306
FB
HB
Or (if for example the sport element could contain any number of id1, id2 and so on elements) you might want it to look like this.
id
sport
33306
id1: FB
33306
id2: HB
Or you might want some different representation altogether. Sorry if that's an incomplete answer, if you want to update the question with what you'd expect the DataTable to look like then I can update this answer with more detail on how to go about step 2.

Need help deserializing C# / .NET 6 into seperate objects

I am attempting to use JsonSerializer.Deserialize() from System.Text.JSON in .NET 6.
I have no control over the format of the JSON.
I have used it successfully in the past but now the data I need to consume is more complicated (but not VERY complicated). I am assuming that I am simply describing my data incorrectly.
I have tried several things.... but the description below is the only way so far that I could consume the data at all.
I think my biggest problem is that I am trying to use the wiz-bang "Paste Special -> Paste JSON as Classes" without really understanding how to form my classes for serialization/deserialization.
Here is a simple example of the JSON I am trying to consume:
[
{
"version": "1.0b",
"sub_version": "x.y.barf"
},
{
"somestring": "I am a string",
"isCool": false,
"a_cool_array": [
"bob",
"jill",
"pete"
]
}
]
If I use the whiz-bang "Paste Special" tool, I get the following generated for me.
public class Rootobject
{
public Class1[] Property1 { get; set; }
}
public class Class1
{
public string version { get; set; }//<-- I need these to remain in their own object
public string sub_version { get; set; }//<-- I need these to remain in their own object
public string somestring { get; set; }
public bool isCool { get; set; }
public string[] a_cool_array { get; set; }
}
Here is the problem that I have.
The whiz-bang tool put my first object (with one version strings) and second (more complicated) object into the same object.
If I use a call like this:
var deserializedJSON = JsonSerializer.Deserialize<List<Class1>>(myJSONTextHere);
I end up with two objects in the list.
The first one has the versions filled out, the second one only has the other fields filled out.
This all makes sense to me but I don't know how to get around the problem.
I need these objects to model the JSON and I need them to save back in the same format when I re-serailize the modified classes elsewhere. This isn't my exact problem as I have simplified it for the question.
I have found one way around this problem.
It is ugly but seems to work. I hate that my code has to know about the data it is manipulating.
I used the actual JSON DOM to split the two disparate classes into individual JSON objects, then used the class de-serializer to load the individual objects into their given types.
In the following example, I am not checking anything.. I happen to know the order of the objects. I could check the raw JSON to make sure it was what I was looking for. In this case, I don't need to.
So, instead of taking the class structure as pasted by the super spiffy "Paste Classes from JSON" thingamajigger.. I split the classes myself.
Like this:
public class VersionClass
{
public string version { get; set; }
public string sub_version { get; set; }
}
public class DataClass
{
public string somestring { get; set; }
public bool isCool { get; set; }
public string[] a_cool_array { get; set; }
}
Then, I can load the JSON into the objects I need like this:
using var jsonDoc = JsonDocument.Parse(jsonText);
var versionClass = jsonDoc.RootElement[0].Deserialize<VersionClass>();
var dataClass = jsonDoc.RootElement[1].Deserialize<DataClass>();
I hope this helps someone having the same problem.
Your json needs to look like this:
{
"class1": [
//more json
],
"class2": [
//more json
]
}
Then you will have:
public class RootObject
{
// class1 and 2 in here
}
public class Class1
{
}
public class Class2
{
}

Separating array and element from a JSON string

I am connecting you Google Places API to retrive results in the form of a JSON string. You can view the complete format of the string Here.
If you a look at it you will see that the actual results array starts after two elements which are html_attributions and next_page_token.
So When i try to deserialize it in this way:
var serializer = new JavaScriptSerializer();
var arr= serializer.Deserialize(result,typeof(string[]));
I get an empty array.
My question is how is there a way i can separate html_attributions and next_page_token fields and the pass the valid results array from the string to be deserialized?
I don't understand the part where you wish to seperate the html_attributions and the next_page_token.
Wouldn't it be sufficient to just deserialize the response with whatever properties that you need?
For example, you can deserialize the response to only retrieve the values that you desire;
// I represent the wrapper result
class Result
{
public List<string> html_attributions { get; set; }
public string next_page_token { get; set; }
public List<ResultItem> results { get; set; }
}
// I represent a result item
class ResultItem
{
public string id { get; set; }
public string name { get; set; }
}
// the actual deserialization
Result Deserialize(string json)
{
var serializer = new JavaScriptSerializer();
return serializer.Deserialize(json, typeof(Result));
}
Edit:
The reason that your deserialization doesn't return you a array of strings is because the response that you retrieve is infact an object and not an array, however the parameter within that object which is named results is an array. In order for you to deserialize more properties you'll have to define them in your "ResultItem" class, sorry for my poor naming here.
For instance, if you'd wish to also retrieve the icon property per result you'll have to add a property named "icon" of type string.
Meanwhile the property "photos" is an array, in order to deserialize it you'll have to create another class and add a property of type list/array of that newly created class, and it has to be named "photos" unless you use a different serializer or use DataContract and DataMember attributes (using the Name property for field mapping).
// the representation of a photo within a result item
class Photo
{
public int height { get; set; }
public List<string> html_attributions { get; set; }
public string photo_reference { get; set; }
public int width { get; set; }
}
// I represent a result item
class ResultItem
{
public string id { get; set; }
public string name { get; set; }
// the added icon
public string icon { get; set; }
// the added photos collection, could also be an array
public List<Photo> photos { get; set; }
}
Just look at the JSON result to figure out what other properties that you might want to add, for instance the "scope" property is an string whilst the "price_level" is an integer.
If I understand your comment correctly you're only interested in the actual results, you'll still have to deserialize the response correctly with its wrapper.
// the actual deserialization
List<ResultItem> Deserialize(string json)
{
var serializer = new JavaScriptSerializer();
var result = serializer.Deserialize(json, typeof(Result));
return result.results;
}
Edit2:
If you really want a string[] as a result you could simply take use of System.Linq using the code above.
string[] stringArray = result.results.Select(r => string.Format("id:{0} - name:{1}", r.id, r.name)).ToArray();
Edit3:
Instead of using the JavascriptSerializer you could use JObject functionality which can be found in the Newtonsoft.Json.Linq library.
var jsonObject = JObject.Parse(json);
string[] results = jsonObject.SelectTokens("results").Select(r => r.ToString()).ToArray();
This will give you an array of strings where each value within the array is the actual json string for each result.
If you however would like to query for the coordinates only:
var jsonObject = JObject.Parse(json);
var coordinates = jsonObject["results"]
.Select(x => x.SelectToken("geometry").SelectToken("location"))
.Select(x => string.Format("{0},{1}", (string)x.SelectToken("lat"), (string)x.SelectToken("lng")))
.ToArray();
This would give you an array of coordinates, eg:
[
"-33.867217,151.195939",
"-33.866786,151.195633",
...
]
Whatever approach you choose you'll be able to accomplish same results using either Newtonsoft or the .net serializer, whilst the Newtonsoft approach would allow you to query without creating strong types for deserialization.
I don't find the point of "[...] pass the valid results array from the string to be deserialized".
Maybe you need to switch to JSON.NET and do something like this:
// You simply deserialize the entire response to an ExpandoObject
// so you don't need a concrete type to deserialize the whole response...
dynamic responseEntity = JsonConvert.DeserializeObject<ExpandoObject>(
googlePlacesJson, new ExpandoObjectConverter()
);
// Now you can access result array as an `IEnumerable<dynamic>`...
IEnumerable<dynamic> results = responseEntity.results;
foreach(dynamic result in results)
{
// Do stuff for each result in the whole response...
}

Designing c# class from json template

I have to design a class based on a json template that i received. I'm stuck at this part of the json:
events: {
"door": [
5,
{
valueone: 27,
valuetwo: "something"
}
],
"window": [
2,
{
valueone: 13,
valuetwo: "something"
}
]
}
The best i can come up with is this property in the root object:
public Dictionary<string, EventData> Events { get; set; }
Where Events is defined like this:
public class EventData
{
public int valueone { get; set; }
public string valuetwo { get; set; }
}
This gives me for example the following output:
Events: {
door: {
valueone: 27,
valuetwo: "something"
}
}
But i have no idea how to design the class to get the numbers in the json example (5 and 2) in the output. I have tried to google for this for a long time today but i'm not quite sure what to search for.
Below is an outline of the code that would fit:
public class Event
{
public List<Elements> door { get; set; }
public List<Elements> window { get; set; }
}
public sealed class Elements
{
public int Id {get; set;}
public IDictionary<string, string> Values { get; set;}
}
You could build your objects with C# then use JSON.Net to serialise them to there JSON counterpart using:
Newtonsoft.Json.JsonConvert.SerializeObject(YOUR-OBJECT-HERE)
Depending on your needs you don't necessarily have to define types for capturing json like that:
For parsing you can use dynamic to capture the json as parsed by some json libararies.
For serializing json you can define anonymous objects like so
Json.Stringify(new {
events = new {
door = new[] {
5,
new { ... }
}
}
});
If you do need to define explicit types (because you want a model in your c# program) you may want to get more clarity about the domain that you are about to model. You can mirror the same JSON with different C# structures, so what really matters here is what the business/requirements do or will look like.
As #Habib noted in his comment you can use json2csharp.com to give you a hint (I did not know of that service until now - looks interesting!), but json2csharp.com will not be able to answer those questions.
Note: The "json" as it stands in your question is not valid JSON.

Deserializing a JSON with variable name/value pairs into object in C#

I am using C# .NET 4.0 to parse a JSON into a custom object. I am using JavaScriptSerializer.Deserialize to map it to a class that I wrote. Problem is, the JSON's name/value pairs are not static and vary depending on the argument isChain, as seen in this JSON fragment (better link at bottom):
{
"STATE_WALK_LEFT":{
"isChain":"1",
"x":"1"
},
"STATE_WALK_LEFT_0":{
"x":"0"
},
"STATE_WALK_LEFT_1":{
"x":"40"
},
"STATE_WALK_LEFT_2":{
"x":"80"
},
"STATE_WALK_RIGHT":{
"isChain":"0"
},
"STATE_RUN_LEFT":{
"isChain":"0"
}
}
The chains can have anywhere from _STATE_0 to _STATE_25 entries in the chains. Is there some way to store this data so I don't have to write 12*26 empty classes like so:
public StateWalkLeft0 STATE_WALK_LEFT { get; set; }
public StateWalkLeft0 STATE_WALK_LEFT_0 { get; set; }
public StateWalkLeft1 STATE_WALK_LEFT_1 { get; set; }
public StateWalkLeft2 STATE_WALK_LEFT_2 { get; set; }
public StateWalkLeft3 STATE_WALK_LEFT_3 { get; set; }
Is there a library or some other way I could use to partially parse only the STATE_0, STATE_1, etc fields? Could you maybe suggest a way to add these recently added JSON pairs?
Edited to clarify:
To get an idea of what I'm working with, here is the Class derived from the JSONs:
Check out my full Class to get an idea of what the JSONs contain
Basically, I just need a way to store these recently implemented chains in this class somehow for processing. All of those classes/properties are generated from these JSONs.
Use Newtonsoft Json.NET and as example following code
internal struct ChainX
{
public int x { get; set; }
public int isChain { get; set; }
}
static string json =
#"{
""STATE_WALK_LEFT"":{
""isChain"":""1"",
""x"":""1""
},
""STATE_WALK_LEFT_0"":{
""x"":""0""
},
""STATE_WALK_LEFT_1"":{
""x"":""40""
},
""STATE_WALK_LEFT_2"":{
""x"":""80""
},
""STATE_WALK_RIGHT"":{
""isChain"":""0""
},
""STATE_RUN_LEFT"":{
""isChain"":""0""
}
}";
and a line of code to deserialize to Dictionary:
var values = JsonConvert.DeserializeObject<Dictionary<string, ChainX>>(json);
after that you can simple access values by dictionary key:
ChainX valueWalkLeft1 = values["STATE_WALK_LEFT_1"];

Categories

Resources