json 解析:marshal 和 unmarshal

Posted lubanseven

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了json 解析:marshal 和 unmarshal相关的知识,希望对你有一定的参考价值。


Go 使用 encoding/json 包的 marshal 和 unmarshal 实现 json 数据的编解码。分别记录如下:

1. marshal

定义结构体:

type OCP struct 
	Name          string         `json:"name"`
	ImageRegistry *ImageRegistry `json:"imageRegistry"`
	Status        string         `json:"status"`
	Events        []string       `json:"events"`
	id            *int


type ImageRegistry struct 
	Addr     string `json:"addr"`
	User     string `json:"user"`
	Password string `json:"password"`

将结构体 OCP 类型值编码成 json 格式:

func main() 
	imageRegistry := ImageRegistry
		Addr:     "x.x.x.x",
		User:     "admin",
		Password: "admin",
	

	ocp := OCP
		Name:          "lubanseven",
		ImageRegistry: &imageRegistry,
		Status:        "running",
		Events:        []string"normal", "normal", "normal",
	

	data, err := json.Marshal(ocp)
	if err != nil 
		fmt.Println(err)
	

	fmt.Println(string(data))

输出:

"name":"lubanseven","imageRegistry":"addr":"x.x.x.x","user":"admin","password":"admin","status":"running","events":["normal","normal","normal"]

从输出可以看出:

  1. 结构体中以小写字母开头的类型(id)不会被编码。
  2. 结构体中指针类型在编码时将转换为指针所指向的值。

更多编码规则可看 JSON and Go

2. unmarshal

类似的将 data 解码为结构体类型 OCP 的值:

var lubanseven OCP
err = json.Unmarshal(data, &lubanseven)
if err != nil 
	fmt.Println(err)

fmt.Println(lubanseven)

输出:

lubanseven 0xc00020e360 running [normal normal normal] <nil>

从输出可以看出:

  1. 指针类型的值在解码时将转换为值的地址。
  2. 对于无法解码的值,将转换为该值的零值,如指针类型变量 id 解码为 nil。

更多编码规则可看 JSON and Go

对于第二点,将 id 类型定义成 int,查看解码后的结构体值:

type OCP struct 
	Name          string         `json:"name"`
	ImageRegistry *ImageRegistry `json:"imageRegistry"`
	Status        string         `json:"status"`
	Events        []string       `json:"events"`
	id            int

输出:

lubanseven 0xc0000cc4b0 running [normal normal normal] 0

这点在解码的时候要注意。

上例中解码的结构体类型是已知的,如果结构体未知该如何确定结构体类型呢?这在实际场景中是会发生的,比如传输的数据流,事先不知道其结构体类型。
可以通过类型断言的方式,确定结构体类型,如下:

var lubanunknown interface
err = json.Unmarshal(data, &lubanunknown)
if err != nil 
	fmt.Println(err)

fmt.Println(lubanunknown)

if value, ok := lubanunknown.(map[string]interface); ok 
	fmt.Println(value)

输出:

map[events:[normal normal normal] imageRegistry:map[addr:x.x.x.x password:admin user:admin] name:lubanseven status:running]
map[events:[normal normal normal] imageRegistry:map[addr:x.x.x.x password:admin user:admin] name:lubanseven status:running]

输出类型是 map[string]interface,key 是 string,value 是 interface,可以对 value 进行类型断言确定 interface 的实质类型(直接看输出也能看出来...):

value := lubanunknown.(map[string]interface)

for k, v := range value 
	switch vv := v.(type) 
	case int:
		fmt.Println(k, "is int: ", vv)
	case string:
		fmt.Println(k, "is string: ", vv)
	case []interface:
		fmt.Println(k, "is slice: ", vv)
		for _, v := range vv 
			fmt.Println(v)
		
	case map[string]interface:
		fmt.Println(k, "is struct: ", vv)
	default:
		fmt.Println(k, "unexpect type of ", reflect.TypeOf(vv))
	

输出:

imageRegistry is struct:  map[addr:x.x.x.x password:admin user:admin]
status is string:  running
events is slice:  [normal normal normal]
normal
normal
normal
name is string:  lubanseven

3. 数据流的 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
        
        for k := range v 
            if k != "Name" 
                delete(v, k)
            
        
        if err := enc.Encode(&v); err != nil 
            log.Println(err)
        
    

示例来自 JSON and Go

运行示例:

$ go run main.go 
"name":"lubanseven","imageRegistry":"addr":"x.x.x.x","user":"admin","password":"admin","status":"running","events":["normal","normal","normal"]

"Name":"lubanseven","imageRegistry":"addr":"x.x.x.x","user":"admin","password":"admin","status":"running","events":["normal","normal","normal"]
"Name":"lubanseven"

芝兰生于空谷,不以无人而不芳。

以上是关于json 解析:marshal 和 unmarshal的主要内容,如果未能解决你的问题,请参考以下文章

Go的json解析:Marshal与Unmarshal

详解golang的json解析方法Marshal跟 Unmarshal(复杂的对象直接用神器生成对象)

markdown Golang json processing.md中的marshal和unmarshal问题

golang Marshal和Unmarshal处理json数据

golang里的json marshal && unmarshal

golang Marshal / Unmarshal将不同的JSON对象转换为Go结构