2012-04-05 22 views
8

Quiero ser capaz de analizar una cadena a un objeto al que puedo acceder usando la notación de puntos, p. myobject.property, en lugar de la notación del arreglo, p. myobject ['propiedad']. La notación de matriz funciona bien. Esto es lo que tengo hasta ahora.Analizando JSON con Dart

tengo algo de XML:

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

que se convierte en el JSON:

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

tengo el siguiente código de Dardo:

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']}"); 

que producen la salida (deseada) :

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 

Pero cuando intento:

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

me sale el siguiente:

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 

Idealmente, quiero un objeto que pueda acceder utilizando la notación de punto y sin el compilador dando advertencia sobre Objeto no tener propiedad. He intentado lo siguiente:

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

pero en vez de darme 'level1name' como se esperaba, me sale:

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

¿qué estoy haciendo mal aquí? ¿Hay alguna manera de hacer lo que estoy intentando? Gracias.

+0

Esto es algo aparte; deberías poder convertir de un objeto a javascript y de javascript a JSON. – will

Respuesta

12

Por el momento, JSON.parse solo devuelve listas (matriz), Maps, String, num, bool y null (api ref).

Sospecho que hasta que el reflejo llegue al lenguaje, no podrá volver a construir los objetos en función de las claves que se encuentran en json.

Podría, sin embargo, crear un constructor en su MyJsonObject que tomara una cadena, llamada JSON.parse internamente, y le asignara los diversos valores.

Algo como esto funciona en el editor de dardos:

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

} 

Una versión no trivial haría necesita algunos bucles y recursividad posible si tenía niveles más profundamente anidados.

Actualización: He hackeado una versión no trivial (inspirado en el post de abajo), es up on github (teniendo también los comentarios de Seth re el constructor):

+0

Es una pena la limitación del idioma.Sin embargo, esa fue una respuesta excelente. Exactamente lo que estaba buscando. Gracias Chris :) –

+0

Podría sugerir el uso de un constructor con nombre, algo así como MyJSONObject.fromJson (jsonString) o similar. Esto crea una intención más obvia para el constructor. –

4

Chris es completamente correcto. Solo agregaré que el analizador JSON podría modificarse para devolver un objeto un poco más rico (algo así como JsonMap en lugar de puro Map) que podría permitir jsonObj.property implementando noSuchMethod. Eso obviamente tendría un rendimiento peor que jsonObj['property'].

+1

Inspirado por este comentario, he tenido un hack en eso, y ahora está en github: http://github.com/chrisbu/dartwatch-JsonObject –