加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Go语言解码未知结构的JSON数据

发布时间:2020-12-16 09:36:26 所属栏目:大数据 来源:网络整理
导读:Go语言内置的 encoding/json 标准库提供了对 JSON 数据进行编解码的功能。在实际开发过程中,有时候我们可能并不知道要解码的 JSON 数据结构是什么样子的,这个时候应该怎么处理呢? 如果要解码一段未知结构的 JSON,只需将这段 JSON 数据解码输出到一个空接
Go语言内置的 encoding/json 标准库提供了对 JSON 数据进行编解码的功能。在实际开发过程中,有时候我们可能并不知道要解码的 JSON 数据结构是什么样子的,这个时候应该怎么处理呢?

如果要解码一段未知结构的 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": "C语言中文网","website": "http://c.biancheng.net/","course": ["Golang","PHP","JAVA","C"]}`)
    var user4 interface{}
    err := json.Unmarshal(u3,&user4)
    if err != nil {
        fmt.Printf("JSON 解码失败:%vn",err)
        return
    }
    fmt.Printf("JSON 解码结果: %#vn",user4)
}
上述代码中,user4 被定义为一个空接口;json.Unmarshal() 函数将一个 JSON 对象 u3 解码到空接口 user4 中,最终 user4 将会是一个键值对的map[string]interface{}结构。

运行结果如下:

JSON 解码结果: map[string]interface {}{"course":[]interface {}{"Golang","PHP","C"},"name":"C语言中文网","website":"http://c.biancheng.net/"}

因为 u3 整体上是一个 JSON 对象,内部属性也会遵循上述类型的转化规则进行转换。

访问解码后数据

要访问解码后的数据结构,需要先判断目标结构是否为预期的数据类型,然后我们可以通过 for 循环搭配 range 语句访问解码后的目标数据:
package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    u3 := []byte(`{"name": "C语言中文网",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 C语言中文网
website is string http://c.biancheng.net/
course is an array:
0 Golang
1 PHP
2 JAVA
3 C

虽然有些烦琐,但的确是一种解码未知结构的 JSON 数据的安全方式。

JSON 的流式读写

Go语言内置的 encoding/json 包还提供了 Decoder 和 Encoder 两个类型,用于支持 JSON 数据的流式读写,并提供了 NewDecoder() 和 NewEncoder() 两个函数用于具体实现:

func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder

【示例 2】从标准输入流中读取 JSON 数据,然后将其解码,最后再写入到标准输出流中:
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": "C语言中文网","C"]}
{"course":["Golang","C"],"website":"http://c.biancheng.net/"}

其中,第二行为我们输入的内容,第三行为输出内容。

使用 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),}
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读