2014-09-04 5 views
5

Ich brauche json so deserialisieren (es ist wie in DICOM definiert - einem internationalen Standard, also kann ich nicht das Format ändern!Wie kann ich einen Objekttyp auswählen Json.Net deserialisieren in den Daten basierend auf Eigenschaftswerte

)
{ 
.... 
"00080060": { 
    "Value": [ 
    "US" 
    ], 
    "vr": "CS" 
}, 
"00080070": { 
    "Value": [ 
    "ACME Products" 
    ], 
    "vr": "LO" 
}, 
"00080090": { 
    "Value": [ 
    { 
     "AlphabeticName": "Better^Make^U.^MD" 
    } 
    ], 
    "vr": "PN" 
}, 
"00081110": { 
    "Value": [ 
    { 
     "00080008": { 
     "Value": [ 
      "XX_0", 
      "OIU", 
      null, 
      "PPP" 
     ], 
     "vr": "CS" 
     } 
    }, 
    {}, 
    { 
     "00080008": { 
     "Value": [ 
      "XX_2", 
      "OIU", 
      null, 
      "PPP" 
     ], 
     "vr": "CS" 
     } 
    } 
    ], 
    "vr": "SQ" 
}, 

Jede Eigenschaft (in einer langen Liste!) hat einen Namen (0008XXXX in obigem Beispiel), und Untereigenschaften "vr" und Wert hat. In den meisten Fällen ist Value einfach ein Array von Objekten (String oder Zahl) und das ist in Ordnung, aber für 2 Spezialfälle (PN und SQ wie oben) benötigt es spezielle Behandlung, und im Falle von SQ ist es tatsächlich ein Array von Top-Level-Objekt wieder (die verschachtelt ad infinitum verschachtelt werden können ...)

Also - was ich brauche, ist eine einfache Methode, während der Deserialisierung den Wert "vr" zu überprüfen und json.net geben den Typ, den es verwenden soll für den damit verbundenen "Wert" - gibt es ein einfaches Mittel, das zu tun? Natürlich, dass die Tatsache, vr vor oder nach dem Wert kommen könnte (abhängig von der Remote-Implementierung) könnte die Dinge weiter komplizieren ...

I ContractResolver und JsonConverter die bei json.net Mechanismen hat gesucht, aber ContractResolver scheint mir nicht zu geben Zugriff auf die gelesenen Daten, um die Auswahl zu ermöglichen, und von JsonConverter abgeleitete Klassen würden mich dazu bringen, das meiste von dem, was json.net dong (sonst so gut!) ist, für mich schon wieder umzusetzen :-(

bin ich hier einige offensichtliche und einfache Lösung fehlt?

+0

'JObject' ist das, was Sie brauchen. Leider habe ich nicht genug Zeit, um das Parsen damit zu erzwingen. –

Antwort

5

Ugh, das ist ein schwieriges Format zu arbeiten. Allerdings sollte es möglich sein, einen Sinn machen mit einem benutzerdefinierten JsonConverter. Die Verwendung eines JObject im Inneren des Konverters schützt uns vor den meisten schweren Lasten. Aber zuerst müssen wir einige Klassen definieren, um die Daten zu deserialisieren.

Die erste Klasse I Node nennen würde; Dies wird die Value Liste und vr enthalten.

class Node 
{ 
    public IList Value { get; set; } 
    public string vr { get; set; } 
} 

Die zweite Klasse ist zum Halten der Gegenstände für den „PN“ Fall benötigt.

class PnItem 
{ 
    public string AlphabeticName { get; set; } 
} 

Hier ist der Code für den Konverter. Der Konverter kann die vr Eigenschaft anzeigen und diese Information verwenden, um den richtigen Listentyp für die Value zu erstellen.

class NodeConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(Node)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject jo = JObject.Load(reader); 
     Node node = new Node(); 
     node.vr = (string)jo["vr"]; 
     if (node.vr == "PN") 
     { 
      node.Value = jo["Value"].ToObject<List<PnItem>>(serializer); 
     } 
     else if (node.vr == "SQ") 
     { 
      node.Value = jo["Value"].ToObject<List<Dictionary<string, Node>>>(serializer); 
     } 
     else 
     { 
      node.Value = jo["Value"].ToObject<List<string>>(serializer); 
     } 
     return node; 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Beachten Sie, dass für die "SQ" Fall, dass wir eine List<Dictionary<string, Node>> sind Deserialisieren. Dies deckt die rekursive Struktur ab. Immer wenn Json.Net versucht einen Knoten zu deserialisieren, wird er zurück in den Konverter gerufen. Wir verwenden eine Dictionary, um die Tatsache zu behandeln, dass die Eigenschaftsnamen variieren können (z. B. "00080070", "00080090" usw.). An der Wurzel müssen wir aus dem gleichen Grund auch zu einem Dictionary<string, Node> deserialize.

Also, alles zusammen zu binden, ist hier, wie Sie Ihre JSON deserialisieren würde:

var dict = JsonConvert.DeserializeObject<Dictionary<string, Node>>(json, 
                  new NodeConverter()); 

Hier ist eine Demo: https://dotnetfiddle.net/hsFlxU

+1

Absolut genial - genau das, was ich brauchte! Ich musste etwas modifizieren, um einige der anderen Merkwürdigkeiten zu berücksichtigen, die ich aus Gründen der Klarheit weggelassen hatte (z.Das ganze Ding ist ein JSON-Array), so dass wir am Ende das gleiche Doppel-Level-Generikum für Top-Level sowie – medconn

+0

Ich hatte das Gefühl, dass wahrscheinlich noch ein paar Details ungesagt waren! Ich bin froh, dass Sie diese Lösung an Ihre Bedürfnisse anpassen konnten. –

Verwandte Themen