[go]灵活的处理json与go结构体

  • go数据结构与json数据结构对应( json.Unmarshal帮助手册)

 bool, for JSON booleans
 float64, for JSON numbers
 string, for JSON strings
 []interface{}, for JSON arrays
 map[string]interface{}, for JSON objects
 nil for JSON nul


注: 手册里可以看到转json时, 常见选项的含义和例子.
package main

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

type response1 struct {
    Page   int
    Fruits []string
}

type response2 struct {
    Page   int      `json:"page"`
    Fruits []string `json:"fruits"`
}

func main() {

    bolB, _ := json.Marshal(true)
    fmt.Println(string(bolB))

    intB, _ := json.Marshal(1)
    fmt.Println(string(intB))

    fltB, _ := json.Marshal(2.34)
    fmt.Println(string(fltB))

    strB, _ := json.Marshal("gopher")
    fmt.Println(string(strB))

    slcD := []string{"apple", "peach", "pear"}
    slcB, _ := json.Marshal(slcD)
    fmt.Println(string(slcB))

    mapD := map[string]int{"apple": 5, "lettuce": 7}
    mapB, _ := json.Marshal(mapD)
    fmt.Println(string(mapB))

    res1D := &response1{
        Page:   1,
        Fruits: []string{"apple", "peach", "pear"}}
    res1B, _ := json.Marshal(res1D)
    fmt.Println(string(res1B))

    res2D := &response2{
        Page:   1,
        Fruits: []string{"apple", "peach", "pear"}}
    res2B, _ := json.Marshal(res2D)
    fmt.Println(string(res2B))

    byt := []byte(`{"num":6.13,"strs":["a","b"]}`)

    var dat map[string]interface{}

    if err := json.Unmarshal(byt, &dat); err != nil {
        panic(err)
    }
    fmt.Println(dat)

    num := dat["num"].(float64)
    fmt.Println(num)

    strs := dat["strs"].([]interface{})
    str1 := strs[0].(string)
    fmt.Println(str1)

    str := `{"page": 1, "fruits": ["apple", "peach"]}`
    res := response2{}
    json.Unmarshal([]byte(str), &res)
    fmt.Println(res)
    fmt.Println(res.Fruits[0])
    
    //上面unmarshal得到的都是字节数组,  这里直接将字节数组写入流
    enc := json.NewEncoder(os.Stdout)
    d := map[string]int{"apple": 5, "lettuce": 7}
    enc.Encode(d)
}
  • go数据类型转json: struct tag for json: 结构体转json时作用

/*
Examples of struct field tags and their meanings:
  // Field appears in JSON as key "myName".
  Field int `json:"myName"`

  // Field appears in JSON as key "myName" and
  // the field is omitted from the object if its value is empty,
  // as defined above.
  Field int `json:"myName,omitempty"`

  // Field appears in JSON as key "Field" (the default), but
  // the field is skipped if empty.
  // Note the leading comma.
  Field int `json:",omitempty"`

  // Field is ignored by this package.
  Field int `json:"-"`

  // Field appears in JSON as key "-".
  Field int `json:"-,"
*/
- 默认
type user struct {
	Name string
	Age  int
}

func main() {
	u := user{
		Name: "m1",
		Age:  22,
	}
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}
// {"Name":"m1","Age":22}

- json tag: 

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

func main() {
	u := user{
		Name: "m1",
		Age:  22,
	}
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}

// {"name":"m1","age":22}
- struct实例缺少字段

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

func main() {
	u := user{
		Name: "m1",
	}
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}

// {"name":"m1","age":0}
- josn tag: omitempty

//例子1:
type user struct {
	Name string `json:"name"`
	Age int `json:"age,omitempty"`
}

func main() {
	u := user{
		Name: "m1",
		Age:  10,
	}
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}

//{"name":"m1","age":10}


//例子2:
type user struct {
	Name string `json:"name"`
	Age int `json:"age,omitempty"`
}

func main() {
	u := user{
		Name: "m1",
		Age:  0,
	}
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}

//{"name":"m1"}


//例子3:
type user struct {
	Name string `json:"name"`
	Age int `json:"age,omitempty"`
}

func main() {
	u := user{
		Name: "m1",
	}
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}

//{"name":"m1"}


- 删除字段:

//例子1:
type user struct {
	Name string `json:"name"`
	Age  int    `json:"-"`
}

func main() {
	u := user{
		Name: "m1",
		Age:  12,
	}
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}

//{"name":"m1"}


//例子2:

type user struct {
	Name string `json:"name"`
	Age  int    `json:"-"`
}

func main() {
	u := user{
		Name: "m1",
		Age:  0,
	}
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}

//{"name":"m1"}

- json tag: string

// 例1:
type user struct {
	Name string `json:"name"`
	Age  int    `json:",string"`
}

func main() {
	u := user{
		Name: "m1",
		Age:  22,
	}
	b, _ := json.Marshal(u)

	fmt.Println(string(b))
}

//{"name":"m1","Age":"22"}


// 例2:
type user struct {
	Name string `json:"name",int"` //str转int, 出错,但不报错
	Age  int 
}

func main() {
	u := user{
		Name: "m1",
		Age:  22,
	}
	b, err := json.Marshal(u)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(b))
}

//{"name":"m1","Age":"22"}

  • 转go数据结构
- json类型和struct不匹配: 转换失败, 报错(支持类型校验)

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

func main() {
	var jsonStr = `
		{
			"name":"m1",
			"age":"22"
		}
	`
	var u user

	err := json.Unmarshal([]byte(jsonStr), &u)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(u)
}

//json: cannot unmarshal string into Go struct field user.age of type int
//{m1 0}
- 支持类型转换(但不支持自适应)
type user struct {
    Name string `json:"name"`
    Age  int    `json:"age,string"`
}

func main() {
    var jsonStr = `
        {
            "name":"m1",
            "age":"22"
        }
    `
    var u user

    err := json.Unmarshal([]byte(jsonStr), &u)
    if err != nil {
        fmt.Println(err.Error())
    }
    fmt.Printf("%#v",u)
}
//main.user{Name:"m1", Age:22}
- 不支持弱类型转换
type user struct {
    Name string `json:"name"`
    Age  int    `json:"age,string"`
}

func main() {
    var jsonStr = `
        {
            "name":"m1",
            "age":22
        }
    `
    var u user

    err := json.Unmarshal([]byte(jsonStr), &u)
    if err != nil {
        fmt.Println(err.Error())
    }
    fmt.Printf("%#v",u)
}
//json: invalid use of ,string struct tag, trying to unmarshal unquoted value into
// int
//main.user{Name:"m1", Age:0}
- 如果json缺字段, struct以零值填充

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

func main() {
	var jsonStr = `
		{
			"name":"m1"
		}
	`
	var u user

	err := json.Unmarshal([]byte(jsonStr), &u)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(u)
}

//{m1 0}
- 无论多少层的json 都能Unmarshal到 map[string]interface{}中
const jsonStr = `
				{
					"name":{
						"first":"Janet",
						"last":"Prichard",
						"address":{"age":22}
					},
					"age":47
				}
				`

func main() {
	m := map[string]interface{}{}

	json.Unmarshal([]byte(jsonStr), &m)

	fmt.Printf("%#v", m)
}
//map[string]interface {}{"age":47, "name":map[string]interface {}{"address":map[string]interface {}{"age":22}, "first":"Janet", "last":"Prichard"}}

临时忽略struct空字段
临时添加额外的字段
临时粘合两个struct
一个json切分成两个struct
临时改名struct的字段
用字符串传递数字
容忍字符串和数字互转
容忍空数组作为对象
使用 MarshalJSON支持time.Time
使用 RegisterTypeEncoder支持time.Time
使用 MarshalText支持非字符串作为key的map
使用 json.RawMessage
使用 json.Number
统一更改字段的命名风格
使用私有的字段
忽略掉一些字段
忽略掉一些字段2
- 练习: 写出下列json的struct:
{
    "resultcode": "200",
    "reason": "Return Successd!",
    "result": {
        "province": "浙江",
        "city": "杭州",
        "areacode": "0571",
        "zip": "310000",
        "company": "中国移动",
        "card": ""
    }
}



type Province struct {
	Resultcode string `json:"resultcode"`
	Reason     string `json:"reason"`
	Results    Results `json:"results"`
}

type Results struct {
	Province string `json:"province"`
	City     string `json:"city"`
	Areacode string `json:"areacode"`
	Zip      string `json:"zip"`
	Company  string `json:"company"`
	Card     string `json:"card"`
}
- 支持tag
func main() {
	// Note that the mapstructure tags defined in the struct type
	// can indicate which fields the values are mapped to.
	type Person struct {
		Name string `mapstructure:"person_name"`
		Age  int    `mapstructure:"person_age"`
	}

	input := map[string]interface{}{
		"person_name": "Mitchell",
		"person_age":  91,
	}

	var result Person
	err := Decode(input, &result)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v", result)
	
	//Output:
	//
	//mapstructure.Person{Name:"Mitchell", Age:91}
}
- 支持字段类型校验
func main() {
	type Person struct {
		Name   string
		Age    int
		Emails []string
		Extra  map[string]string
	}

	// This input can come from anywhere, but typically comes from
	// something like decoding JSON where we're not quite sure of the
	// struct initially.
	input := map[string]interface{}{
		"name":   123,
		"age":    "bad value",
		"emails": []int{1, 2, 3},
	}

	var result Person
	err := Decode(input, &result)
	if err == nil {
		panic("should have an error")
	}

	fmt.Println(err.Error())
	
	//Output:
	//
	//5 error(s) decoding:
	//* 'Age' expected type 'int', got unconvertible type 'string'
	//* 'Emails[0]' expected type 'string', got unconvertible type 'int'
	//* 'Emails[1]' expected type 'string', got unconvertible type 'int'
	//* 'Emails[2]' expected type 'string', got unconvertible type 'int'
	//* 'Name' expected type 'string', got unconvertible type 'int'
}
- 支持结构体嵌套
func main() {
	// Squashing multiple embedded structs is allowed using the squash tag.
	// This is demonstrated by creating a composite struct of multiple types
	// and decoding into it. In this case, a person can carry with it both
	// a Family and a Location, as well as their own FirstName.
	type Family struct {
		LastName string
	}
	type Location struct {
		City string
	}
	type Person struct {
		Family    `mapstructure:",squash"`
		Location  `mapstructure:",squash"`
		FirstName string
	}

	input := map[string]interface{}{
		"FirstName": "Mitchell",
		"LastName":  "Hashimoto",
		"City":      "San Francisco",
	}

	var result Person
	err := Decode(input, &result)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s %s, %s", result.FirstName, result.LastName, result.City)
	
	//Output:
	//
	//Mitchell Hashimoto, San Francisco
}
- 支持类型自适应(week转换)
- 实际的用处

// json数据: data对应结构体可能不同, 所以定义为 []map[string]string

{
    "type": "UPDATE",
    "database": "blog",
    "table": "blog",
    "data": [
        {
            "blogId": "100001",
            "title": "title",
            "content": "this is a blog",
            "uid": "1000012",
            "state": "1"
        }
    ]
}



package main

import (
	"encoding/json"
	"fmt"
	"github.com/mitchellh/mapstructure"
)

type Event struct {
	Type     string              `json:"type"`
	Database string              `json:"database"`
	Table    string              `json:"table"`
	Data     []map[string]string `json:"data"`
}

type Blog struct {
	BlogId  string `mapstructure:"blogId"`
	Title   string `mapstructrue:"title"`
	Content string `mapstructure:"content"`
	Uid     int32  `mapstructure:"uid"`
	State   int32  `mapstructure:"state"`
}

func main() {
	msg := []byte(`{
    "type": "UPDATE",
    "database": "blog",
    "table": "blog",
    "data": [
        {
            "blogId": "100001",
            "title": "title",
            "content": "this is a blog",
            "uid": "1000012",
            "state": "1"
        }
    ]}`)
	e := Event{}
	if err := json.Unmarshal(msg, &e); err != nil {
		panic(err)
	}
	if e.Table == "blog" {
		var blogs []Blog
		if err := mapstructure.WeakDecode(e.Data, &blogs); err != nil {
			panic(err)
		}

		fmt.Println(blogs)
	}
}

参考: GO小知识之实例演示 json 如何转化为 map 和 struct

1. json.Unmarshal 将JSON转为 map[string]interface{}。
	缺陷:
		需要检查key是否存在
		key 容易写错

2. 改进: 将不固定的部分即: Data: []map[string]string
		 固定的部分保持

3. 将可变字段用mapstructure转换为struct, 能自适应value类型

- 取值
package main

import "github.com/tidwall/gjson"

const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`

func main() {
	value := gjson.Get(json, "name.last")
	println(value.String())
}
- 遍历
const json = `
				{
					"name":{
						"first":"Janet",
						"last":"Prichard",
						"address":{"age":22}
					},
					"age":47
				}
				`
func main() {
	result := gjson.Get(json, "name")
	result.ForEach(func(key, value gjson.Result) bool {
		println(value.String())
		return true // keep iterating
	})
}
- Unmarshal to a map

m, ok := gjson.Parse(json).Value().(map[string]interface{})
if !ok {
	// not a map
}
posted @ 2019-12-30 10:26  毛台  阅读(...)  评论(...编辑  收藏