2012-04-05 22 views
8

Ich möchte in der Lage sein, eine Zeichenfolge zu einem Objekt zu analysieren, auf das ich unter Verwendung der Punktnotation z. myobject.property, anstelle der Array-Notation z.B. Mein Objekt ['Eigenschaft']. Die Array-Notation funktioniert einwandfrei. Hier ist, was ich bisher habe.Parsen von JSON mit Dart

Ich habe einige XML:

<level1 name="level1name"> 
    <level2 type="level2Type"> 
    <entry>level2entry</entry> 
    <entry>level2entry</entry> 
    </level2> 
</level1> 

die zu der JSON konvertiert:

{ 
    "level1": { 
    "name": "level1name", 
    "level2": { 
     "type": "level2Type", 
     "entry": [ 
     "level2entry", 
     "level2entry" 
     ] 
    } 
    } 
} 

Ich habe folgenden Dart-Code:

Object jsonObject = JSON.parse("""{ 
     "level1": { 
     "name": "level1name", 
     "level2": { 
      "type": "level2Type", 
      "entry": [ 
      "level2entry", 
      "level2entry" 
      ] 
     } 
     } 
    } 
"""); 

    print("my test 1 == ${jsonObject}"); 
    print("my test 2 == ${jsonObject['level1']}"); 
    print("my test 3 == ${jsonObject['level1']['name']}"); 

die den (gewünschten) -Ausgang erzeugen, :

my test 1 == {level1: {name: level1name, level2: {type: level2Type, entry: [level2entry, level2entry]}}} 
my test 2 == {name: level1name, level2: {type: level2Type, entry: [level2entry, level2entry]}} 
my test 3 == level1name 

Aber wenn ich versuche:

print("my test 1 == ${jsonObject.level1}"); 

ich wie folgt zusammen:

Exception: NoSuchMethodException : method not found: 'get:level1' 
Receiver: {level1: {name: level1name, level2: {type: level2Type, entry: [level2entry, level2entry]}}} 
Arguments: [] 
Stack Trace: 0. Function: 'Object.noSuchMethod' url: 'bootstrap' line:717 col:3 

Idealerweise möchte ich ein Objekt, das ich auf die Punktnotation und ohne den Compiler Warnung über Objekt geben kein Eigentum. Ich habe versucht, die folgenden:

class MyJSONObject extends Object{ 
    Level1 _level1; 
    Level1 get level1() => _level1; 
    set level1(Level1 s) => _level1 = s; 
} 

class Level1 { 
    String _name; 
    String get name() => _name; 
    set name(String s) => _name = s; 
} 
... 
MyJSONObject jsonObject = JSON.parse("""{ 
     "level1": { 
     "name": "level1name", 
     "level2": { 
      "type": "level2Type", 
      "entry": [ 
      "level2entry", 
      "level2entry" 
      ] 
     } 
     } 
    } 
"""); 
... 
print("my test 1 == ${jsonObject.level1.name}"); 

sondern mir geben ‚level1name‘ wie erhofft, die ich erhalten:

Exception: type 'LinkedHashMapImplementation<String, Dynamic>' is not a subtype of type 'MyJSONObject' of 'jsonObject'. 

Was mache ich falsch hier? Gibt es eine Möglichkeit, das zu tun, was ich versuche? Vielen Dank.

+0

Dies ist eine Art von beiseite; Sie sollten in der Lage sein, von einem Objekt in Javascript und von JavaScript in JSON zu konvertieren. – will

Antwort

12

Momentan gibt JSON.parse nur Listen (Array), Maps, String, num, bool und null (api ref) zurück.

Ich vermute, dass, bis die Reflexion es in die Sprache schafft, es nicht in der Lage sein wird, Objekte basierend auf den in json gefundenen Schlüsseln neu zu konstruieren.

Sie könnten jedoch einen Konstruktor in Ihrem MyJsonObject erstellen, der intern eine Zeichenfolge namens JSON.parse verwendet und die verschiedenen Werte zugewiesen hat.

So etwas wie das funktioniert in der Dart Editor:

#import("dart:json"); 
class Level2 { 
    var type; 
    var entry; 
} 

class Level1 { 
    var name; 
    var level2;   
} 

class MyJSONObject { 
    Level1 level1; 


    MyJSONObject(jsonString) { 
    Map map = JSON.parse(jsonString); 

    this.level1 = new Level1(); 
    level1.name = map['level1']['name']; 
    level1.level2 = new Level2(); 
    level1.level2.type = map['level1']['level2']['type']; 
    //etc... 

    } 
} 

main() { 
    var obj = new MyJSONObject(json); 
    print(obj.level1.level2.type); 

} 

Eine nicht triviale Version benötigt würde einige Schleifen und mögliche Rekursion, wenn Sie tiefer verschachtelte Ebene haben.

Update: Ich habe gehackt zusammen, um eine nicht-triviale Version (durch den Beitrag unten inspiriert), dann ist es up on github (auch Seths Kommentare erneut den Konstruktor nehmen):

+0

Es ist eine Schande über diese Sprachbeschränkung.Das war jedoch eine hervorragende Antwort. Genau das, was ich gesucht habe. Danke Chris :) –

+0

Ich könnte vorschlagen, einen benannten Konstruktor, etwas wie MyJSONObject.fromJson (jsonString) oder ähnliches zu verwenden. Dies erzeugt eine offensichtlichere Absicht für den Konstruktor. –

4

Chris ganz richtig ist. Ich werde nur hinzufügen, dass der JSON-Parser geändert werden könnte, um ein wenig reicheres Objekt (etwas wie JsonMap anstelle von reinem Map), jsonObj.property durch die Implementierung noSuchMethod zu ermöglichen. Das würde offensichtlich schlechter funktionieren als jsonObj['property'].

+1

Inspiriert von diesem Kommentar hatte ich einen Hack, und es ist jetzt auf Github: http://github.com/chrisbu/dartwatch-JsonObject –