My problem in short: I need to deserialize two big JSON strings to one class, but strings are little different. Here is the first one:
{
"persons": [
{
"age":30,
"name":"david",
"hobbies": [
{
"name":"tennis",
"hours":5
},
{
"name":"football",
"hours":10
}
]
},
{
"name":"adam",
"age":23,
"hobbies":[]
}
]
}
and the other one:
{
"person": [
{
"age":25,
"name":"dave",
"hobbies":[
{
"name":"Basketball",
"hours":5
},
{
"name":"football",
"hours":10
}
]
},
{
"name":"Steve",
"age":28,
"hobbies": []
}
]
}
You can see that one time it's "Persons", and the other time it's "Person". Is there any simple solution to this? I was thinking about creating two lists in my class
List<Person> person;
List<Person> persons;
and after deserialization combine then manually somehow. But there must be a simplier way.
By the way, this is not the exact code I need to deserialize. I just wanted to keep the main idea as simple as possible.
One simple solution is to use a single list in your class, but then add an alternate setter with the other name which references the same list. You can even make it private as long as you decorate it with a [JsonProperty]
attribute. That way the public interface of your class will look normal, but it will still work with both JSON property names.
public class RootObject
{
[JsonProperty("persons")]
public List<Person> People { get; set; }
// This is visible to Json.Net and references the real list
[JsonProperty("person")]
private List<Person> Person
{
set { People = value; }
}
}
public class Person
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("age")]
public int Age { get; set; }
[JsonProperty("hobbies")]
public List<Hobby> Hobbies { get; set; }
}
public class Hobby
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("hours")]
public int Hours { get; set; }
}
Fiddle: https://dotnetfiddle.net/9Dw48J
EDIT
To address your comments: PopulateObject
can be used to blindly augment an existing object with data from JSON, but it will not do the kind of merging you are looking for. It seems you are looking for a way to match people by name (and maybe age?) and then combine the hobbies for those people. For that you will need to write your own logic. I would suggest deserializing each list into separate instances of your RootObject
class, then merging the data in a post-processing step. You can make a method on the RootObject
class which will accept another RootObject
to merge. Perhaps something like this:
public class RootObject
{
...
public void MergeWith(RootObject other)
{
if (other.People == null) return;
if (People == null) People = new List<Person>();
foreach (Person person in other.People)
{
// You may need to make changes here--
// How do you determine whether two people are the same?
Person existingPerson = People.FirstOrDefault(p => p.Name == person.Name &&
p.Age == person.Age);
if (existingPerson != null)
{
existingPerson.MergeWith(person);
}
else
{
People.Add(person);
}
}
}
}
And on the Person
class...
public class Person
{
...
public void MergeWith(Person other)
{
if (other.Hobbies == null) return;
if (Hobbies == null) Hobbies = new List<Hobby>();
foreach (Hobby hobby in other.Hobbies)
{
Hobby existingHobby = Hobbies.FirstOrDefault(h => h.Name == hobby.Name);
if (existingHobby != null)
{
// You may need to make changes here--
// What do you do if two hobbies have the same name but different hours?
existingHobby.Hours += hobby.Hours;
}
else
{
Hobbies.Add(hobby);
}
}
}
}
To deserialize and merge you would then do:
var firstObj = JsonConvert.DeserializeObject<RootObject>(firstJson);
var secondObj = JsonConvert.DeserializeObject<RootObject>(secondJson);
firstObj.MergeWith(secondObj);
Fiddle: https://dotnetfiddle.net/8Fiwsd
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