Reputation: 2844
I want to deserialize a json object to a custom class. The class could look like this:
public class CommunicationMessage {
public string Key { get; set; }
public string Value { get; set; }
public List<CommunicationMessage> Childs { get; set; }
}
And the json I want to deserialize looks like this:
{
"Skills": [{
"Skill": [{
"SkillID": "1",
"ParticipantID": "7",
"CanDo": "True"
}, {
"SkillID": "2",
"ParticipantID": "7",
"CanDo": "True"
}, {
"SkillID": "3",
"ParticipantID": "7",
"CanDo": "False"
}]
}]
}
And this is the code I am using to deserialize the json:
private void ReadRecursive(JToken token, ref CommunicationMessage root) {
if (token is JProperty) {
CommunicationMessage msg = new CommunicationMessage();
if (token.First is JValue) {
msg.Key = ((JProperty)token).Name;
msg.Value = (string)((JProperty)token).Value;
} else {
msg.Key = ((JProperty)token).Name;
foreach (JToken child in token.Children()) {
ReadRecursive(child, ref msg);
}
}
root.Childs.Add(msg);
} else {
foreach (JToken child in token.Children()) {
ReadRecursive(child, ref root);
}
}
}
I am expecting to get this hirarchy:
Skills
Skill
SkillID:1
ParticipantID:7
CanDo:true
Skill
SkillID:2
ParticipantID:7
CanDo:true
Skill
SkillID:3
ParticipantID:7
CanDo:false
But I am getting this:
Skills
Skill
SkillID:1
ParticipantID:7
CanDo:
SkillID:2
ParticipantID:7
CanDo:true
SkillID:3
ParticipantID:7
CanDo:false
I can't find the lines where my failure is, so maybe anyone can help me here.
Thanks!!
Upvotes: 0
Views: 230
Reputation: 2535
You could just check for when you are at the right level/object type using logic inside your recursive method.
void ReadRecursive(JToken token, ref CommunicationMessage root)
{
var p = token as JProperty;
if (p != null && p.Name == "Skill")
{
foreach (JArray child in p.Children())
{
foreach (JObject skill in child.Children())
{
// Create/add a Skill message instance for current Skill (JObject)
var skillMsg = new CommunicationMessage { Key = p.Name };
// Populate Childs for current skill instance
skillMsg.Childs = new List<CommunicationMessage>();
foreach (JProperty skillProp in skill.Children())
{
skillMsg.Childs.Add(new CommunicationMessage
{
Key = skillProp.Name,
Value = (string)skillProp.Value
});
}
root.Childs.Add(skillMsg);
}
}
}
// Recurse
foreach (JToken child in token.Children())
ReadRecursive(child, ref root);
}
Upvotes: 0
Reputation: 94
Using a DataContractJsonSerializer
from System.Runtime.Serialization
would make the deserialization easier:
Stream data = File.OpenRead(@"data.json");
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(CommunicationMessage));
CommunicationMessage message = (CommunicationMessage)serializer.ReadObject(data);
But you also need a class like this:
[DataContract]
class CommunicationMessage
{
[DataContract]
class SkillsData
{
[DataContract]
internal class SkillData
{
[DataMember(Name = "SkillID")]
internal object SkillID;
[DataMember(Name = "ParticipantID")]
internal object ParticipantID;
[DataMember(Name = "CanDo")]
internal object CanDo;
}
[DataMember(Name = "Skill")]
internal SkillData[] Skill;
}
[DataMember(Name = "Skills")]
SkillsData[] Skills;
}
Above you have the class SkillData
, which holds the data of each skill. So if you take the array Skill
, you have the wanted hirarchy.
Upvotes: 0
Reputation: 29282
Use Newtonsoft Json.NET.
output message = JsonConvert.DeserializeObject<CommunicationMessage>(json);
(where json
is the JSON string.)
I used this page - json2csharp - to create classes that match the JSON you posted:
public class Skill2
{
public string SkillID { get; set; }
public string ParticipantID { get; set; }
public string CanDo { get; set; }
}
public class Skill
{
public List<Skill2> Skill { get; set; }
}
public class CommunicationMessage
{
public List<Skill> Skills { get; set; }
}
The class names are autogenerated. It always names the root object RootObject
. But you can change it to CommunicationMessage
(I did.)
If you want the class to have different property names that don't match the JSON you can do that with attributes.
public class Skill2
{
[JsonProperty["Key"]
public string SkillID { get; set; }
[JsonProperty["Value"]
public string ParticipantID { get; set; }
public string CanDo { get; set; }
}
Upvotes: 0
Reputation: 6030
Your code seems to do its job quite ok (although there are simpler ways to achieve your goal). The problematic part is the JSON it self. It's organized in two arrays.
So your code puts out the Skills
-array (which has one element) and the Skill
-array which holds the actual the 3 skills you're expecting.
{
"Skills": [{ // array -> note the [
"Skill": [{ // array -> note the [
Hence one way to solve this would be to edit the JSON (if this is possible):
{
"Skills": [{
"SkillID": "1",
"ParticipantID": "7",
"CanDo": "True"
}, {
"SkillID": "2",
"ParticipantID": "7",
"CanDo": "True"
}, {
"SkillID": "3",
"ParticipantID": "7",
"CanDo": "False"
}]
}
Upvotes: 1