Deserialize a json object with different structure and same name - c#

I write an app that gets IMDb movie information by scraping movie page source. Some of the movie data in page source are in JSON format with movie schema from "Schema.org".
{
"#context": "http://schema.org",
"#type": "Movie",
"url": "/title/tt7131622/",
"name": "Once Upon a Time... in Hollywood",
"genre": [
"Comedy",
"Drama"
],
"actor": [
{
"#type": "Person",
"url": "/name/nm0000138/",
"name": "Leonardo DiCaprio"
},
{
"#type": "Person",
"url": "/name/nm0000093/",
"name": "Brad Pitt"
},
{
"#type": "Person",
"url": "/name/nm3053338/",
"name": "Margot Robbie"
},
{
"#type": "Person",
"url": "/name/nm0386472/",
"name": "Emile Hirsch"
}
],
"director": {
"#type": "Person",
"url": "/name/nm0000233/",
"name": "Quentin Tarantino"
},
"creator": [
{
"#type": "Person",
"url": "/name/nm0000233/",
"name": "Quentin Tarantino"
},
{
"#type": "Organization",
"url": "/company/co0050868/"
},
{
"#type": "Organization",
"url": "/company/co0452101/"
},
{
"#type": "Organization",
"url": "/company/co0159772/"
}
}
I made a "Movie" class to deserialize the JSON object. There is a property Person class with the name "Director".
internal class ImdbJsonMovie
{
public string Url { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public List<string> Genre { get; set; }
public List<ImdbJsonPerson> Actor { get; set; }
public ImdbJsonPerson Director { get; set; }
//public string[] Creator { get; set; }
}
It's OK. But the problem is some movies such as "The Matrix" have more than one director.
{
"#context": "http://schema.org",
"#type": "Movie",
"url": "/title/tt0133093/",
"name": "The Matrix",
"genre": [
"Action",
"Sci-Fi"
],
"actor": [
{
"#type": "Person",
"url": "/name/nm0000206/",
"name": "Keanu Reeves"
},
{
"#type": "Person",
"url": "/name/nm0000401/",
"name": "Laurence Fishburne"
},
{
"#type": "Person",
"url": "/name/nm0005251/",
"name": "Carrie-Anne Moss"
},
{
"#type": "Person",
"url": "/name/nm0915989/",
"name": "Hugo Weaving"
}
],
"director": [
{
"#type": "Person",
"url": "/name/nm0905154/",
"name": "Lana Wachowski"
},
{
"#type": "Person",
"url": "/name/nm0905152/",
"name": "Lilly Wachowski"
}
],
"creator": [
{
"#type": "Person",
"url": "/name/nm0905152/",
"name": "Lilly Wachowski"
},
{
"#type": "Person",
"url": "/name/nm0905154/",
"name": "Lana Wachowski"
},
{
"#type": "Organization",
"url": "/company/co0002663/"
},
{
"#type": "Organization",
"url": "/company/co0108864/"
},
{
"#type": "Organization",
"url": "/company/co0060075/"
},
{
"#type": "Organization",
"url": "/company/co0019968/"
},
{
"#type": "Organization",
"url": "/company/co0070636/"
}
}
So it must be List<Person>.
internal class ImdbJsonMovie
{
public string Url { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public List<string> Genre { get; set; }
public List<ImdbJsonPerson> Actor { get; set; }
public List<ImdbJsonPerson> Director { get; set; }
//public string[] Creator { get; set; }
}
Another problem is how to deserialize creator property that is made by the Person class and Organization class.
So the question is "How to deserialize this complex JSON object?"
Thank you

Did you try: https://app.quicktype.io/?l=csharp? It can generate model in C# for you, which is very good begining for further changes (if the Schema has to be different according to different json responses)
I did enter your JSON and the model created is following:
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Movies
{
[JsonProperty("#context")]
public Uri Context { get; set; }
[JsonProperty("#type")]
public string Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("genre")]
public List<string> Genre { get; set; }
[JsonProperty("actor")]
public List<Tor> Actor { get; set; }
[JsonProperty("director")]
public List<Tor> Director { get; set; }
[JsonProperty("creator")]
public List<Tor> Creator { get; set; }
}
public partial class Tor
{
[JsonProperty("#type")]
public TypeEnum Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; set; }
}
public enum TypeEnum { Organization, Person };
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
TypeEnumConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class TypeEnumConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(TypeEnum) || t == typeof(TypeEnum?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
switch (value)
{
case "Organization":
return TypeEnum.Organization;
case "Person":
return TypeEnum.Person;
}
throw new Exception("Cannot unmarshal type TypeEnum");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (TypeEnum)untypedValue;
switch (value)
{
case TypeEnum.Organization:
serializer.Serialize(writer, "Organization");
return;
case TypeEnum.Person:
serializer.Serialize(writer, "Person");
return;
}
throw new Exception("Cannot marshal type TypeEnum");
}
public static readonly TypeEnumConverter Singleton = new TypeEnumConverter();
}
}
[Update]
As for problems with sometime single, sometime array thing --> look here: How to handle both a single item and an array for the same property using JSON.net

Thank you #Piotr. It completely worked. because your first part of the answer was not correct for me, I rewrite your response as an answer.
as you said the correct answer was in this link.
https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n
So I made this class.
class JsonConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(List<T>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<List<T>>();
}
return new List<T> { token.ToObject<T>() };
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
and changed my Movie Class to this.
internal class ImdbJsonMovie
{
public string Url { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("image")]
public string Image { get; set; }
[JsonProperty("genre")]
[JsonConverter(typeof(JsonConverter<string>))]
public List<string> Genre { get; set; }
[JsonProperty("contentRating")]
public string ContentRating { get; set; }
[JsonProperty("actor")]
[JsonConverter(typeof(JsonConverter<ImdbJsonTypeEnum>))]
public List<ImdbJsonTypeEnum> Actor { get; set; }
[JsonProperty("director")]
[JsonConverter(typeof(JsonConverter<ImdbJsonTypeEnum>))]
public List<ImdbJsonTypeEnum> Director { get; set; }
[JsonProperty("creator")]
[JsonConverter(typeof(JsonConverter<ImdbJsonTypeEnum>))]
public List<ImdbJsonTypeEnum> Creator { get; set; }
}
and this Enum
public class ImdbJsonTypeEnum
{
[JsonProperty("#type")]
public TypeEnum Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
public enum TypeEnum
{
Organization,
Person
};
}
It worked for one director and multi director movies.
Thank you

Related

NSwag Duplicate objects created

I use NSwagStudio to create a C# client from an OpenAPI document.
So far everything works, but I noticed a problem to which I haven't found a solution yet.
The problem is that NSwagStudio creates duplicate classes for a recurring structure.
The following JSON as an example:
{
"components": {
"schemas": {
"Person": {
"type": "object",
"properties": {
"Id": {
"type": "string"
},
"Name": {
"type": "string"
},
"First Name": {
"type": "string"
},
"Lastname": {
"type": "string"
},
"attributes": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"url": {
"type": "string"
}
}
}
},
"description": "Account Object"
},
"Address": {
"type": "object",
"properties": {
"Id": {
"type": "string"
},
"Street": {
"type": "string"
},
"Post Code": {
"type": "string"
},
"City": {
"type": "string"
},
"Country": {
"type": "string"
},
"attributes": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"url": {
"type": "string"
}
}
}
},
"description": "Address Object"
}
}
}
}
Here are 2 simple objects described, Person and Address.
Both objects have this structure in common:
"attributes" : {
"type" : "object",
"properties" : {
"type" : {
"type" : "string"
},
"url" : {
"type" : "string"
}
}
}
In C#, the result looks like this:
public partial class Attributes
{
[Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Type { get; set; }
[Newtonsoft.Json.JsonProperty("url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Url { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
public string ToJson()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(this, new Newtonsoft.Json.JsonSerializerSettings());
}
public static Attributes FromJson(string data)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<Attributes2>(data, new Newtonsoft.Json.JsonSerializerSettings());
}
}
public partial class Attributes2
{
[Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Type { get; set; }
[Newtonsoft.Json.JsonProperty("url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Url { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
public string ToJson()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(this, new Newtonsoft.Json.JsonSerializerSettings());
}
public static Attributes2 FromJson(string data)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<Attributes2>(data, new Newtonsoft.Json.JsonSerializerSettings());
}
}
These attribute classes themselves are just helper classes for other classes.
In total over 700 of them were created.
Is it not possible to create only one class for this?
The path part of the OpenAPI document contains $ref references to the "main" object
{
"/Person": {
"description": "",
"get": {
"responses": {
"200": {
"description": "Status Code 200",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Person"
}
}
}
},
}
}
}
}
The C# class Person, which is specified by $ref (see above)
Here the getter/setter with Attributes372 class.
public partial class Person
{
[Newtonsoft.Json.JsonProperty("Id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Id { get; set; }
[Newtonsoft.Json.JsonProperty("Name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Name{ get; set; }
[Newtonsoft.Json.JsonProperty("LastName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string LastName { get; set; }
[Newtonsoft.Json.JsonProperty("FirstName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string FirstName { get; set; }
[Newtonsoft.Json.JsonProperty("attributes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public Attributes372 Attributes { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
}
``

How to remove a middle property from JSON in System.Text.Json?

Let's say we have these C# classes:
public class Teacher
{
public long Id { get; set; }
public string Name { get; set; }
public boolean IsActive { get; set; }
public dynamic RelatedItems { get; set; }
}
public class Student
{
public long Id { get; set; }
public string Name { get; set; }
public double AverageScrore { get; set; }
public dynamic RelatedItems { get; set; }
}
public class Course
{
public long Id { get; set; }
public string Title { get; set; }
}
And here's the object graph that is built:
var teacher = teacherService.Get(teacherId);
teacher.RelatedItems.Students = studentService.GetByTeacherId(teacherId);
foreach (var student in teacher.RelatedItems.Students)
{
student.RelatedItems.Courses = courseService.GetStudentCourses(studentId);
}
The object graph above produces this JSON after serialization (using System.Text.Json):
{
"Id": "5",
"Name": "John",
"IsActive": true,
"RelatedItems": {
"Students": [
{
"Id": 7,
"Name": "Joe",
"AverageScore": 9.3,
"RelatedItems": {
"Courses": [
{
"Id": 12,
"Title": "Math"
}
]
}
}
]
}
}
What I need to do is to remove those RelatedItems in the serialized JSON, and move their children one step up. This would be the result:
{
"Id": "5",
"Name": "John",
"IsActive": true,
"Students": [
{
"Id": 7,
"Name": "Joe",
"AverageScore": 9.3,
"Courses": [
{
"Id": 12,
"Title": "Math"
}
]
}
]
}
Is it possible to be done via System.Text.Json?
You have to write custom classes for serialization
var options = new JsonSerializerOptions();
options.Converters.Add(new CustomJsonConverter());
json = JsonSerializer.Serialize(StudentClassObject, options);
Implementation of CustomJsonConverter
public class CustomJsonConverter : JsonConverter<Student>
{
public override Book Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// Use default implementation when deserializing (reading)
return JsonSerializer.Deserialize<Book>(ref reader, options);
}
public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
{
writer.WriteStartObject();
using (JsonDocument document = JsonDocument.Parse(JsonSerializer.Serialize(value)))
{
foreach (var property in document.RootElement.EnumerateObject())
{
if (property.Name != "RelatedItems")
property.WriteTo(writer);
}
}
writer.WriteEndObject();
}
}

Complicated Json to C# Object Deserialize with classes

I am trying to deserialize a json response I get from a web call. I have it 90 percent figured out. The only part I am having a hard time figuring out is there are these json arrays which have data in them and each array name is unique using the email address. I have not been able to figure out how to turn the Email Arrays into 1. Dynamic and having it create many lists or just a couple depending on what comes back in the response and also dynamically naming the list arrays to put the data into the Records class.
As you can see in the Records class I need this to be more dynamic and flexible to receive any and all emails.
Below is the json:
{
"result": {
"records": {
"joeblow#gmail.com": [
{
"OrderId": "d9535109-d305-4584-a503-8194bbcfcff2",
"CompletedOrderId": "BCFCFF2",
"CustomerId": 1212,
"CompletedTime": "2020-10-26 13:32:02",
"Email": "joeblow#gmail.com",
"ShippingFirstName": "Joe",
"ShippingMiddleName": "",
"ShippingLastName": "Blow",
"LineItems": {
"tfl.es.bluray": { "qty": 1 },
"booklets.en.ebook": { "qty": 1 }
}
}
],
"cleob#hotmail.com": [
{
"OrderId": "7bf97b3a-bc46-411c-bc30-12563326dba0",
"CompletedOrderId": "326DBA0",
"CustomerId": 1212,
"CompletedTime": "2020-10-26 20:07:44",
"Email": "cleob#hotmail.com",
"ShippingFirstName": "Cleo",
"ShippingMiddleName": "",
"ShippingLastName": "Blue",
"LineItems": {
"tfl.es.bluray": { "qty": 1 },
"booklets.en.ebook": { "qty": 1 },
"aos.en.pb": { "qty": 1 },
"course-tos.en.olr": { "qty": 1 },
"pow-hsk-nofilm.en.combo": { "qty": 1 },
"course-organizing.en.olr": { "qty": 1 }
}
}
],
"johnd#gmail.com": [
{
"OrderId": "630f0dda-94c3-4b82-a070-2554004dce29",
"CompletedOrderId": "04DCE29",
"CustomerId": 12345,
"CompletedTime": "2020-10-25 21:52:04",
"Email": "johnd#gmail.com",
"ShippingFirstName": "John",
"ShippingMiddleName": "",
"ShippingLastName": "Doe",
"LineItems": {
"tfl.es.bluray": { "qty": 1 },
"booklets.en.ebook": { "qty": 1 },
"aos.en.pb": { "qty": 1 },
"course-tos.en.olr": { "qty": 1 },
"pow-hsk-nofilm.en.combo": { "qty": 1 },
"course-organizing.en.olr": { "qty": 1 },
"oak-2007.en.cd": { "qty": 1 }
}
}
]
},
"errors": [
{
"id": "bademailaddress-yahoo.com",
"message": "Email address 'bademailaddress-yahoo.com' is not a valid email address"
}
]
},
"jsonrpc": "2.0",
"id": 12345634523
}
And the classes I made for the json deserialization:
public partial class JsonEmailDeSerializer
{
[JsonProperty("result")]
public Result Result { get; set; }
[JsonProperty("jsonrpc")]
public string Jsonrpc { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
}
public partial class Result
{
[JsonProperty("records")]
public Records Records { get; set; }
[JsonProperty("errors")]
public List<Error> Errors { get; set; }
}
public partial class Error
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
public partial class Records
{
[JsonProperty("joeblow#gmail.com")]
public List<MailCom> JoeblowGmailCom { get; set; }
[JsonProperty("cleob#hotmail.com")]
public List<MailCom> CleobHotmailCom { get; set; }
[JsonProperty("johnd#gmail.com")]
public List<MailCom> JohndGmailCom { get; set; }
}
public partial class MailCom
{
[JsonProperty("OrderId")]
public Guid OrderId { get; set; }
[JsonProperty("CompletedOrderId")]
public string CompletedOrderId { get; set; }
[JsonProperty("CustomerId")]
public long CustomerId { get; set; }
[JsonProperty("CompletedTime")]
public DateTimeOffset CompletedTime { get; set; }
[JsonProperty("Email")]
public string Email { get; set; }
[JsonProperty("ShippingFirstName")]
public string ShippingFirstName { get; set; }
[JsonProperty("ShippingMiddleName")]
public string ShippingMiddleName { get; set; }
[JsonProperty("ShippingLastName")]
public string ShippingLastName { get; set; }
[JsonProperty("LineItems")]
public Dictionary<string, LineItem> LineItems { get; set; }
}
public partial class LineItem
{
[JsonProperty("qty")]
public long Qty { get; set; }
}
public partial class JsonEmailDeSerializer
{
public static JsonEmailDeSerializer FromJson(string json) => JsonConvert.DeserializeObject<JsonEmailDeSerializer>(json, FedExShipper.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this JsonEmailDeSerializer self) => JsonConvert.SerializeObject(self, FedExShipper.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
Common approach to deserializing json with dynamic property names is to use Dictionary<string, ...>, in this case - Dictionary<string, List<MailCom>> can be used for Records property:
public partial class Result
{
[JsonProperty("records")]
public Dictionary<string, List<MailCom>> Records { get; set; }
[JsonProperty("errors")]
public List<Error> Errors { get; set; }
}
Json.NET can treat json object properties as keys for dictionary which makes it suitable to deserialize such dynamic data. The same is true for System.Text.Json.
That will never serialize to a class properly.
You'll have to use a lower-level API like Utf8JsonReader to read that level in the document, at least.

Convert IEnumerable<object> results to List<Account>

I have a salesforce rest service which returns results in IEnumerable format. Below is a sample results.
[{
"attributes": {
"type": "Account",
"url": "/services/data/v28.0/sobjects/Account/001i0000WK5xYAAT"
},
"RecordType": {
"attributes": {
"type": "RecordType",
"url": "/services/data/v28.0/sobjects/RecordType/012i00000x7FwAAI"
},
"Name": "Health Care Practitioners"
},
"Name": "JOSEPH SANDERS",
"Status_ims__c": "Verified",
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v28.0/sobjects/Account/001i000000WK5xYAAT"
},
"RecordType": {
"attributes": {
"type": "RecordType",
"url": "/services/data/v28.0/sobjects/RecordType/012i0000000x7FwAAI"
},
"Name": "Health Care Practitioners"
},
"Name": "DONALD GRABER",
"Status_ims__c": "Verified",
}]
public class Account
{
public string Name { get{ return GetOption ("Name");} }
public string Status_ims__c { get{ return GetOption ("Status_ims__c");}}
public Attributes attributes {get;}
public RecordType recordType {get;}
}
public class Attributes
{
public string type { get; set; }
public string url { get; set; }
}
public class Attributes2
{
public string type { get; set; }
public string url { get; set; }
}
public class RecordType
{
public Attributes2 attributes { get; set; }
public string Name { get; set; }
}
Above is the structure I have for Account Object. How to convert results to List and map to each property on Account object.
For Example is using json.net ->
var account = JsonConvert.DeserializeObject<List<Account>>(stringData);
Also if there are some differences between the object and the data you can use JsonProperty Annotations
Therefore you could also have more readable properties in your class model like
[JsonProperty("Status_ims__c ")]
public string Status
You can simple use this:
var accounts = JsonConvert.DeserializeObject<List<Account>>("your json string...");
If you use Newtonsoft.Json you can use Newtonsoft.Json.JsonConvert.DeserializeObject method.
Also make sure that your properties have setters in Account class.

Parse json string to object with linq

In my application I want to show a folder and its containing bookmarks. I try to achieve something like this:
folder Wikipedia
url a
url b
url ...
folder StackOverflow
url a
url b
Therefore I have to parse the following json string:
{
"checksum": "7d7205349eb64a4894aafc5ce074c0c0",
"roots": {
"bookmark_bar": {
"children": [ {
"children": [ {
"date_added": "13021579661026871",
"id": "28",
"name": "design patterns - Do you allow the Web Tier to access the DAL directly? - Stack Overflow",
"type": "url",
"url": "http://stackoverflow.com/questions/796656/do-you-allow-the-web-tier-to-access-the-dal-directly"
}, {
"date_added": "13021665700468056",
"id": "31",
"name": "VS 2010 Error when creating or opening projects - Stack Overflow",
"type": "url",
"url": "http://stackoverflow.com/questions/8403853/vs-2010-error-when-creating-or-opening-projects"
} ],
"date_added": "13021579680308871",
"date_modified": "13024947520078515",
"id": "29",
"name": "StackOverflow",
"type": "folder"
}, {
"children": [ {
"date_added": "13022096980978880",
"id": "45",
"name": "Dependency injection - Wikipedia, the free encyclopedia",
"type": "url",
"url": "http://en.wikipedia.org/wiki/Dependency_injection"
}, {
"date_added": "13024941326636844",
"id": "124",
"name": "Strategy pattern - Wikipedia, the free encyclopedia",
"type": "url",
"url": "http://en.wikipedia.org/wiki/Strategy_pattern"
} ],
"date_added": "13023315356559470",
"date_modified": "13024946156966435",
"id": "72",
"name": "Wiki",
"type": "folder"
}, {
"children": [ {
"date_added": "13023667785042757",
"id": "85",
"name": "Anemic Domain Model Illustrated | Frequent incoherent cogitation",
"type": "url",
"url": "http://vitamic.wordpress.com/2007/01/04/anemic-domain-model-illustrated/"
} ],
"date_added": "13023667668403520",
"date_modified": "13023668043391377",
"id": "82",
"name": "#Read",
"type": "folder"
}, {
"date_added": "13025102943539897",
"id": "130",
"name": "Modern UI for WPF - Home",
"type": "url",
"url": "http://mui.codeplex.com/wikipage?title=screenshots&referringTitle=Home"
} ],
"date_added": "13020681767991841",
"date_modified": "13025102947408897",
"id": "1",
"name": "Lesezeichenleiste",
"type": "folder"
}
},
"version": 1
}
I have tried the GroupBy Function, like this without success:
var items = jObject.Descendants()
.Where(x => x.Type == JTokenType.Object &&
x.Value<string>("type") != null)
.GroupBy(x => x.Value<string>("type"));
foreach (var item in items)
{
Console.WriteLine(item.Key.ToString());
foreach (var children in item)
{
Console.WriteLine(" " + children.Value<string>("name"));
}
}
I have also tried do apply the Join Function but I am missing a join property here. Can someone point me in the right direction please?
I would parse that json using concrete classes.
var root = JsonConvert.DeserializeObject<RootObj>(json);
Print(root.roots.bookmark_bar,"");
 
void Print(Node n,string padding)
{
Console.WriteLine(padding + "+" + n.name);
foreach(var url in n.children.Where(c => c.type == "url"))
{
Console.WriteLine(padding + "\t-" + url.name);
}
foreach (var folder in n.children.Where(c => c.type == "folder"))
{
Print(folder, padding + "\t");
}
}
 
public class Node
{
public string date_added { get; set; }
public string date_modified { get; set; }
public string id { get; set; }
public string name { get; set; }
public string type { get; set; }
public string url { get; set; }
public List<Node> children { get; set; }
}
public class Roots
{
public Node bookmark_bar { get; set; }
}
public class RootObj
{
public string checksum { get; set; }
public Roots roots { get; set; }
public int version { get; set; }
}
Above code is enough to parse your json, but if you want *date_modified* and *date_added* fields as DateTime, you can implement a JsonConverter class
var root = JsonConvert.DeserializeObject<RootObj>(json, new DateTimeConverter());
 
class DateTimeConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return new DateTime(1970,1,1).Add(TimeSpan.FromTicks(long.Parse((string)reader.Value)));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Then your Node class will be
public class Node
{
public DateTime date_added { get; set; }
public DateTime date_modified { get; set; }
public string id { get; set; }
public string name { get; set; }
public string type { get; set; }
public string url { get; set; }
public List<Node> children { get; set; }
}

Categories

Resources