🌞

Golang系列教程--JSON解析

json
提供了 JSON 与 Go 变量之间的序列化与反序列化。

📜本文内容



JSON序列化

func Marshal(v interface{}) ([]byte, error)

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name    string `json:"name"`
	Country string `json:"country"`
	City    string `json:"city"`
}

func main() {
	amy := person{
		Name:    "Amy",
		Country: "China",
		City:    "Beijing",
	}
	data1, _ := json.Marshal(amy)
	fmt.Println(string(data1))
	data2, _ := json.MarshalIndent(amy, "", "    ")
	fmt.Println(string(data2))
}

使用 MarshalIndent() 可使数据输出的形式美观一些

1
2
3
4
5
6
{"name":"Amy","country":"China","city":"Beijing"}
{
   "name": "Amy",
   "country": "China",
   "city": "Beijing"
}

tag及使用技巧

1. 省略空字段 omitempty
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name    string `json:"name"`
	Country string `json:"country"`
	City    string `json:"city,omitempty"`
}

func main() {
	amy := person{
		Name:    "Amy",
	}
	data, _ := json.MarshalIndent(amy, "", "    ")
	fmt.Println(string(data))
}

JSON内的 city 字段增加 omitempty 关键字,初始化对象时未对该字段赋值,在序列化后将不显示;country 字段未注明忽略空值,序列化赋了默认0值:

1
2
3
4
{
    "name": "Amy",
    "country": ""
}
2. 忽略特定字段 -
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name    string `json:"name"`
	Country string `json:"country"`
	City    string `json:"-"`
}

func main() {
	amy := person{
		Name:    "Amy",
		Country: "China",
		City:    "Beijing",
	}
	data, _ := json.MarshalIndent(amy, "", "    ")
	fmt.Println(string(data))
}

即使字段已经初始化,序列化后的内容也不会包含此字段

1
2
3
4
{
    "name": "Amy",
    "country": "China"
}
3. JSON字段类型转换
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name    string `json:"name"`
	Age     int `json:"age,string"`
}

func main() {
	amy := person{
		Name:    "Amy",
		Age:     25,
	}

	data, _ := json.MarshalIndent(amy,"","    ")
	fmt.Printf("%s\n\n", string(data))
}

结构体内的 Age 字段为整型,加上 string 将本字段的值转化为字符串类型:

1
2
3
4
{
   "name": "Amy",
   "age": "25"
}
4. 临时添加新字段
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name    string `json:"name"`
	Country string `json:"country"`
	City    string `json:"city"`
}

func main() {
	amy := person{
		Name:    "Amy",
		Country: "China",
		City:    "Beijing",
	}
	data, _ := json.MarshalIndent(
		struct {
			person
			Gender string `json:"gender"`
		}{
			person: amy,
			Gender: "female",
		},"","    ")
	fmt.Println(string(data))
}

在序列化时新建一个结构体即可:

1
2
3
4
5
6
{
    "name": "Amy",
    "country": "China",
    "city": "Beijing",
    "gender": "female"
}
5. 多结构体组合成

从4中得到启发,可将多个结构体的字段组合成一个JSON

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name    string `json:"name"`
	Country string `json:"country"`
	City    string `json:"city"`
}

type occupation struct {
	Company  string `json:"company"`
	Position string `json:"position"`
}

func main() {
	amy := person{
		Name:    "Amy",
		Country: "China",
		City:    "Beijing",
	}

	job := occupation{
		Company:  "Google",
		Position: "developer",
	}
	data, _ := json.MarshalIndent(
		struct {
			person
			occupation
		}{
			person:     amy,
			occupation: job,
		}, "", "    ")
	fmt.Println(string(data))
}
1
2
3
4
5
6
7
{
    "name": "Amy",
    "country": "China",
    "city": "Beijing",
    "company": "Google",
    "position": "developer"
}
6. 对时间类型的序列化

Go对时间的序列化方式是格式化转化成字符串,并默认使用RFC3339标准 2006-01-02T15:04:05.999999999Z07:00 做格式化,时间对象转化为JSON默认使用 MarshalJSON() 方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func (t Time) MarshalJSON() ([]byte, error) {
	if y := t.Year(); y < 0 || y >= 10000 {
		// RFC 3339 is clear that years are 4 digits exactly.
		// See golang.org/issue/4556#c15 for more discussion.
		return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
	}

	b := make([]byte, 0, len(RFC3339Nano)+2)
	b = append(b, '"')
	b = t.AppendFormat(b, RFC3339Nano)
	b = append(b, '"')
	return b, nil
}

Marshaler 接口定义了 MarshalJSON() 方法,Go中的时间 time.Time 实现了 Marshaler 接口:

1
2
3
type Marshaler interface {
        MarshalJSON() ([]byte, error)
}

结合上述思路,我们可以自定义时间类型,实现 Marshaler 接口,达到自定义序列化的目的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
	"encoding/json"
	"fmt"
	"time"
)

//自定义时间类型
type MyTime time.Time

// 实现Marshaler接口
func (mytime MyTime) MarshalJSON() ([]byte, error) {
	n := time.Time(mytime).Format("2006-01-02 15:04")
	t := "\"" + n + "\""
	return []byte(t), nil
}

type person struct {
	Name     string `json:"name"`
	Country  string `json:"country"`
	City     string `json:"city"`
	Birthday MyTime `json:"birthday"`
}

func main() {
	amy := person{
		Name:     "Amy",
		Country:  "China",
		City:     "Beijing",
		Birthday: MyTime(time.Now()),
	}
	data, _ := json.MarshalIndent(amy, "", "    ")
	fmt.Println(string(data))
}

本例将时间输出格式修改为 年-月-日 时:分

1
2
3
4
5
6
{
    "name": "Amy",
    "country": "China",
    "city": "Beijing",
    "birthday": "2019-09-05 18:42"
}

JSON反序列化

func Unmarshal(data []byte, v interface{}) error

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name    string `json:"name"`
	Country string `json:"country"`
	City    string `json:"city"`
}

func main() {
	data := `{
	"name": "Amy",
	"country": "China",
	"city":"Beijing"
	}`
	amy := person{}
	err := json.Unmarshal([]byte(data), &amy)
	if err == nil {
		fmt.Printf("%s\n%s\n%s\n", amy.Name, amy.Country, amy.City)
	}
}

反序列化完成字符串到对象的转化,当 Unmarshal() 方法返回错误不空表示反序列化失败

1
2
3
Amy
China
Beijing

JSON反序列化的常用技巧

拆分成多个结构体
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name    string `json:"name"`
	Country string `json:"country"`
	City    string `json:"city"`
}

type occupation struct {
	Company  string `json:"company"`
	Position string `json:"position"`
}

func main() {
	data := `{
	"name": "Amy",
	"country": "China",
	"city":"Beijing",
	"company":"Google",
	"position":"developer"
	}`

	amy := person{}
	job := occupation{}

	err := json.Unmarshal([]byte(data),
		&struct {
			*person
			*occupation
		}{&amy, &job})
	if err == nil {
		fmt.Printf("%v\n%v\n", amy, job)
	}
}
1
2
{Amy China Beijing}
{Google developer}

JSON与私有属性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name    string `json:"name"`
	country string `json:"country"`
}

func main() {
	d := `{
	"name": "Amy",
	"country": "China"
	}`

	amy := Person{}

	err := json.Unmarshal([]byte(d),&amy)
	if err == nil {
		fmt.Printf("%v\n", amy)
	}

  Sam := Person{
    Name: "Sam",
    country: "CN",
  }
  data,err := json.Marshal(Sam)
	if err == nil {
		fmt.Printf("%v\n", string(data))
	}
}

Person 内的 country 是私有属性,JSON的序列化及反序列化都不会对私有属性转化。

1
2
{Amy}
{"name":"Sam"}

👏欢迎评论👏

updatedupdated2020-05-082020-05-08