jsontree
静态类型的JSON树。
该树只能包含JSON兼容的原子类型,而不能包含其他任何内容。也就是说,只有String、int、double、bool或null — 通过嵌套的Map或List对象组合而成。
这允许您在非常早期阶段预防数据错误。您将看到IDE的警告,并且程序将无法编译。
示例
以声明式风格创建树
import 'package:jsontree/jsontree.dart';
void main() {
final tree = {
"planet": "Mars".jsonNode,
"diameter": 6779.jsonNode,
"satellites": ["Phobos".jsonNode, "Deimos".jsonNode].jsonNode
}.jsonNode;
print(tree.toJsonCode());
// {"planet":"Mars","diameter":6779,"satellites":["Phobos","Deimos"]}
}
或者以命令式风格创建树
import 'package:jsontree/jsontree.dart';
void main() {
final satellites = MutableJsonList.empty();
satellites.data.add("Phobos".jsonNode);
satellites.data.add("Deimos".jsonNode);
final tree = MutableJsonMap.empty();
tree.data["planet"] = "Mars".jsonNode;
tree.data["diameter"] = 6779.jsonNode;
tree.data["satellites"] = satellites;
print(tree.toJsonCode());
// {"planet":"Mars","diameter":6779,"satellites":["Phobos","Deimos"]}
}
动机
设想我们需要创建一个JSON request,稍后它将被转换为JSON并发送到服务器。
错误:动态类型
import 'dart:convert';
main() {
final request = <String, dynamic>{}; // to be converted to JSON
// DateTime is not convertible, but we don't know that yet
request["time"] = DateTime.now(); // oops
request["message"] = "Hi!";
// runtime exception: DateTime cannot be converted
send(json.convert(request));
}
正确:静态类型
import 'dart:convert';
import 'package:jsontree/jsontree.dart';
respond() {
final request = MutableJsonMap(); // no dynamic types
// to place an object inside MutableJsonMap we are forced to convert each
// parameter to a JsonNode. But there's no way to convert DateTime to it,
// so we have to do it right
request["time"] = DateTime.now().millisecondsSinceEpoch.jsonNode;
request["message"] = "Hi!".jsonNode;
// no errors, as it should be
send(json.convert(request));
}
JsonNode树的创建
x.jsonNode会创建一个包装x值的对象。该对象取决于x的类型。
例如,5.jsonNode会创建JsonInt(5)。而5.23.jsonNode会创建JsonDouble(5.23)。
这同样适用于集合。
final sheldon = {
'name': 'Sheldon'.jsonNode,
'surname': 'Cooper'.jsonNode,
'iq': 187.jsonNode,
'girlfriends': 1.jsonNode
}.jsonNode;
// you can't add .jsonNode to the map if you miss at least
// one .jsonNode added to elements
final leonard = {
'name': 'Leonard'.jsonNode,
'surname': 'Hofstadter'.jsonNode,
'iq': 173.jsonNode,
'girlfriends': 4.jsonNode
}.jsonNode;
// connect these nodes into an even larger structure
final tree = {
'science': 'physics'.jsonNode,
'neighbours': [leonard, sheldon].jsonNode
}.jsonNode;
无论类型如何,所有包装器对象都将继承自基类JsonNode。如果您已经创建了一个JsonNode,您可以确信其中包含JSON兼容的数据。
JsonNode树转换为JSON字符串
对于任何JsonNode对象,您都可以调用.toJsonCode()方法将其转换为JSON字符串。
import 'package:jsontree/jsontree.dart';
...
final tree = [1.jsonNode, 2.jsonNode].jsonNode;
print(tree.toJsonCode());
您也可以将树直接传递给json.convert
import 'package:jsontree/jsontree.dart';
import 'dart:convert';
...
final tree = [1.jsonNode, 2.jsonNode].jsonNode;
print(json.convert(tree));
JSON字符串转换为JsonNode树
使用此库解析JSON只有在您想使用解析后的值来创建另一个树时才有意义。
final a = JsonNode.fromJsonCode(src1);
final b = JsonNode.fromJsonCode(src2);
print([a, b, "something else".jsonNode].jsonNode.toJsonCode())
JsonNode树转换为原始对象
您还可以调用JsonNode.unwrap()来移除所有包装器,并获得原始的Dart对象集合。因为这些对象在创建树时已经过验证,所以结果保证可以转换为JSON。
import 'package:jsontree/jsontree.dart';
import 'dart:convert'
...
JsonList tree = [1.jsonNode, 2.jsonNode].jsonNode;
List<int> list = tree.unwrap(); // [1, 2]
// of course, the list convertible to JSON
print(json.convert(dartList));
对象转换为JsonNode树
这种转换违背了该库的宗旨。它需要动态类型检查,并可能导致运行时错误。
但是,如果您已经准备好了数据结构,这可能是一个合理的折衷。
final leonard = {
'name': 'Leonard',
'surname': 'Hofstadter',
'iq': 173,
};
JsonNode tree = JsonNode.wrap(leonard);
JsonNodes的不可变性
默认情况下,所有对象都是不可变的。
JsonMap m = {"a": 1.jsonNode, "b": 2.jsonNode}.jsonNode;
// you can read m or m.data, but cannot change
列表和映射也有可变版本。
var m = MutableJsonMap({"a": 1.jsonNode, "b": 2.jsonNode});
// you can read/write m and m.data
可变性和不可变性可以在对象创建后实现。
JsonMap readOnly = {"a": 1.jsonNode, "b": 2.jsonNode}.jsonNode;
MutableJsonMap readWrite = readOnly.toMutable(); // creates a copy
readWrite["c"] = 3.jsonNode;
JsonMap readOnlyAgain = readWrite.asImmutable(); // wraps the data as immutable
toMutable将创建数据的副本,同时尊重原始对象的不可变性。
asImmutable将只是将数据包装在一个不允许修改的对象中。
层级结构
JsonAny
^^ JsonValue
^^ JsonInt
^^ JsonInt53 (JavaScript range)
^^ JsonInt64 (full int64 range)
^^ JsonDouble
^^ JsonString
^^ JsonList
^^ MutableJsonList
^^ JsonMap
^^ MutableJsonMap
^^ JsonNull
默认情况下,除了MutableJsonMap和MutableJsonList之外,所有对象都是不可变的。
整数范围
默认情况下,int.jsonNode会创建一个JsonInt53对象。它只允许您设置在JavaScript中不会丢失精度的整数值。
final a = 5.jsonNode; // no problem
final b = 9999999999999999.jsonNode; // throws ArgumentError
此限制很重要,因为JSON字面意思是JavaScript对象表示法。
但是大多数语言都能从JSON中读取更大的数字。要存储完整范围的数字,请使用int.jsonNode64。
final c = 9999999999999999.jsonNode64; // no problem
许可证
版权所有 © 2022 Artёm IG。根据MIT许可证发布。