简体   繁体   中英

JSon.Net deserialize custom class

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

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"
    }]
}

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

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM