How to parse multilayered JSON object? [duplicate] - c#

This question already has answers here:
Create a strongly typed c# object from json object with ID as the name
(1 answer)
How can I parse a JSON string that would cause illegal C# identifiers?
(3 answers)
Closed 11 months ago.
I receive the following kind of response after a JSON request:
{
participants:{
"0":{
"name":"Name1",
"lastname": "lastname",
"email":"last#name.com",
"id":"12345"
},
"1":{
"name":"Name2",
"lastname": "lastname2",
"email":"last#name2.de",
"id":"72382"
}
}
}
So far only way I found so far to deserialize this is like this:
using System;
using Newtonsoft.Json;
namespace JSONParse
{
public class Root
{
public object participants { get; set; }
}
class MainClass
{
public static void Main(string[] args)
{
var myJson = JsonConvert.DeserializeObject<Root>(jsonMsg);
//Do stuff with it
Console.WriteLine(myJson.participants.ToString());
Console.ReadLine();
}
private static string jsonMsg = #"{
participants:{
""0"":{
""name"":""Name1"",
""lastname"": ""lastname"",
""email"":""last#name.de"",
""id"":""12345""
},
""1"":{
""name"":""Name2"",
""lastname"": ""lastname2"",
""email"":""last#name2.de"",
""id"":""72382""
}
}
}";
}
}
I've tried parsing it as both an array and a list, but this fails as this object is neither. It looks like a "de-arrayed array", so to speak.
The other, not practical, solution I found would be to create a new class for every possible key inside the response. But since the real data can have a possible unlimited number of keys, this is out of the question. It's not feasible to create an infinite amount of identical classes, all conveniently namend 0 to infinity.
How can I parse this response, so I can access the information correctly from within my code?

Related

JSON.NET deserialize JSON then format string [duplicate]

This question already has answers here:
running a transformation on a Json DeserializeObject for a property
(2 answers)
Closed 3 years ago.
I have the following JSON:
{
"lastOcurrences":[
{
"myString":"16726354"
},
{
"myString":"66728744"
},
{
"myString":"91135422"
}
]
}
and I have a class to deserialize it on:
public class JsonObject
{
public List<LastOcurrence> LastOcurrences { get; set; }
}
public class LastOcurrence
{
public string MyString { get; set; }
}
Upon deserializing it with JsonConvert.DeserializeObject<T>(json), I'd like to be able to format the string myString, to store 167-263-54, instead of 16726354.
What solution would please my soul: Using attributes on the properties, something of the likes of JsonConverter, but...
What i'd like to avoid doing: I would not like to use reflection to iterate through every property, only to then read the attribute and apply the formatting. Is there any way of doing this 'automatically' with JsonConvert?
One possible solution is to use custom getters and setters for this and when it is deserialized you keep the raw data stored. This will do JIT formatting. Depending on the usage of this data this could be much quicker however if there are a lot of repeated reads of the same data then this may be a bit slower.
public class LastOcurrence
{
private string _myString;
public string MyString
{
get { return Regex.Replace(_myString, #"^(.{ 3})(.{ 3})(.{ 2})$", "$1-$2-$3"); }
set { _myString = value; }
}
}

DESerialize JSON to c# objects dynamically

I am getting JSON data from a webservice. it is providing me with FORM DATA with different questions and answers. every answer is a different c# object. I am trying to find the best way to map the ANSWERS to correct c# object.
for example if Question Id is "37" Then its a Address Object.
I have JSON String like in this format below
"answers": {
"37": {
"name": "yourAddress37",
"order": "6",
"sublabels": "{\"cc_firstName\":\"First Name\",\"cc_lastName\":\"Last Name\",\"cc_number\":\"Credit Card Number\",\"cc_ccv\":\"Security Code\",\"cc_exp_month\":\"Expiration Month\",\"cc_exp_year\":\"Expiration Year\",\"addr_line1\":\"Street Address\",\"addr_line2\":\"Street Address Line 2\",\"city\":\"City\",\"state\":\"State \\/ Province\",\"postal\":\"Postal \\/ Zip Code\",\"country\":\"Country\"}",
"text": "Your Home Address:",
"type": "control_address",
"answer": {
"addr_line1": "148 east 38st ",
"addr_line2": "",
"city": "Brooklyn ",
"state": "Ny",
"postal": "11203",
"country": ""
},
"prettyFormat": "Street Address: 148 east 38st <br>City: Brooklyn <br>State / Province: Ny<br>Postal / Zip Code: 11203<br>"
},
"38": {
"name": "emergencyContact",
"order": "9",
"sublabels": "{\"prefix\":\"Prefix\",\"first\":\"First Name\",\"middle\":\"Middle Name\",\"last\":\"Last Name\",\"suffix\":\"Suffix\"}",
"text": "Emergency Contact Name:",
"type": "control_fullname",
"answer": {
"first": "Pauline ",
"last": "Sandy "
},
"prettyFormat": "Pauline Sandy "
}
}
and it MAPS to following c# property
public Dictionary<int, answer> answers{ get; set; }
Then I have a generic Answer class
public class answer
{
public string name { get; set; }
public dynamic answer { get; set; }
}
if you look at the ANSWER data from json then you will see its different for every question. for example one answer would be ADDRESS OBJECT, other answer would be FIRST & LAST NAME object.
my question is, how can i deserialize json into correct objects/properties automatically? I can create different POCO objects, such as address & ProfileName, but how would i map them automatically to correct object/property.
EDIT:
Loop through all Answers
foreach (var a in item.answers)
{
// pass the ANSWER OBJECT (dynamic data type) to function
createNewApplication(System.Convert.ToInt16(a.Key), a.Value.answer,ref app);
}
private void createNewApplication(int key, dynamic value,ref HcsApplicant app)
{
if (key == 4) // data is plain string
app.yourPhone = value;
if (key == 8)
app.yourEmail = value;
if (key==37) // data is a object
app.address = value.ToObject<address>();
}
is this approach OK? any cleaner way of doing it?
I personally don't like every option that involves custom parsing and looking directly on the questions.
You can make use of partial deserialization via JToken class.
Just declare your answers dictionary as such:
public Dictionary<int, JToken> Answers{ get; set; }
And then whenever you need the address page you can simply do Answers[37].ToObject<Address>(). How you manage to call this method, depends upon the rest of your code, but you can embed it in properties, in a big switch, in multiple methods, one for each class. One option I like is to have a static From method in each deserializable class:
public class Address
{
public string Name { get; set; }
// all the othe properties
// ....
public static Address From(Dictionary<int, JToken> answers)
{
return answers?.TryGetValue(37, out var address) ?? false
? address?.ToObject<Address>()
: null;
}
}
// so you can just write:
var address = Address.From(answers);
As a side note, remember that the default deserialization settings for Json.Net are case insensitive, so you can deserialize the name property from JSON to a more idiomatic Name property on your POCOs.
Make a constructor for each answer type that constructs by parsing a JSON object string. Make all the answers implement an interface, e.g. IAnswer. Map all constructors (as functions) to the corresponding question IDs in a dictionary. Lastly, loop through the questions, call each constructor, and maybe put them in a new dictionary.
Example code:
interface IAnswer { };
public class ExampleAnswer : IAnswer
{
public ExampleAnswer(String JSONObject)
{
// Parse JSON here
}
}
delegate IAnswer AnswerConstructor(String JSONObject);
Dictionary<int, AnswerConstructor> Constructors = new Dictionary<int, AnswerConstructor>()
{
{1234, ((AnswerConstructor)(json => new ExampleAnswer(json)))}
// Add all answer types here
};
Dictionary<int, IAnswer> ParseAnswers(Dictionary<int, String> JSONObjects)
{
var result = new Dictionary<int, IAnswer>();
foreach (var pair in JSONObjects)
result.Add(pair.Key, Constructors[pair.Key](pair.Value));
return result;
}
Edit: Look at Matt's answer for some good options for how to parse JSON.
Edit2, In response to your edit: That looks like a good way of doing it! I think it's better than my answer, since you can keep all type information, unlike my method.
The only thing I see that you might want to change is using else if or switch instead of multiple ifs. This could increase performance if you have many answers.
You have a couple of options:
Deserialize into a dynamic object using the System.Web package as per this answer or the JSON.Net package as per this answer then use conditional checks/the null propagation operator to access a property.
Automatically deserialize down to the level where there are differences, then have code to manual deserialize the properties that are different into the correct POCO types on your parent Deserialized object.
Leverage one of the Serialization Callbacks provided by JSON.Net (OnDeserializing or OnDeserialized) to handle populating the different properties into the correct types as part of the deserialization pipeline.
With approaches 2 and 3 you could write a nicer helper method on your POCO that inspected the objects properties and returned a result which would be the type that was set (I would recommend returning an Enum) e.g.:
public PropertyTypeEnum GetPropertyType(MyPocoClass myPocoClass)
{
if (myPocoClass.PropertyOne != null)
{
return PropertyTypeEnum.TypeOne;
}
else if (...)
{
return PropertyTypeEnum.TypeN
}
else
{
// probably throw a NotImplementedException here depending on your requirements
}
}
Then in your code to use the object you can use the returned Enum to switch on the logical paths of your code.

How to deserialize a json data array [duplicate]

This question already has answers here:
How to deserialize a JSON array into an object using Json.Net?
(2 answers)
Serializing/deserializing arrays with mixed types using Json.NET
(1 answer)
Closed 3 years ago.
I have this json file:
{
"timestamp": 1557323147422,
"change_id": 11687520784,
"data": [
[ "new", 5775.0, 16530.0 ],
[ "new", 5774.5, 360.0 ]
]
}
I need to set up a class to deserialize it, but the data array is causing me a problem.
I tried to map data to:
List<(string, double, double)>
but that doesn't work.
List works, but then it's just pushing the problem one step away.
I can map it to
List<dynamic>
and then I get a list of JArray that I need to parse individually.
What I need is to be able to map it to some class that has a string and 2 doubles.
You can use http://json2csharp.com/
I generated this code:
public class RootObject
{
public long timestamp { get; set; }
public long change_id { get; set; }
public List<List<object>> data { get; set; }
}
Your array is still an array of object in JSON, it is neither a tuple nor a type.
So List<List<object>> (or IEnumerable<IEnumerable<object>>) seems to be the only option.

How to deserialize only part of the json document? [duplicate]

This question already has answers here:
Deserializing just a single node of a JSON response
(2 answers)
Closed 4 years ago.
Using Json.Net on dotnet core v3 preview.
The json looks similar to:
{
"rootElement": {
"id": 500,
"name": "water balloon"
}
}
I would like to deserialize this into an object that looks like:
public class Item {
public int id {get;set;}
public string name {get;set;}
}
instead of the much more annoying:
public class ItemWrapper {
public Item rootElement {get;set;}
}
This is obviously a contrived example, but it illustrated the problem. The actual Item class is far more complicated. And there are many of them. So I'm trying to identify a solution that will work for any json document that has this general format with a root node followed by the object I am actually interested in.
Any thoughts?
You can use JObject.Parse from Newtonsoft.Json.Linq namespace, and get your item like so:
var obj = JObject.Parse("json");
var item = obj["rootElement"].ToObject<Item>();

Parse json name begins with number in C# by Json.net - Newtonsoft [duplicate]

This question already has answers here:
Deserialize json that has some property name starting with a number
(2 answers)
Closed 5 years ago.
I need to parse JSON file in C# code by using JSON.net (Newtonsoft)
But json file I receive begins as this:
{"3h":3}
the variable name begins with number but c# can't do like this.
How can I set the value in the right way? Should I swap the variable name by my self? That would make very dirty code.
Thank you.
You can do this little focus with mapping:
class Program
{
static void Main(string[] args)
{
string jsonInput = #"{""3h"":3}";
var result = (myJsonObj)JsonConvert.DeserializeObject<myJsonObj>(jsonInput);
Console.WriteLine(result.MyProperty);
}
}
public class myJsonObj
{
[JsonProperty(PropertyName = "3h")]
public string MyProperty { get; set; }
}

Categories