2014-05-14 16 views
6

Dies ist ein Beispiel für die JSON-Datei:Wie ein dynamisch namens Wurzelknoten mit json.NET deserialisieren

{ 
   "John Smith": { 
      "id": "72389", 
      "email": "[email protected]", 
      "books": [ 
         { 
            "id": "0", 
            "title": "The Hunger Games", 
            "rating": "5" 
         }, 
         { 
            "id": "1", 
            "title": "Harry Potter and the Order of the Phoenix", 
            "rating": "3" 
         }, 
      ], 
      "magazines": [ 
         { 
            "id": "2", 
            "title": "National Geographic", 
            "rating": "1" 
         }, 
         { 
            "id": "3", 
            "title": "Wired", 
            "rating": "4" 
         } 
      ], 
   } 
} 

Beachten Sie den Wurzelknoten einen dynamischen Namen (John Smith) hat, und jedes json Ich muss deserialize wird einen anderen Namen haben. Diese json Struktur erfordern würde Klassen-Setup haben, wie folgt:

public class RootObject 
{ 
    public JohnSmith { get; set; } 
} 

public class JohnSmith //oops 
{ 
    public string id { get; set; } 
    public string email { get; set; } 
    public List<Book> books { get; set; } 
    public List<Magazine> magazines { get; set; } 
} 

public class Book 
{ 
    public string id { get; set; } 
    public string title { get; set; } 
    public string rating { get; set; } 
} 

public class Magazine 
{ 
    public string id { get; set; } 
    public string title { get; set; } 
    public string rating { get; set; } 
} 

Mein Ziel ist es „Umgehen/ignorieren“ root Objekt deserialisieren und was am wichtigsten ist, dass dynamicaly namens Knoten. Das ist nicht entscheidend, aber ich möchte den Nachnamen erhalten und als Eigenschaft der Person-Klasse festlegen können.

public class Person 
{ 
    public string id { get; set; } 
    public string email { get; set; } 
    public string name { get; set; } 
    public List<Book> books { get; set; } 
    public List<Magazine> magazines { get; set; } 
} 

public class Book 
{ 
    public string id { get; set; } 
    public string title { get; set; } 
    public string rating { get; set; } 
} 

public class Magazine 
{ 
    public string id { get; set; } 
    public string title { get; set; } 
    public string rating { get; set; } 
} 

Hier ist, wie ich das jetzt tue:

var jo = JObject.Parse(json); 
var deserializable = jo.First.First.ToString(); 

string name; 
var jp = (JProperty)jo.First; 
if (jp != null) name = jp.Name; 

var person = JsonConvert.DeserializeObject<Person>(deserializable); 
person.name = name; 

Dies funktioniert OK, aber ich habe mich gefragt, vielleicht könnte es mithilfe einer benutzerdefinierten JsonConverter besser gemacht werden? Ich fürchte, das ist ein bisschen über meinem Kopf, also frage ich hier nach etwas Hilfe ...

Wie auch immer, wenn es einen besseren Weg gibt, dies zu erreichen, bitte teilen.

Antwort

8

Ich würde den ersten Teil Ihrer Lösung behalten (deserializing zu JObject), aber ich würde nicht eine andere Serialisierung tun. Mein Code würde wie folgt aussehen:

var jo = JObject.Parse(json); 
var jp = jo.Properties().First(); 
var name = jp.Name; 
var person = jp.Value.ToObject<Person>(); 

Edit:

Falls Sie einen benutzerdefinierten Konverter möchten, können Sie den folgenden Code verwenden. Der Konverter konvertiert Ihr Objekt in eine Liste von Person s, wobei jede Eigenschaft eine andere Person darstellt.

class PersonListConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var list = (PersonList) value; 

     writer.WriteStartObject(); 

     foreach (var p in list.Persons) 
     { 
      writer.WritePropertyName(p.Name); 
      serializer.Serialize(writer, p); 
     } 

     writer.WriteEndObject(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var jo = serializer.Deserialize<JObject>(reader); 
     var result = new PersonList(); 
     result.Persons = new List<Person>(); 

     foreach (var prop in jo.Properties()) 
     { 
      var p = prop.Value.ToObject<Person>(); 
      // set name from property name 
      p.Name = prop.Name; 
      result.Persons.Add(p); 
     } 

     return result; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(PersonList); 
    } 
} 

Wo PersonList würde wie folgt aussehen:

[JsonConverter(typeof(PersonListConverter))] 
class PersonList 
{ 
    public List<Person> Persons { get; set; } 
} 
+0

+1 Ich mag Ihre Antwort besser als meine. – codenheim

+0

Wie kann ich den Namen der Haupteigenschaft erhalten? –

+0

@RoyiNamir Ich bin mir nicht sicher, was du wissen willst. Sie möchten den Namen welcher Eigenschaft genau bekommen? Das JSON-Beispiel von cryodream hat nur eine Person (= eine Eigenschaft im Hauptobjekt). Mein Code iteriert alle Eigenschaften des Hauptobjekts. Aber mit dem Beispiel JSON gibt es natürlich nur eine Iteration. Also in meinem Code gibt es keine _main property_. Alle Eigenschaften des Wurzelobjekts werden gleich behandelt (in den foreach-Schleifen). – fero

0

Ich würde versuchen, eine Regex auf die rohe JSON zuerst, extrahieren Sie den Namen, regex ersetzen Sie es mit einem festen Knoten-Namen, dann deserialize auf das modifizierte Ergebnis mit dem Stammknoten, den Sie jetzt wissen, ist da.

Verwandte Themen