使用Dart解析JSON

8
我希望能够将字符串解析为对象,以便使用点符号表示法(例如myobject.property)访问它,而不是数组表示法(例如myobject['property'])。数组表示法可以正常工作。这是我目前的代码。
我有一些XML:
<level1 name="level1name">
  <level2 type="level2Type">
    <entry>level2entry</entry>
    <entry>level2entry</entry>
  </level2>
</level1>

转换为JSON格式:

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

我有以下Dart代码:

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

生成(所需的)输出:

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

但是当我尝试时:

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

我得到以下内容:
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

理想情况下,我希望拥有一个对象,可以使用点符号访问,并且编译器不会警告“对象没有该属性”。我尝试了以下方法:

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

但是我没有得到我所希望的'level1name',而是得到了:

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

这里我做错了什么?有没有办法实现我的尝试?谢谢。

这有点离题了;你应该能够从一个对象转换为JavaScript,然后从JavaScript转换为JSON。 - will
2个回答

12

目前,JSON.parse仅返回列表(数组)、映射、字符串、数字、布尔值和null (API参考)。

我怀疑在反射进入语言之前,它将无法根据在json中找到的键来重建对象。

不过,您可以在MyJsonObject中创建一个构造函数,该构造函数接受一个字符串,内部调用JSON.parse,并分配各个值。

类似这样的代码在Dart编辑器中可行:

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

}

如果你有更深层次的嵌套,一个不太简单的版本需要一些循环和可能的递归。

更新:我已经通过一些技巧(受下面帖子的启发)设计出了一个不太简单的版本,它在 github上(同时接受 Seth 对构造函数的评论):


很遗憾有这种语言限制。不过,那是一个出色的答案。正是我在寻找的。谢谢 Chris :) - Phlox Midas
我建议使用命名构造函数,例如 MyJSONObject.fromJson(jsonString) 或类似的方式。这会为构造函数创建一个更明显的意图。 - Seth Ladd

4

Chris是完全正确的。我的补充是JSON解析器可以被修改以返回一个稍微丰富一点的对象(例如JsonMap而不是纯粹的Map),它可以通过实现noSuchMethod,使得jsonObj.property成为可能。这显然比jsonObj['property']性能差。


1
受这条评论的启发,我试着对此进行了一些修改,并将其上传到了Github上:http://github.com/chrisbu/dartwatch-JsonObject - Chris Buckett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接