2016-06-25 8 views
0

Ich möchte ein JSON-Objekt zu einer benutzerdefinierten Klasse deserialisieren. Die Klasse könnte wie folgt aussehen:JSon.Net Deserialize benutzerdefinierte Klasse

public class CommunicationMessage { 

    public string Key { get; set; } 

    public string Value { get; set; } 

    public List<CommunicationMessage> Childs { get; set; } 
} 

Und die json ich wie folgt aussieht deserialisieren möchten:

{ 
"Skills": [{ 
    "Skill": [{ 
     "SkillID": "1", 
     "ParticipantID": "7", 
     "CanDo": "True" 
    }, { 
     "SkillID": "2", 
     "ParticipantID": "7", 
     "CanDo": "True" 
    }, { 
     "SkillID": "3", 
     "ParticipantID": "7", 
     "CanDo": "False" 
    }] 
}] 
} 

Und das ist der Code, den ich die json deserialisieren bin mit:

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

Ich erwarte, diese hirarchy zu erhalten:

Skills 
    Skill 
     SkillID:1 
     ParticipantID:7 
     CanDo:true 
    Skill 
     SkillID:2 
     ParticipantID:7 
     CanDo:true 
    Skill 
     SkillID:3 
     ParticipantID:7 
     CanDo:false 

Aber ich bin immer dies:

Skills 
    Skill 
     SkillID:1 
     ParticipantID:7 
     CanDo: 
     SkillID:2 
     ParticipantID:7 
     CanDo:true 
     SkillID:3 
     ParticipantID:7 
     CanDo:false 

Ich kann die Linien finden, wo mein Versagen ist, vielleicht kann mir jemand hier helfen.

Danke !!

Antwort

1

Ihr Code scheint seinen Job ziemlich gut zu erledigen (obwohl es einfachere Wege gibt, Ihr Ziel zu erreichen). Der problematische Teil ist das JSON selbst. Es ist in zwei Arrays organisiert.

Ihr Code löscht das Skills -array (das ein Element enthält) und das Skill -array, das die tatsächlichen 3 Fähigkeiten enthält, die Sie erwarten.

{ 
    "Skills": [{  // array -> note the [ 
     "Skill": [{  // array -> note the [ 

daher eine Möglichkeit, dies zu lösen wäre, die JSON zu bearbeiten (falls dies möglich ist):

{ 
    "Skills": [{ 
     "SkillID": "1", 
     "ParticipantID": "7", 
     "CanDo": "True" 
    }, { 
     "SkillID": "2", 
     "ParticipantID": "7", 
     "CanDo": "True" 
    }, { 
     "SkillID": "3", 
     "ParticipantID": "7", 
     "CanDo": "False" 
    }] 
} 
+0

Das ist leider nicht möglich. Normalerweise hätte ich gerne ein JSON-Objekt, das Elemente mit demselben Schlüssel enthält. Aber Json ist nicht allos. So las ich, dass ich meine Klasse zum json umwandeln konnte, das ich –

0

Verwendung Newtonsoft Json.NET.

output message = JsonConvert.DeserializeObject<CommunicationMessage>(json); 

(wo json ist die JSON-String.)

ich diese Seite verwendet - json2csharp - Klassen zu erstellen, die die JSON passen Sie auf dem Laufenden:

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

Die Klassennamen werden automatisch generiert. Es benennt immer das Wurzelobjekt RootObject. Aber Sie können es in CommunicationMessage ändern (ich tat.)

Wenn die Klasse unterschiedliche Eigenschaftsnamen haben soll, die nicht mit dem JSON übereinstimmen, können Sie das mit Attributen tun.

public class Skill2 
{ 
    [JsonProperty["Key"] 
    public string SkillID { get; set; } 
    [JsonProperty["Value"] 
    public string ParticipantID { get; set; } 
    public string CanDo { get; set; } 
} 
+0

bekannt gab, verwende ich Json.Net, aber ich muss einen kundenspezifischen Parser verwenden. Es gibt auch keine Möglichkeit, Klassen wie Ihre zu definieren. –

+0

Wenn der JSON nicht direkt zu den Klassen deserialisiert werden kann, die Sie verwenden möchten, können Sie diese einfach in die Klassen deserialisieren und dann eine zusätzliche Mapping - Funktion schreiben Klasse, die Sie verwenden möchten. –

0

ein DataContractJsonSerializer von System.Runtime.Serialization Verwendung würde die Deserialisierung leichter machen:

Stream data = File.OpenRead(@"data.json"); 
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(CommunicationMessage)); 
CommunicationMessage message = (CommunicationMessage)serializer.ReadObject(data); 

Aber Sie brauchen auch eine Klasse wie folgt:

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

oben haben Sie die Klasse SkillData, die hält die Daten jeder Fähigkeit. Also, wenn Sie das Array Skill nehmen, haben Sie die gewünschte Hierarchie.

0

Sie können einfach überprüfen, wenn Sie auf der richtigen Ebene/Objekttyp Logik innerhalb Ihrer rekursiven Methode verwenden.

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

Wäre eine Lösung, aber ich möchte es möglichst wiederverwendbar machen. Und ich möchte auch hier nicht über 50 Tasten hartcodieren –

+0

Welche Taste (n) ändern sich? Also "json ich möchte das deserialize sieht so aus ..." aber es ist nicht wirklich immer so strukturiert oder ?? – blins

+0

Dies war nur ein Beispiel. Im echten Leben gibt es keine klar definierte Hierarchie dieses Jsons. Manchmal kommen die Fähigkeiten so, manchmal sind sie 10-mal tiefer verschachtelt. –