Deserialize Nested JSON into C# Objects

Deserialize nested JSON into C# objects

For "Items" use a Dictionary<string, List<Info>>, i.e.:

class Response
{
public Dictionary<string, List<Info>> Items { get; set; }
public string[] Errors { get; set; }
}

class Info
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public int Prop3 { get; set; }
public bool Prop4 { get; set; }
}

This assumes that the item names "Item322A" and "Item2B" will vary from response to response, and reads these names in as the dictionary keys.

Sample fiddle.

Deserialize nested JSON, C#

There are a couple of problems here:

  1. In your Body class, the TrackList property does not match the JSON. The corresponding property in the JSON is called track_list. The class properties must either exactly match the JSON (ignoring case) or else you need to use a [JsonProperty] attribute on the property to indicate what the JSON name will be. For example:

     public class Body
    {
    [JsonProperty("track_list")]
    public List<TrackList> TrackList { get; set; }
    }
  2. You are attempting to deserialize into the Track class, but you should be deserializing to Root since that represents the root of the JSON.

     var root = JsonConvert.DeserializeObject<Root>(json);       

    Once you have deserialized to Root you can "drill down" to print out the tracks.

     foreach (var item in root.message.body.TrackList)
    {
    Console.WriteLine(item.track.track_name);
    }

Fiddle: https://dotnetfiddle.net/JnljGU

Deserialize nested Json into a list

A simple approach is to use JArray and iterate through the values in the DOM, extracting them as needed:

var parsed = JArray.Parse(json);
foreach (var item in parsed[0]["data"])
{
Console.WriteLine($"{item["lat"]} {item["lng"]} {item["fixTime"]}");
}

However, a more robust method is to deserialize into classes. I just pasted your json into https://json2csharp.com. It even suggests how to deserialize your json (although, since the json represents an array I had to update to deserialize to List<Root>). This is the result (comments are mine):

// use this to deserialize
List<Root> myDeserializedClass = JsonConvert.DeserializeObject<List<Root>>(myJsonResponse);

// classes
// you'll need to define what goes here
public class Geozones
{
}

public class Datum
{
public string state { get; set; }
public double lat { get; set; }
public double lng { get; set; }
public int accuracy { get; set; }
public int fixTime { get; set; }
public string source { get; set; }
public Geozones geozones { get; set; }
public string address { get; set; }
public string type { get; set; }
public int id { get; set; }
public DateTime time { get; set; }
public DateTime insertTime { get; set; }
public int seqNbr { get; set; }
}

public class Root
{
public List<Datum> data { get; set; }
public bool truncated { get; set; }
public bool skipped { get; set; }
public string serial { get; set; }
public string name { get; set; }
public string type { get; set; }
}

Then to get the values:

foreach (var item in myDeserializedClass)
{
foreach (var data in item.data)
{
Console.WriteLine($"{data.lat} {data.lng} {data.fixTime}");
}
}

Alternatively, you could mix the two approaches and use ToObject<T>():

List<Datum> items = JArray.Parse(json)[0]["data"].ToObject<List<Datum>>();

How to deserialize nested JSON in C#

All code was tested using VS2019 and working properly.

The simpliest way will be

var root =Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var path = root + @"\SubtitleTranslator\LanguagesList.json";
var json = File.ReadAllText(path);
var jsonDeserialized = JsonConvert.DeserializeObject<Root>(json);
List<Language> languages = null;
if( jsonDeserialized.StatusCode== 200) languages=jsonDeserialized.Result.languages;

or if you don't need any data except languages, try this code

var languages= JObject.Parse(json)["Result"]["languages"].ToObject<Language[]>();

in this case you will need only Language class

OUTPUT (in both cases)

[{"language":"af","language_name":"Afrikaans","native_language_name":"Afrikaans","country_code":"ZA","words_separated":true,"direction":"left_to_right","supported_as_source":false,"supported_as_target":false,"identifiable":true},
{"language":"ar","language_name":"Arabic","native_language_name":"العربية","country_code":"AR","words_separated":true,"direction":"right_to_left","supported_as_source":true,"supported_as_target":true,"identifiable":true},
{"language":"az","language_name":"Azerbaijani","native_language_name":"آذربایجان دیلی","country_code":"AZ","words_separated":true,"direction":"right_to_left","supported_as_source":false,"supported_as_target":false,"identifiable":true}]

Update

you can test it using Console.WriteLine

foreach (var lg in languages)
{
Console.WriteLine($"Language Name: {lg.native_language_name}, Coutry Code: {lg.country_code}");

}

Language class

public class Language
{
public string language { get; set; }
public string language_name { get; set; }
public string native_language_name { get; set; }
public string country_code { get; set; }
public bool words_separated { get; set; }
public string direction { get; set; }
public bool supported_as_source { get; set; }
public bool supported_as_target { get; set; }
public bool identifiable { get; set; }
}

another classes (if needed)

public class Root
{
public int StatusCode { get; set; }
public Headers Headers { get; set; }
public Result Result { get; set; }
}
public class Headers
{
[JsonProperty("X-XSS-Protection")]
public string XXSSProtection { get; set; }

[JsonProperty("X-Content-Type-Options")]
public string XContentTypeOptions { get; set; }

[JsonProperty("Content-Security-Policy")]
public string ContentSecurityPolicy { get; set; }

[JsonProperty("Cache-Control")]
public string CacheControl { get; set; }
public string Pragma { get; set; }

[JsonProperty("Strict-Transport-Security")]
public string StrictTransportSecurity { get; set; }

[JsonProperty("x-dp-watson-tran-id")]
public string XDpWatsonTranId { get; set; }

[JsonProperty("X-Request-ID")]
public string XRequestID { get; set; }

[JsonProperty("x-global-transaction-id")]
public string XGlobalTransactionId { get; set; }
public string Server { get; set; }

[JsonProperty("X-EdgeConnect-MidMile-RTT")]
public string XEdgeConnectMidMileRTT { get; set; }

[JsonProperty("X-EdgeConnect-Origin-MEX-Latency")]
public string XEdgeConnectOriginMEXLatency { get; set; }
public string Date { get; set; }
public string Connection { get; set; }
}

public class Result
{
public List<Language> languages { get; set; }
}
````

How do I deserialize a nested JSON object which is a string in System.Text.Json?

You need to create a custom JsonConverter<T>, where T is EstoData in this case, to be able to correctly deserialise the nested Data JSON object.

This should work, both for deserialisation and serialisation of the object again:

StringToEstoDataConverter.cs

public class StringToEstoDataConverter : JsonConverter<EstoData>
{
public override EstoData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var infoData = jsonDoc.RootElement.GetString();
if (infoData != null)
return JsonSerializer.Deserialize<EstoData>(infoData, options);
}

return default;
}

public override void Write(Utf8JsonWriter writer, EstoData value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}

EstoJarelMaksTulemnus.cs

public class EstoJarelMaksTulemnus
{
public string[] Errors { get; set; }

[JsonConverter(typeof(StringToEstoDataConverter))]
public EstoData Data { get; set; }

public string Mac { get; set; }
}

Usage:

var tulemus = JsonSerializer.Deserialize<EstoJarelMaksTulemnus>(apiResponse, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

Here's a working demo:

public class Program
{
public static void Main()
{
var data =
"{\"errors\":[],\"data\":\"{\\\"id\\\":\\\"iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913\\\",\\\"status\\\":\\\"CREATED\\\",\\\"purchase_url\\\":\\\"https:\\\\\\/\\\\\\/user.esto.ee\\\\\\/application\\\\\\/iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913\\\",\\\"merchant_reference\\\":\\\"158502\\\",\\\"amount\\\":93.95,\\\"currency\\\":\\\"EUR\\\",\\\"is_test\\\":true,\\\"return_url\\\":\\\"http:\\\\\\/\\\\\\/localhost:54274\\\\\\/CheckoutController\\\\\\/EstoJarelmaksOK?tellimus=104742\\\",\\\"notification_url\\\":\\\"http:\\\\\\/\\\\\\/localhost:54274\\\\\\/CheckoutController\\\\\\/EstoJarelmaksTeade?tellimus=104742\\\"}\",\"mac\":\"E9C3E61FC347D80200F542C43ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9\"}";

var tulemus = JsonSerializer.Deserialize<EstoJarelMaksTulemnus>(data, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

Console.WriteLine(tulemus.Errors.Length);
Console.WriteLine(tulemus.Data.Id);
Console.WriteLine(tulemus.Data.Status);
Console.WriteLine(tulemus.Data.Purchase_url);
Console.WriteLine(tulemus.Data.Merchant_reference);
Console.WriteLine(tulemus.Data.Amount);
Console.WriteLine(tulemus.Data.Currency);
Console.WriteLine(tulemus.Data.Is_test);
Console.WriteLine(tulemus.Data.Return_url);
Console.WriteLine(tulemus.Data.Notification_url);
Console.WriteLine(tulemus.Mac);
}
}

public class StringToEstoDataConverter : JsonConverter<EstoData>
{
public override EstoData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var infoData = jsonDoc.RootElement.GetString();
if (infoData != null)
return JsonSerializer.Deserialize<EstoData>(infoData, options);
}

return default;
}

public override void Write(Utf8JsonWriter writer, EstoData value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}

public class EstoJarelMaksTulemnus
{
public string[] Errors { get; set; }

[JsonConverter(typeof(StringToEstoDataConverter))]
public EstoData Data { get; set; }

public string Mac { get; set; }
}

public class EstoData
{
public string Id { get; set; }
public string Status { get; set; }
public string Purchase_url { get; set; }
public string Merchant_reference { get; set; }
public decimal Amount { get; set; }
public string Currency { get; set; }
public bool Is_test { get; set; }
public string Return_url { get; set; }
public string Notification_url { get; set; }
}

Output:

0
iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913
CREATED
https://user.esto.ee/application/iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913
158502
93.95
EUR
True
http://localhost:54274/CheckoutController/EstoJarelmaksOK?tellimus=104742
http://localhost:54274/CheckoutController/EstoJarelmaksTeade?tellimus=104742
E9C3E61FC347D80200F542C43ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9

How to Deserialize complex JSON and create it as C# Object

You've got JSON containing JSON, basically - so you should expect to have to deserialize once. (If you can change the structure of the JSON to avoid this double-serialization, that would be better, admittedly, but I'll assume that's fixed.)

For example, you could have:

public class Root
{
public List<Value> Values { get; set; }
}

public class Value
{
// Add other properties if you need them
public string RawValue { get; set; }
}

Then:

string json = ...;
Root root = JsonConvert.DeserializeObject<Root>(json);
// This just takes the first value - we don't know whether you actually
// ever have more than one...
string rawValue = root.Values[0].RawValue;
JArray array = JArray.Parse(rawValue);

That assumes you're happy using JArray/JObject for the "embedded" objects. If you want to model those as well, you'd have:

public class Station
{
[JsonProperty("ID")]
public int Id { get; set; }
public int StationNo { get; set; }
// etc
}

... then for deserializing:

string json = ...;
Root root = JsonConvert.DeserializeObject<Root>(json);
// This just takes the first value - we don't know whether you actually
// ever have more than one...
string rawValue = root.Values[0].RawValue;
List<Station> stations = JsonConvert.DeserializeObject<List<Station>>(rawValue);

There shouldn't be any "extra" escaping by the time you've deserialized twice.

Deserializing nested JSON array inside nested JSON object in c#?

Install nuget Newtonsoft.Json. Create next hierarchy:

using System;
using System.Collections.Generic;

using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

public class MyClass
{
[JsonProperty("container")]
public Container Container { get; set; }
}

public class Container
{
[JsonProperty("cans1")]
public Cans[] Cans1 { get; set; }

[JsonProperty("ids")]
[JsonConverter(typeof(DecodeArrayConverter))]
public long[] Ids { get; set; }

[JsonProperty("cans2")]
public Cans[] Cans2 { get; set; }
}

public class Cans
{
[JsonProperty("name")]
public string Name { get; set; }

[JsonProperty("ids")]
public string[] Ids { get; set; }
}

And then

 JsonConvert.DeserializeObject<MyClass>(yourJsonString);

UPD

Based on comment, try this:

var des = JsonConvert.DeserializeObject<MyClass>(t);

foreach(var arr in des.Container.Where(r => r.Key.StartsWith("cans")))
{

Console.WriteLine($"{arr.Key}");
foreach(var elem in arr.Value)
{
Console.WriteLine($" {elem.Value<string>("name")}");
}
}

public class MyClass
{
[JsonProperty("container")]
public Dictionary<string, JArray> Container { get; set; }
}


Related Topics



Leave a reply



Submit