0

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!!

4 Answers 4

1

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"
    }]
}
Sign up to request clarification or add additional context in comments.

1 Comment

Unfortunately this is not possible. Normally I would like to have a json object which holds elements with the same key. But json does't allos this. So I read that i could convert my class to the json I posted
0

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; }
}

2 Comments

I do use Json.Net but i must use a custom parser. Also there is no way to define classes like yours
If the JSON can't be directly deserialized to the classes you want to use then you could just deserialize them into the classes like above and then write some additional mapping function to convert them to the class you want to use.
0

Using a DataContractJsonSerializerfrom System.Runtime.Serializationwould 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.

Comments

0

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);
}

4 Comments

Would be a solution, but I want it as most reusable as possible. And also I don't want to hardcode abaout 50 keys right here
What key(s) change? So "json I want to deserialize looks like this..." but it is not really always structured that way or??
This was just an example. In real live, there is no hard defined hirarchy of this json. Sometimes the skills come like this, sometimes they are nested 10 times deeper
Skill can be nested deeper or Skills? It would be nice if you add a second json example to your question so we have a precise idea of how it can vary if you would like better abstraction in a solution.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.