[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
}

声明:该文章系转载,转载该文章的目的在于更广泛的传递信息,并不代表本网站赞同其观点,文章内容仅供参考。

本站是一个个人学习和交流平台,网站上部分文章为网站管理员和网友从相关媒体转载而来,并不用于任何商业目的,内容为作者个人观点, 并不代表本网站赞同其观点和对其真实性负责。

我们已经尽可能的对作者和来源进行了通告,但是可能由于能力有限或疏忽,导致作者和来源有误,亦可能您并不期望您的作品在我们的网站上发布。我们为这些问题向您致歉,如果您在我站上发现此类问题,请及时联系我们,我们将根据您的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。