Sonic: Go语言的超级JSON库,解析与编码速度狂飙( 三 )


在很多编程语言的编译器或解释器实现中,抽象语法树中的每个元素(节点)都会有对应的数据结构表示,通常这些数据结构会被称为 ast.Node 或类似的名字 。每个 ast.Node 表示源代码中的一个语法结构,如表达式、语句、函数声明等 。
抽象语法树的节点可以包含以下信息:

  • 节点的类型:例如表达式、语句、函数调用等 。
  • 节点的内容:节点所代表的源代码的内容 。
  • 子节点:一些节点可能包含子节点,这些子节点也是抽象语法树的节点,用于构建更复杂的语法结构 。
  • 属性:一些节点可能会包含附加的属性,如变量名、操作符类型等 。
我们通过几个案例理解一下Ast.Node的使用 。
准备数据data := `{"name": "z3","info":{"num": [11,22,33]}}`将数据转换为Ast.Node通过传入bytes或者string返回一个Ast.Node 。其中你可以指定path获取JSON中的子路径元素 。
每个路径参数必须是整数或者字符串
  • 整数是目标索引(>=0),表示以数组形式搜索当前节点 。
  • 字符串为目标key,表示搜索当前节点为对象 。
// 函数签名:func Get(src []byte, path ...interface{}) (ast.Node, error) {return GetFromString(string(src), path...)}// GetFromString与Get相同,只是src是字符串,这样可以减少不必要的内存拷贝 。func GetFromString(src string, path ...interface{}) (ast.Node, error) {return ast.NewSearcher(src).GetByPath(path...)}获取当前节点的完整数据func base() { data := `{"name": "z3","info":{"num": [11,22,33]}}` // no path return all json string root, err := sonic.GetFromString(data) if err != nil {log.Panic(err) } if raw, err := root.Raw(); err != nil {log.Panic(err) } else {log.Println(raw) }}// print// 2023/08/26 17:15:52 {"name": "z3","info":{"num": [11,22,33]}}根据path或者索引获取数据func base() { data := `{"name": "z3","info":{"num": [11,22,33]}}` // no path return all json string root, err := sonic.GetFromString(data) if err != nil {log.Panic(err) }// according to path(根据key,查询当前node下的元素) if path, err := root.GetByPath("name").Raw(); err != nil {log.Panic(err) } else {log.Println(path) } // indexOrget (同时提供index和key进行索引和key的匹配) if path, err := root.IndexOrGet(1, "info").Raw(); err != nil {log.Panic(err) } else {log.Println(path) }// index (按照index进行查找当前node下的元素)// root.Index(1).Index(0).Raw()意味着// root.Index(1) == "info"// root.Index(1).Index(0) == "num"// root.Index(1).Index(0).Raw() == "[11,22,33]" if path, err := root.Index(1).Index(0).Raw(); err != nil {log.Panic(err) } else {log.Println(path) }}// print// 2023/08/26 17:17:49 "z3"// 2023/08/26 17:17:49 {"num": [11,22,33]}// 2023/08/26 17:17:49 [11,22,33]Ast.Node支持链式调用 。故我们可以从root node节点,根据path路径向下搜索指定的元素 。
index和key混用user := root.GetByPath("statuses", 3, "user")// === root.Get("status").Index(3).Get("user")根据path进行修改数据func base() { data := `{"name": "z3","info":{"num": [11,22,33]}}` // no path return all json string root, err := sonic.GetFromString(data) if err != nil {log.Panic(err) } // according to path if path, err := root.GetByPath("name").Raw(); err != nil {log.Panic(err) } else {log.Println(path) } // indexOrget (同时提供index和key进行索引和key的匹配) if path, err := root.IndexOrGet(1, "info").Raw(); err != nil {log.Panic(err) } else {log.Println(path) } // index if path, err := root.Index(1).Index(0).Raw(); err != nil {log.Panic(err) } else {log.Println(path) } // set// ast提供了很多go类型转换node的函数 if _, err := root.Index(1).SetByIndex(0, ast.NewArray([]ast.Node{ast.NewNumber("101"),ast.NewNumber("202"), })); err != nil {log.Panic(err) } raw, _ := root.Raw() log.Println(raw)}// print// 2023/08/26 17:23:55 "z3"// 2023/08/26 17:23:55 {"num": [11,22,33]}// 2023/08/26 17:23:55 [11,22,33]// 2023/08/26 17:23:55 {"name":"z3","info":{"num":[101,202]}}序列化func base() {data := `{"name": "z3","info":{"num": [11,22,33]}}` // no path return all json string root, err := sonic.GetFromString(data) if err != nil {log.Panic(err) } bts, _ := root.MarshalJSON() log.Println("Ast.Node(Marshal): ", string(bts)) btes, _ := json.Marshal(&root) log.Println("encoding/json (Marshal): ", string(btes))}// print// 2023/08/26 17:39:06 Ast.Node(Marshal):{"name": "z3","info":{"num": [11,22,33]}}// 2023/08/26 17:39:06 encoding/json (Marshal):{"name":"z3","info":{"num":[11,22,33]}}


推荐阅读