How do I deserialize nested JSON data into a flattened object? - c#

I'm using Json.NET to deserialize incoming json data into an object, but I want to flatten one of the a nested data into a property as an array.
What my incoming json data looks like:
{
“sets": {
"set": [
{
"name": "Act 1:",
“title”: [
{
"name": “A”
},
{
"name": “B”
},
{
"name": “C”
},
{
"name": “D”
}
]
},
{
"name": "Act 2:",
“title”: [
{
"name": “E”
},
{
"name": “F”
},
{
"name": “G”
}
]
}
]
}
}
What I want the transformed data to look like when object is serialized:
{
“sets": {
“title”: [
{
"name": “A”
},
{
"name": “B”
},
{
"name": “C”
},
{
"name": “D”
},
{
"name": “E”
},
{
"name": “F”
},
{
"name": “G”
}
]
}
}
What approach can I take to achieve this? Is it possible to customize how my object gets deserialized?

I know you are asking for it to be done in the deserialization but this gives the same results.
https://dotnetfiddle.net/U89KwW
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
public class Program
{
public const string Json = "{\"sets\": {\"set\": [{\"name\": \"Act 1:\",\"title\": [{\"name\":\"A\"},{\"name\": \"B\"},{\"name\": \"C\"},{\"name\": \"D\"}]},{\"name\": \"Act 2:\",\"title\": [{\"name\": \"E\"},{\"name\": \"F\"},{\"name\": \"G\"}]}]}}";
public static void Main()
{
Something something = JsonConvert.DeserializeObject<Something>(Json);
something.Titles = something.sets.set.SelectMany(c=> c.title).ToList();
something.sets = null;
string JsonResult = JsonConvert.SerializeObject(something);
Console.WriteLine(JsonResult);
}
}
public class Something
{
public Sets sets {get;set;}
public List<Title> Titles {get;set;}
}
public class Sets
{
public List<Set> set {get;set;}
}
public class Set
{
public string name {get;set;}
public List<Title> title {get;set;}
}
public class Title
{
public string name {get;set;}
}

Related

Netwonsoft JSON deserialize into List with named entries

I want to deserialize this JSON:
{
"Home1": [
{
"name": "Hans",
"age": 20
},
{...}
],
"Home2": [
{...},
{...}
]
}
into an List<House>
with these classes:
class Person {
public string Name { get; set; }
public int Age { get; set; }
}
class House : List<Person> {
public string Name { get; set; }
}
How can I tell Newtonsoft JSON that House.Name should be for the key (Home1)?
PS: The class structure is not fixed, but I need the name of the house to be a property in a class.
Leaving behind the rational behind the idea of inheriting a list and your class structure you surely can create custom converter but I would argue much easier option would be to deserialize json into Dictionary<string, House> (which can represent your json structure) and then manually map the names:
var result = JsonConvert.DeserializeObject<Dictionary<string, House>>(json);
foreach (var kvp in result)
{
kvp.Value.Name = kvp.Key;
}
var houses = result.Values;
try this
var deserializedJson = JsonConvert.DeserializeObject<Dictionary<string, List<Person>>>(json);
var houses=new List<House>();
foreach (var element in deserializedJson)
{
houses.Add(new House { Name = element.Key, Persons = element.Value} );
}
var result=JsonConvert.SerializeObject(houses);
}
result
[
{
"Name": "Home1",
"Persons": [
{
"Name": "Hans",
"Age": 20
}
]
},
{
"Name": "Home2",
"Persons": [
{
"Name": "John",
"Age": 22
}
]
}
]
classes
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class House
{
public string Name { get; set; }
public List<Person> Persons {get; set;}
}
Json parsing/deserialization doesn't work this way.
You must have the class of same structure, of what the json is.
Your source json is object having property Home1, Home2 etc.
But you directly expecting it to convert into another structure.
I recommend first convert the json in Real object with the structure of json. Then loop through the property and fill it with loop in List.
Also can you please explain what this class is supposed to do.
class House : List<Person> { public string Name { get; set; } }
For me it doesn't make any sense.
An answer based on you requirement,
How about we clean your JSON string before deserializing and spicing it up with REGEX?
string json = #"{
""Home1"": [
{
""name"": ""Hans"",
""age"": 20
},
{
""name"": ""Hans"",
""age"": 20
},
],
""Home2"": [
{
""name"": ""Hans"",
""age"": 20
},
{
""name"": ""Hans"",
""age"": 20
},
]
}";
/*Replaces all Home + Digit combination to Home*/
json = Regex.Replace(json, #"Home\d*", "Home");
/* Output
{
"Home": [
{
"name": "Hans",
"age": 20
},
{
"name": "Hans",
"age": 20
},
],
"Home": [
{
"name": "Hans",
"age": 20
},
{
"name": "Hans",
"age": 20
},
]
}
*/

How to deserialise JSON from HubSpot

I am having trouble deserializing JSON received from HubSpot ContactList API.
I am using Restsharp and NewtonSoft, and I'm having real struggles understanding how to correctly define the required classes in order to deserialize the JSON string, which is below:
"contacts": [
{
"vid": 2251,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2251",
"properties": {
"firstname": {
"value": "Carl"
},
"lastmodifieddate": {
"value": "1554898386040"
},
"company": {
"value": "Cygnus Project"
},
"lastname": {
"value": "Swann"
}
},
"form-submissions": [],
"identity-profiles": [
{
"vid": 2251,
"saved-at-timestamp": 1553635648634,
"deleted-changed-timestamp": 0,
"identities": [
{
"type": "EMAIL",
"value": "cswann#cygnus.co.uk",
"timestamp": 1553635648591,
"is-primary": true
},
{
"type": "LEAD_GUID",
"value": "e2345",
"timestamp": 1553635648630
}
]
}
],
"merge-audits": []
},
{
"vid": 2301,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2301",
"properties": {
"firstname": {
"value": "Carlos"
},
"lastmodifieddate": {
"value": "1554886333954"
},
"company": {
"value": "Khaos Control"
},
"lastname": {
"value": "Swannington"
}
},
"identity-profiles": [
{
"vid": 2301,
"saved-at-timestamp": 1553635648733,
"deleted-changed-timestamp": 0,
"identities": [
{
"type": "EMAIL",
"value": "cswann#khaoscontrol.com",
"timestamp": 1553635648578,
"is-primary": true
},
{
"type": "LEAD_GUID",
"value": "c7f403ba",
"timestamp": 1553635648729
}
]
}
],
"merge-audits": []
}
],
"has-more": false,
"vid-offset": 2401
}
If I simply request the vid, I correctly get 2 vid's back. It's when I try to do the properties and that i get a fail.
Please help
Lets reduce the Json to the minimum to reproduce your error :
{
"vid": 2301,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2301",
"properties": {
"firstname": {
"value": "Carlos"
},
"lastmodifieddate": {
"value": "1554886333954"
},
"company": {
"value": "Khaos Control"
},
"lastname": {
"value": "Swannington"
}
}
}
And the appropriate class ContactListAPI_Result:
public partial class ContactListAPI_Result
{
[JsonProperty("vid")]
public long Vid { get; set; }
[JsonProperty("portal-id")]
public long PortalId { get; set; }
[JsonProperty("is-contact")]
public bool IsContact { get; set; }
[JsonProperty("profile-url")]
public Uri ProfileUrl { get; set; }
[JsonProperty("properties")]
public Dictionary<string, Dictionary<string, string>> Properties { get; set; }
}
public partial class ContactListAPI_Result
{
public static ContactListAPI_Result FromJson(string json)
=> JsonConvert.DeserializeObject<ContactListAPI_Result>(json);
//public static ContactListAPI_Result FromJson(string json)
// => JsonConvert.DeserializeObject<ContactListAPI_Result>(json, Converter.Settings);
}
public static void toto()
{
string input = #" {
""vid"": 2301,
""portal-id"": 5532227,
""is-contact"": true,
""profile-url"": ""https://app.hubspot.com/contacts/5532227/contact/2301"",
""properties"": {
""firstname"": {
""value"": ""Carlos""
},
""lastmodifieddate"": {
""value"": ""1554886333954""
},
""company"": {
""value"": ""Khaos Control""
},
""lastname"": {
""value"": ""Swannington""
}
}
}";
var foo = ContactListAPI_Result.FromJson(input);
}
But the Value of one property will be burrow in the sub dictionary, we can the project the object in a more usefull one :
public partial class ItemDTO
{
public long Vid { get; set; }
public long PortalId { get; set; }
public bool IsContact { get; set; }
public Uri ProfileUrl { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
Adding the projection to the Class:
public ItemDTO ToDTO()
{
return new ItemDTO
{
Vid = Vid,
PortalId = PortalId,
IsContact = IsContact,
ProfileUrl = ProfileUrl,
Properties =
Properties.ToDictionary(
p => p.Key,
p => p.Value["value"]
)
};
}
Usage :
var result = foo.ToDTO();
Live Demo
Creating and managing class structure for big and nested key/value pair json is tedious task
So one approach is to use JToken instead.
You can simply parse your JSON to JToken and by querying parsed object, you will easily read the data that you want without creating class structure for your json
From your post it seems you need to retrieve vid and properties from your json so try below code,
string json = "Your json here";
JToken jToken = JToken.Parse(json);
var result = jToken["contacts"].ToObject<JArray>()
.Select(x => new
{
vid = Convert.ToInt32(x["vid"]),
properties = x["properties"].ToObject<Dictionary<string, JToken>>()
.Select(y => new
{
Key = y.Key,
Value = y.Value["value"].ToString()
}).ToList()
}).ToList();
//-----------Print the result to console------------
foreach (var item in result)
{
Console.WriteLine(item.vid);
foreach (var prop in item.properties)
{
Console.WriteLine(prop.Key + " - " + prop.Value);
}
Console.WriteLine();
}
Output:

Form the JSON object - serialization C#

"fields": [
{
"field": {
"name": "SMS",
"value": "Yes"
}
},
{
"field": {
"name": "Email",
"value": ""
}
},
{
"field": {
"name": "Total",
"value": ""
}
},
]
I have tried to form the JSON format like above, so i formed the class like below. While serialization it does not return expected form, how can i achieve this one.
public class Test
{
public List<Field> fields;
}
public class Field
{
public string name { get; set; }
public string value { get; set; }
}
Response:
"fields": [{
"name": "SMS",
"value": "Yes"
}, {
"name": "Email",
"value": ""
},{
"name": "Total",
"value": ""
}]
Use this website http://json2csharp.com and generate all the classes automatically. Just copy-paste your json there.
You can customize resulting JSON object with anonymous types and LINQ. Please try this code:
var test = new Test {fields = new List<Field>()};
test.fields.Add(new Field {name = "f1", value = "v1"});
test.fields.Add(new Field {name = "f2", value = "v2"});
var json = JObject.FromObject(new { fields = test.fields.Select(f => new {field = f}).ToArray() })
.ToString();
A json variable would be:
{
"fields": [
{
"field": {
"name": "f1",
"value": "v1"
}
},
{
"field": {
"name": "f2",
"value": "v2"
}
}
]
}
You just missed a class level:
public class Test
{
public List<FieldHolder> fields;
}
public class FieldHolder
{
public Field field { get; set; }
}
public class Field
{
public string name { get; set; }
public string value { get; set; }
}

Cannot deserialize the current JSON array

First: I'm new to using JSON, and I used the answers on here to use Json.Net to deserialize data from a Pokemon API into a C# class (Pokemon class). I used http://json2csharp.com to help me define my class and it looks like this:
public class Pokemon
{
public Pokemon(string json)
{
JsonConvert.PopulateObject(json, this, PokeApi.JsonSerializerSettings);
}
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("evolutions")]
public Evolutions evolutions { get; set; }
[JsonProperty("national_id")]
public int national_id { get; set; }
}
with a bunch of other properties like resource_uri, attack stat, etc.
As the answer offered on the aforementioned link said, I used JsonConvert.DeserializeObject(json) like so:
public Pokemon GetPokemon(int nationalId)
{
using (WebClient client = new WebClient())
{
var json = client.DownloadString("http://pokeapi.co/api/v1/pokemon/" + nationalId + "/");
var output = JsonConvert.DeserializeObject<Pokemon>(json);
return output;
}
}
However I keep getting an exception that says "Cannot deserialize the current JSON array (e.g.[1,2,3]) into type 'Evolutions' because the type requires a JSON object..."
I found a lot of other questions asking the same exact thing, but I was confused with the top answers - sometimes the answer was to use JsonProperty, sometimes it was to use JsonConverter, without really an explanation on what all these meant. Do I need both?
Edit: sample json (call: http://pokeapi.co/api/v1/pokemon/1/)
{
"abilities": [
{
"name": "overgrow",
"resource_uri": "/api/v1/ability/1/"
},
{
"name": "chlorophyll",
"resource_uri": "/api/v1/ability/2/"
}
],
"attack": 49,
"catch_rate": 45,
"created": "2013-11-02T12:08:25.745455",
"defense": 49,
"egg_cycles": 21,
"egg_groups": [
{
"name": "Monster",
"resource_uri": "/api/v1/egg/1/"
},
{
"name": "Grass",
"resource_uri": "/api/v1/egg/8/"
}
],
"ev_yield": "1 Sp Atk",
"evolutions": {
"level": 16,
"method": "level up",
"resource_uri": "/api/v1/pokemon/2/",
"to": "Ivysaur"
},
"exp": 64,
"growth_rate": "ms",
"happiness": 70,
"height": "2'4",
"hp": 45,
"male_female_ratio": "87.5/12.5",
"modified": "2013-11-02T13:28:04.914889",
"moves": [
{
"learn_type": "other",
"name": "Tackle",
"resource_uri": "/api/v1/move/1/"
},
{
"learn_type": "other",
"name": "Growl",
"resource_uri": "/api/v1/move/2/"
},
{
"learn_type": "level up",
"level": 10,
"name": "Vine whip",
"resource_uri": "/api/v1/move/3/"
}
],
"name": "Bulbasaur",
"national_id": 1,
"resource_uri": "/api/v1/pokemon/4/",
"sp_atk": 65,
"sp_def": 65,
"species": "seed pokemon",
"speed": 45,
"total": 318,
"types": [
{
"name": "grass",
"resource_uri": "/api/v1/type/5/"
},
{
"name": "poison",
"resource_uri": "/api/v1/type/8/"
}
],
"weight": "15.2lbs"
}
Evolutions class:
public class Evolutions
{
public int level { get; set; }
public string method { get; set; }
public string resource_uri { get; set; }
public string to { get; set; }
}
I tried http://json2csharp.com/ with http://pokeapi.co/api/v1/pokemon/19/ and what I see is
public class RootObject
{
//...
public List<Evolution> evolutions { get; set; }
//...
}
This pretty mush is your Pokemon class. So you need to declare Evolutions as list.

JSON Deserialization C#

I'm trying to parse out some information I've retrieved from RottenTomatoes that's in a JSON format
{
"cast": [
{
"id": "162655641",
"name": "Tom Hanks",
"characters": [
"Woody"
]
},
{
"id": "162655909",
"name": "Tim Allen",
"characters": [
"Buzz Lightyear"
]
},
{
"id": "162655020",
"name": "Joan Cusack",
"characters": [
"Jessie the Cowgirl"
]
},
{
"id": "162672460",
"name": "Ned Beatty",
"characters": [
"Lots-o'-Huggin' Bear",
"Lotso"
]
},
{
"id": "162657445",
"name": "Richard Kind",
"characters": [
"Bookworm"
]
},
{
"id": "162654813",
"name": "Erik von Detten",
"characters": [
"Sid"
]
},
{
"id": "770713272",
"name": "James Anthony Cotton",
"characters": []
}
],
"links": {
"rel": "http://api.rottentomatoes.com/api/public/v1.0/movies/770672122.json"
}
}
I'm just trying to get this code to work but I'm getting an InvalidOperationException and this error
"Type 'System.String' is not supported for deserialization of an array."
Here's my code in main
string json = File.ReadAllText("json.txt");
CastInfo castMember = new JavaScriptSerializer().Deserialize<CastInfo>(json);
Here are my classes
public class CastInfo
{
public List<CustomCastInfo> cast { get; set; }
}
public class CustomCastInfo
{
public string id { get; set; }
public string name { get; set; }
public List<string> characters { get; set; }
}
And advice? And I realize I need to do something about the "links" in the bottom, but even when I delete that it still doesn't work.
I just tried running this with the json you provided and it worked fine.
using System.Collections.Generic;
using System.IO;
using System.Web.Script.Serialization;
namespace JsonDeserialization
{
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText("json.txt");
CastInfo castMember = new JavaScriptSerializer().Deserialize<CastInfo>(json);
}
}
public class CastInfo
{
public List<CustomCastInfo> cast { get; set; }
}
public class CustomCastInfo
{
public string id { get; set; }
public string name { get; set; }
public List<string> characters { get; set; }
}
}

Categories