Go语言解码未知结构的JSON数据
Go语言内置的 encoding/json 标准库提供了对 JSON 数据进行编解码的功能。在实际开发过程中,有时候我们可能并不知道要解码的 JSON 数据结构是什么样子的,这个时候应该怎么处理呢?
如果要解码一段未知结构的 JSON,只需将这段 JSON 数据解码输出到一个空接口即可。关于 JSON 数据的编码和解码的详细介绍可以阅读《Json数据编码和解码》一节。
在实际解码过程中,JSON 结构里边的数据元素将做如下类型转换:
在Go语言标准库 encoding/json 中,可以使用
【示例 1】解析 JSON 数据,并将结果映射到空接口对象:
运行结果如下:
使用 Decoder 和 Encoder 对数据流进行处理可以应用得更为广泛些,比如读写 HTTP 连接、WebSocket 或文件等,Go语言标准库中的 net/rpc/jsonrpc 就是一个应用了 Decoder 和 Encoder 的实际例子:
如果要解码一段未知结构的 JSON,只需将这段 JSON 数据解码输出到一个空接口即可。关于 JSON 数据的编码和解码的详细介绍可以阅读《Json数据编码和解码》一节。
类型转换规则
在前面介绍接口的时候,我们提到基于Go语言的面向对象特性,可以通过空接口来表示任何类型,这同样也适用于对未知结构的 JSON 数据进行解码,只需要将这段 JSON 数据解码输出到一个空接口即可。在实际解码过程中,JSON 结构里边的数据元素将做如下类型转换:
- 布尔值将会转换为Go语言的 bool 类型;
- 数值会被转换为Go语言的 float64 类型;
- 字符串转换后还是 string 类型;
- JSON 数组会转换为 []interface{} 类型;
- JSON 对象会转换为 map[string]interface{} 类型;
- null 值会转换为 nil。
在Go语言标准库 encoding/json 中,可以使用
map[string]interface{}
和[]interface{}
类型的值来分别存放未知结构的 JSON 对象或数组。【示例 1】解析 JSON 数据,并将结果映射到空接口对象:
package main import ( "encoding/json" "fmt" ) func main() { u3 := []byte(`{"name": "新宝库", "website": "https://www.xinbaoku.com/", "course": ["Golang", "PHP", "JAVA", "C"]}`) var user4 interface{} err := json.Unmarshal(u3, &user4) if err != nil { fmt.Printf("JSON 解码失败:%v\n", err) return } fmt.Printf("JSON 解码结果: %#v\n", user4) }上述代码中,user4 被定义为一个空接口;json.Unmarshal() 函数将一个 JSON 对象 u3 解码到空接口 user4 中,最终 user4 将会是一个键值对的
map[string]interface{}
结构。运行结果如下:
JSON 解码结果: map[string]interface {}{"course":[]interface {}{"Golang", "PHP", "JAVA", "C"}, "name":"新宝库", "website":"https://www.xinbaoku.com/"}
因为 u3 整体上是一个 JSON 对象,内部属性也会遵循上述类型的转化规则进行转换。访问解码后数据
要访问解码后的数据结构,需要先判断目标结构是否为预期的数据类型,然后我们可以通过 for 循环搭配 range 语句访问解码后的目标数据:package main import ( "encoding/json" "fmt" ) func main() { u3 := []byte(`{"name": "新宝库", "website": "https://www.xinbaoku.com/", "course": ["Golang", "PHP", "JAVA", "C"]}`) var user4 interface{} err := json.Unmarshal(u3, &user4) if err != nil { fmt.Printf("JSON 解码失败:%v\n", err) return } user5, ok := user4.(map[string]interface{}) if ok { for k, v := range user5 { switch v2 := v.(type) { case string: fmt.Println(k, "is string", v2) case int: fmt.Println(k, "is int", v2) case bool: fmt.Println(k, "is bool", v2) case []interface{}: fmt.Println(k, "is an array:") for i, iv := range v2 { fmt.Println(i, iv) } default: fmt.Println(k, "类型未知") } } } }运行结果如下:
name is string 新宝库
website is string https://www.xinbaoku.com/
course is an array:
0 Golang
1 PHP
2 JAVA
3 C
JSON 的流式读写
Go语言内置的 encoding/json 包还提供了 Decoder 和 Encoder 两个类型,用于支持 JSON 数据的流式读写,并提供了 NewDecoder() 和 NewEncoder() 两个函数用于具体实现:
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
package main import ( "encoding/json" "log" "os" ) func main() { dec := json.NewDecoder(os.Stdin) enc := json.NewEncoder(os.Stdout) for { var v map[string]interface{} if err := dec.Decode(&v); err != nil { log.Println(err) return } if err := enc.Encode(&v); err != nil { log.Println(err) } } }执行上面的代码,我们需要先输入 JSON 结构数据供标准输入流 os.Stdin 读取,读取到数据后,会通过 json.NewDecoder 返回的解码器对其进行解码,最后再通过 json.NewEncoder 返回的编码器将数据编码后写入标准输出流 os.Stdout 并打印出来:
go run main.go
{"name": "新宝库", "website": "https://www.xinbaoku.com/", "course": ["Golang", "PHP", "JAVA", "C"]}
{"course":["Golang","PHP","JAVA","C"],"name":"新宝库","website":"https://www.xinbaoku.com/"}
使用 Decoder 和 Encoder 对数据流进行处理可以应用得更为广泛些,比如读写 HTTP 连接、WebSocket 或文件等,Go语言标准库中的 net/rpc/jsonrpc 就是一个应用了 Decoder 和 Encoder 的实际例子:
// NewServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn. func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec { return &serverCodec{ dec: json.NewDecoder(conn), enc: json.NewEncoder(conn), c: conn, pending: make(map[uint64]*json.RawMessage), } }
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算