Parsing nested JSON objects with JSON.NET - c#

My JSON feed has nested objects like this:
{
"id": 1765116,
"name": "StrozeR",
"birth": "2009-08-12",
"avatar": "http:\/\/static.erepublik.com\/uploads\/avatars\/Citizens\/2009\/08\/12\/f19db99e9baddad73981d214a6e576ef_100x100.jpg",
"online": true,
"alive": true,
"ban": null,
"level": 61,
"experience": 183920,
"strength": 25779.42,
"rank": {
"points": 133687587,
"level": 63,
"image": "http:\/\/www.erepublik.com\/images\/modules\/ranks\/god_of_war_1.png",
"name": "God of War*"
},
"elite_citizen": false,
"national_rank": 6,
"residence": {
"country": {
"id": 81,
"name": "Republic of China (Taiwan)",
"code": "TW"
},
"region": {
"id": 484,
"name": "Hokkaido"
}
}
}
and my object classes are like this:
class Citizen
{
public class Rank
{
public int points { get; set; }
public int level { get; set; }
public string image { get; set; }
public string name { get; set; }
}
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public string avatar { get; set; }
public bool online { get; set; }
public bool alive { get; set; }
public string ban { get; set; }
public string birth { get; set; }
public int level { get; set; }
public int experience { get; set; }
public double strength { get; set; }
public List<Rank> rank { get; set; }
}
}
I try to parse my JSON data with following code
private async void getJSON()
{
var http = new HttpClient();
http.MaxResponseContentBufferSize = Int32.MaxValue;
var response = await http.GetStringAsync(uri);
var rootObject = JsonConvert.DeserializeObject<Citizen.RootObject>(response);
uriTB.Text = rootObject.name;
responseDebug.Text = response;
}
but I get the following error:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Erepublik.Citizen+Rank]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
I can't even parse the value in the main object. Anyway to fix this? and how can I parse a value inside of a nested object? for example: "points" in "rank"

Like the error message says, your rank property in the .NET class is a List<Rank>, but in your JSON it's just a nested object, not an array. Change it to just a Rank instead of a List<Rank>.
Arrays in JSON (or any Javascript, really) are enclosed in []. The {} characters specify a single object. The CLR type has to roughly match the JSON type in order to deserialize. Object to object, array to array.

Related

How to deserialise this nested json response and save the the array values with multiple Jobjects (in Unity)

I have little to no experience in JSON and I am stuck with a problem. Any help is appreciated.
I want to access specifically the names' values from the additionalInformation array.
JSON Response:
{
"statusCode": 200,
"version": 1,
"jsonData": [
{
"additionalInformation": [
{
"id": "XXX94XXXX9xxXx_xxxXXXX",
"name": "xxxx xxx x xxxxxxxx"
},
{
"id": "0xXXxcXxv5PQqT$6i2zLgV",
"name": "xxx xxxxxxxx"
},
{
"id": "11Krt_our2rPCPqJ_2fKZR",
"name": "xxx xxxxxxxx xx"
},
{
"id": "2jYw4IyBP8KuozM_ej7DGf",
"name": "xxxxxxx 1"
},
{
"id": "3B8O805wL1ufabHMz1Je3v",
"name": "xxxxxxx 2"
},
{
"id": "0FVKUYZkvFaxd_OQUiyPBZ",
"name": "xxxxxxx"
},
{
"id": "3O41QFd0573QQvFco5zUUP",
"name": "Xxxxxxxxx"
}
],
"type": 0
}
],
"errorMessages": [],
"warningMessages": [],
"informationMessages": []
}
Model:
public class CFunctions
{
public int statusCode { get; set; }
public int version { get; set; }
public List<PFunctions>[] jsonData { get; set; }
public List<string> errorMessages { get; set; }
public List<string> warningMessages { get; set; }
public List<string> informationMessages { get; set; }
/*public CFunctions()
{
jsonData = new List<PFunctions>();
}*/
}
[Serializable]
public class PFunctions
{
public List<PAdditionalInfo>[] additionalInformation { get; set; }
public int type { get; set; }
/*public PFunctions()
{
additionalInformation = new List<PAdditionalInfo>();
}*/
}
[Serializable]
public class PAdditionalInfo
{
public Guid id { get; set; }
public string name { get; set; }
}
Deserialisation
var request = UnityWebRequest.Get(baseurl);
var operation = request.SendWebRequest();
var jsonResponse = request.downloadHandler.text;
List<CFunctions>[] PFunctionsList = JsonConvert.DeserializeObject<List<CFunctions>[]>(jsonResponse);
Error:
Cannot deserialize the current JSON object into type 'System.Collections.Generic.List`1[CFunctions][]' because the type requires a JSON array to deserialize correctly.
To fix this error either change the JSON to a JSON array or change the deserialized type so that it is a normal .NET type that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'statusCode', line 1, position 14.
UnityEngine.Debug:Log(Object)
What I tried
The error pertains even when I changed List<PAdditionalInfo> to List<PAdditionalInfo>[]
I am not sure how to use JsonObjectAttribute and if it is the best way.
You've declared an array of List<T> in the models, eg List<PAdditionalInfo>[]. The json represents single arrays, not nested. You can fix that by choosing one or the other (I decided to use List<> but array is valid too):
public class PFunctions
{
public List<PAdditionalInfo> additionalInformation { get; set; } // removed []
...
}
public class CFunctions
{
public int statusCode { get; set; }
public int version { get; set; }
public List<PFunctions> jsonData { get; set; } // removed []
...
}
The class you're deserializing to is incorrect. Deserialize to the correct type (which is CFunctions not List<CFunctions>[]):
CFunctions cFunctions = JsonConvert.DeserializeObject<CFunctions>(json);
the most efficient way to get an additional information is this one line code and you only need one class
List<AdditionalInformation> additionalInformation = JObject.Parse(json)
["jsonData"][0]["additionalInformation"].ToObject<List<AdditionalInformation>>();
class
public class AdditionalInformation
{
public string id { get; set; }
public string name { get; set; }
}

Json.JsonSerializationException : Cannot deserialize the current JSON object

My problem is that I'm getting this error when I try to deserialize my API json response.
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Entities.JsonDataType]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
My json data return something like this
{
"success": true,
"result": [
{
"name": "USD Amerikan Doları",
"buying": "6.6920",
"selling": "6.6995"
},
{
"name": "EUR Euro",
"buying": "7.7322",
"selling": "7.7393"
},
{
"name": "GBP İngiliz Sterlini",
"buying": "8.5933",
"selling": "8.6041"
},
"..."
]
}
My class properties:
public class JsonDataType
{
//public string name { get; set; }
//public string buying { get; set; }
//public string selling { get; set; }
public bool success { get; set; }
public List<Result> result { get; set; }
}
public class Result
{
public string name { get; set; }
public string buying { get; set; }
public string selling { get; set; }
}
And I'm getting the error when I deserialize:
List<JsonDataType> X = Newtonsoft.Json.JsonConvert.DeserializeObject<List<JsonDataType>>(response.Content);
Also I tried these codes but none of them working
JsonDataType X = JsonConvert.DeserializeObject(response.Content);
IEnumerable<Result> X = (JsonDataType)JsonConvert.DeserializeObject<IEnumerable<Result>>(response.Content, typeof(JsonDataType));
List<Result> X = JsonConvert.DeserializeObject<JsonDataType>(response.Content, typeof(Result));
If someone could help me i will be so peaceful.
Thanks for your time in advance (✿◠‿◠)
Here is my answer
JsonDataType X = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonDataType>(response.Content);

How can I deserialize my string into JSON?

The idea is that I want to take my string, convert it to a JSON object, then loop through the results array to extract all of the id fields and put them in a separate array.
I've tried multiple 'C# string to JSON examples' but have gotten the farthest with this particular bit of code.
main:
String myString = "{
"total": 111,
"token": "abcdefghijklmn",
"results": [
{
"id": "001",
"some_stuff": {
"aValue": 0,
"bValue": 1
}
},
{
"id": "001",
"some_stuff": {
"aValue": 0,
"bValue": 1
}
},
{
"id": "001",
"some_stuff": {
"aValue": 0,
"bValue": 1
}
},
],
"whatdidido": {
"iretrieved": "yes"
}
}";
var list = JsonConvert.DeserializeObject<List<IdReturn>>(myString);
classes:
public class IdReturn
{
public int total { get; set; }
public string token { get; set; }
public List<Attribute> results { get; set; }
}
public class results
{
public string id { get; set; }
public string some_stuff { get; set; }
}
The expected result is a JSON object that I can use as: list.results[i].id to get to each id. The error message that I get from the code above is:
Unhandled Exception: Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[myExample.IdReturn]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
First your string is not written as valid C#, it should be:
String myString = #"{
""total"": 111,
""token"": ""abcdefghijklmn"",
""results"": [
{
""id"": ""001"",
""some_stuff"": {
""aValue"": 0,
""bValue"": 1
}
},
{
""id"": ""001"",
""some_stuff"": {
""aValue"": 0,
""bValue"": 1
}
},
{
""id"": ""001"",
""some_stuff"": {
""aValue"": 0,
""bValue"": 1
}
},
],
""whatdidido"": {
""iretrieved"": ""yes""
}
}";
Next you need a set of classes to represent the JSON structure:
public class Rootobject
{
public int total { get; set; }
public string token { get; set; }
public Result[] results { get; set; }
public Whatdidido whatdidido { get; set; }
}
public class Whatdidido
{
public string iretrieved { get; set; }
}
public class Result
{
public string id { get; set; }
public Some_Stuff some_stuff { get; set; }
}
public class Some_Stuff
{
public int aValue { get; set; }
public int bValue { get; set; }
}
And finally to deserialize it and print each id you can do this:
var root = JsonConvert.DeserializeObject<Rootobject>(myString);
Console.WriteLine(string.Join(",", root.results.Select(item => item.id)));
Which, for your sample will result in:
001,001,001

Loading JSON file gives serialization error

I have below JSON file,
[
{
"applicationConfig": {
"Name": "Name1",
"Site": "Site1"
},
"pathConfig": {
"SourcePath": "C:\\Temp\\Outgoing1",
"TargetPath": "C:\\Files"
},
"credentialConfig": {
"Username": "test1",
"password": "super1"
}
},
{
"applicationConfig": {
"Name": "Name2",
"Site": "Site2"
},
"pathConfig": {
"SourcePath": "C:\\Temp\\Outgoing2",
"TargetPath": "C:\\Files"
},
"credentialConfig": {
"Username": "test2",
"password": "super2"
}
}
]
And below are C# classes structure,
public class Configurations
{
public List<ApplicationConfig> ApplicationConfigs { get; set; }
public List<PathConfig> PathConfigs { get; set; }
public List<CredentialConfig> CredentialConfigs { get; set; }
}
public class ApplicationConfig
{
public string Name { get; set; }
public string Site { get; set; }
}
public class PathConfig
{
public string SourcePath { get; set; }
public string TargetPath { get; set; }
}
public class CredentialConfig
{
public string Username { get; set; }
public string password { get; set; }
}
Now trying to load JSON and getting below error,
using (var streamReader = new StreamReader(#"./Config.json"))
{
var X = JsonConvert.DeserializeObject<Configurations>(streamReader.ReadToEnd());
}
$exception {"Cannot deserialize the current JSON array (e.g. [1,2,3])
into type 'ConsoleApp8.Configurations' because the type requires a
JSON object (e.g. {\"name\":\"value\"}) to deserialize
correctly.\r\nTo fix this error either change the JSON to a JSON
object (e.g. {\"name\":\"value\"}) or change the deserialized type to
an array or a type that implements a collection interface (e.g.
ICollection, IList) like List that can be deserialized from a JSON
array. JsonArrayAttribute can also be added to the type to force it to
deserialize from a JSON array.\r\nPath '', line 1, position
1."} Newtonsoft.Json.JsonSerializationException
What else I need to serialize?
Your JSON represents an array - although the closing [ should be a ]. But you're trying to serialize it into a single Configurations object. Additionally, you seem to be expecting separate arrays for the application configs, path configs and credential configs - whereas your JSON shows an array of objects, each of which has all three.
I suspect you want:
public class Configuration
{
[JsonProperty("applicationConfig")]
ApplicationConfig ApplicationConfig { get; set; }
[JsonProperty("pathConfig")]
PathConfig PathConfig { get; set; }
[JsonProperty("credentialConfig")]
CredentialConfig CredentialConfig { get; set; }
}
// Other classes as before, although preferably with the password property more conventionally named
Then use:
List<Configuration> configurations =
JsonConvert.DeserializeObject<List<Configuration>>(streamReader.ReadToEnd());
You'll then have a list of configuration objects, each of which will have the three "subconfiguration" parts.
Your JSON class definition is close but not quite. Moroever the last [ must be ]
JSON class definition is created wtih QuickType
public partial class Configuration
{
[JsonProperty("applicationConfig")]
public ApplicationConfig ApplicationConfig { get; set; }
[JsonProperty("pathConfig")]
public PathConfig PathConfig { get; set; }
[JsonProperty("credentialConfig")]
public CredentialConfig CredentialConfig { get; set; }
}
public partial class ApplicationConfig
{
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("Site")]
public string Site { get; set; }
}
public partial class CredentialConfig
{
[JsonProperty("Username")]
public string Username { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
}
public partial class PathConfig
{
[JsonProperty("SourcePath")]
public string SourcePath { get; set; }
[JsonProperty("TargetPath")]
public string TargetPath { get; set; }
}
Finally you need to serialize with
var config_list = JsonConvert.DeserializeObject<List<Configuration>>(streamReader.ReadToEnd());
I think it is a typo, you are opening the square bracket instead of closing it in the JSON file.
[ {
"applicationConfig": {
"Name": "Name1",
"Site": "Site1"
},
"pathConfig": {
"SourcePath": "C:\Temp\Outgoing1",
"TargetPath": "C:\Files"
},
"credentialConfig": {
"Username": "test1",
"password": "super1"
} }, {
"applicationConfig": {
"Name": "Name2",
"Site": "Site2"
},
"pathConfig": {
"SourcePath": "C:\Temp\Outgoing2",
"TargetPath": "C:\Files"
},
"credentialConfig": {
"Username": "test2",
"password": "super2"
} } [ <-HERE

Deserializing json in c# for the nest-api

I am trying trying to Deserialize the Devices json structure below with c#, newtonsoft, and .net 3.5, put have been unable to produce code that works as the "qxdddh" and "q0tL6au" are dynamically generated names.
Ultimately creating a list or array of thermostat classes for each thermostat in the structure (in this case "qxdddh" and "q0tL6au").
{
"thermostats": {
"qxdddh": {
"locale": "en-US",
"temperature_scale": "F",
"is_using_emergency_heat": false,
"has_fan": true,
"software_version": "4.1",
"has_leaf": true,
"device_id": "qxdddh",
"name": "",
"can_heat": true,
"can_cool": true,
"hvac_mode": "heat",
"target_temperature_c": 12.5,
"target_temperature_f": 55,
"target_temperature_high_c": 24.0,
"target_temperature_high_f": 75,
"target_temperature_low_c": 20.0,
"target_temperature_low_f": 68,
"ambient_temperature_c": 21.0,
"ambient_temperature_f": 70,
"away_temperature_high_c": 24.0,
"away_temperature_high_f": 76,
"away_temperature_low_c": 12.5,
"away_temperature_low_f": 55,
"structure_id": "ryWu-tRQstxux0tYhmZ8ESsrGgDjDQ",
"fan_timer_active": false,
"name_long": "Thermostat",
"is_online": true
},
"q0tL6au": {
"locale": "en-US",
"temperature_scale": "F",
"is_using_emergency_heat": false,
"has_fan": true,
"software_version": "4.1",
"has_leaf": true,
"device_id": "q0tL6au",
"name": "Den",
"can_heat": false,
"can_cool": true,
"hvac_mode": "off",
"target_temperature_c": 20.5,
"target_temperature_f": 69,
"target_temperature_high_c": 24.0,
"target_temperature_high_f": 75,
"target_temperature_low_c": 20.0,
"target_temperature_low_f": 68,
"ambient_temperature_c": 23.0,
"ambient_temperature_f": 73,
"away_temperature_high_c": 24.0,
"away_temperature_high_f": 76,
"away_temperature_low_c": 12.5,
"away_temperature_low_f": 55,
"structure_id": "ryWu-tqNu0tYhmZ8ESsrGgDjDQ",
"fan_timer_active": false,
"name_long": "Den Thermostat",
"is_online": true
}
}
}
The initial attempt of code was
public class Devices
{
public TstatDetails[] thermostats { get; set; }
}
public class TstatDetails
{
public string locale { get; set; }
public string temperature_scale { get; set; }
public string is_using_emergency_heat { get; set; }
public string has_fan { get; set; }
public string software_version { get; set; }
public string has_leaf { get; set; }
public string device_id { get; set; }
public string name { get; set; }
public string can_heat { get; set; }
public string can_cool { get; set; }
public string hvac_mode { get; set; }
public string target_temperature_c { get; set; }
public string target_temperature_f { get; set; }
public string target_temperature_high_c { get; set; }
public string target_temperature_high_f { get; set; }
public string target_temperature_low_c { get; set; }
public string target_temperature_low_f { get; set; }
public string ambient_temperature_c { get; set; }
public string ambient_temperature_f { get; set; }
public string away_temperature_high_c { get; set; }
public string away_temperature_high_f { get; set; }
public string away_temperature_low_c { get; set; }
public string away_temperature_low_f { get; set; }
public string structure_id { get; set; }
public string fan_timer_active { get; set; }
public string name_long { get; set; }
public string is_online { get; set; }
}
and
Devices tstats = (Devices) Newtonsoft.Json.JsonConvert.DeserializeObject<Devices>(jsonstring);
Which produces and exception with the following description
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type 'NestTest.NestOAuth2+TstatDetails[]' because the type
requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g.
[1,2,3]) or change the deserialized type so that it is a normal .NET
type (e.g. not a primitive type like integer, not a collection type
like an array or List) that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to
deserialize from a JSON object.
I understand the error (i think) but being fairly new to c# am unsure on how to correct for this scenario.
Just change your Devices class to use a Dictionary<,> instead of an array:
public class Devices
{
public Dictionary<string, TstatDetails> thermostats { get; set; }
}
JSON.NET will interpret each property of the thermostats object in the JSON as an entry in the dictionary, and populate it appropriately. (Your calling code remains exactly the same.)
Then you'll have all the thermostats available by ID. For example:
TstatDetails details = tstats["qxdddh"];
Once that's working, I'd strongly recommend you try to make all the property names more conventional :)
Your Json object should be an array, not just an object.
It should basically be wrapped with [ .... ] (of which within you can definitely have multiple objects) rather than { ... }.
It should probably look similar to this:
[
{
"locale": "en-US",
"temperature_scale": "F",
"is_using_emergency_heat": false,
...
},
{
"locale": "en-US",
"temperature_scale": "F",
"is_using_emergency_heat": false,
...
}
]
EDIT
OK, I can't compete with The Skeet.
But I'll leave my answer because it's correct as well (just one option to attack the problem).

Categories