This is an example of the json file:
{
"John Smith": {
"id": "72389",
"email": "[email protected]",
"books": [
{
"id": "0",
"title": "The Hunger Games",
"rating": "5"
},
{
"id": "1",
"title": "Harry Potter and the Order of the Phoenix",
"rating": "3"
},
],
"magazines": [
{
"id": "2",
"title": "National Geographic",
"rating": "1"
},
{
"id": "3",
"title": "Wired",
"rating": "4"
}
],
}
}
Notice the root node has a dynamic name (John Smith), and every json I need to deserialize will have a different name. This json structure would require to have classes setup as follows:
public class RootObject
{
public JohnSmith { get; set; }
}
public class JohnSmith //oops
{
public string id { get; set; }
public string email { get; set; }
public List<Book> books { get; set; }
public List<Magazine> magazines { get; set; }
}
public class Book
{
public string id { get; set; }
public string title { get; set; }
public string rating { get; set; }
}
public class Magazine
{
public string id { get; set; }
public string title { get; set; }
public string rating { get; set; }
}
My goal is to deserialize "bypassing/ignoring" root object and most importantly that dynamicaly named node. This is not crucial, but I would like to be able to get the last name and set as a property on the Person class.
public class Person
{
public string id { get; set; }
public string email { get; set; }
public string name { get; set; }
public List<Book> books { get; set; }
public List<Magazine> magazines { get; set; }
}
public class Book
{
public string id { get; set; }
public string title { get; set; }
public string rating { get; set; }
}
public class Magazine
{
public string id { get; set; }
public string title { get; set; }
public string rating { get; set; }
}
Here is how I am doing this now:
var jo = JObject.Parse(json);
var deserializable = jo.First.First.ToString();
string name;
var jp = (JProperty)jo.First;
if (jp != null) name = jp.Name;
var person = JsonConvert.DeserializeObject<Person>(deserializable);
person.name = name;
This works OK, but I was wondering, maybe it could be done better by using a custom JsonConverter? I'm afraid this is a little bit over my head atm, so I am asking here for some help...
Anyway, if there is any better way to achieve this, please share.
I would keep the first part of your solution (deserializing to JObject
), but I wouldn't do another serialization. My code would look like this:
var jo = JObject.Parse(json);
var jp = jo.Properties().First();
var name = jp.Name;
var person = jp.Value.ToObject<Person>();
Edit:
In case you want a custom converter, you could use the following code. The converter converts your object to a list of Person
s where every property represents another Person
.
class PersonListConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var list = (PersonList) value;
writer.WriteStartObject();
foreach (var p in list.Persons)
{
writer.WritePropertyName(p.Name);
serializer.Serialize(writer, p);
}
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jo = serializer.Deserialize<JObject>(reader);
var result = new PersonList();
result.Persons = new List<Person>();
foreach (var prop in jo.Properties())
{
var p = prop.Value.ToObject<Person>();
// set name from property name
p.Name = prop.Name;
result.Persons.Add(p);
}
return result;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(PersonList);
}
}
Where PersonList
would look like this:
[JsonConverter(typeof(PersonListConverter))]
class PersonList
{
public List<Person> Persons { get; set; }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With