zoukankan      html  css  js  c++  java
  • JSON的Go解析

    JSON(Javascript Object Notation)是一种轻量级的数据交换语言,以文字为基础,具有自我描述性且易于让人阅读。尽管JSON是Javascript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。JSON与XML最大的不同在于XML是一个完整的标记语言,而JSON不是。JSON由于比XML更小、更快,更易解析,以及浏览器的内建快速解析支持,使得其更适用于网络数据传输领域。

    1. 标准库解析

    Go语言标准库已经支持JSONencoding/json

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

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

    分别实现结构体或interfaceJSON字符串,JSON字符串转结构体或interface的操作。

    Marshal函数只有在转换成功的时候才会返回数据,在转换的过程中我们需要注意几点:

    ·         JSON对象只支持string作为key,所以要编码一个map,那么必须是map[string]T这种类型(TGo语言中任意的类型)

    ·         Channel, complexfunction是不能被编码成JSON

    ·         嵌套的数据是不能编码的,不然会让JSON编码进入死循环

    ·         指针在编码的时候会输出指针指向的内容,而空指针会输出null

    1.1 结构体解析

    JSON字符串转化为Structstruct的字段名与JSONkey对应,如果JSONkeyFoo,怎样找到对应的字段呢?

    ·         首先查找tag含有Foo的可导出的struct字段(首字母大写)

    ·         其次查找字段名是Foo的导出字段

    ·         最后查找类似FOO或者FoO这样的除了首字母之外其他大小写不敏感的导出字段

    能够被赋值的字段必须是可导出字段(即首字母大写)。同时JSON解析的时候只会解析能找得到的字段,找不到的字段会被忽略。这样的一个好处是:当你接收到一个很大的JSON数据结构而你却只想获取其中的部分数据的时候,你只需将你想要的数据对应的字段名大写,即可轻松解决这个问题。

    注:字符串转struct时,结构体与JSON子串实现双向最大匹配,只解析能解析的子串。

    struct转JSON时,可用tag指定key名称:

    ·         字段的tag"-",那么这个字段不会输出到JSON

    ·         tag中带有自定义名称,那么这个自定义名称会出现在JSON的字段名中

    ·         tag中如果带有",omitempty"选项,那么如果该字段值为空,就不会输出到JSON串中(,后无空格),只有struct转json时起作用。

    ·         如果字段类型是bool, string, int, int64等,而tag中带有",string"选项,那么这个字段在输出到JSON的时候会把该字段对应的值转换成JSON字符串

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type Server struct{
        ServerName string `json:"serverName"`
        ServerIP string `json:"serverIP"`
        Name string `json:"-"`
    }
    
    type Serverslice struct {
        Servers [] Server `json:"servers"`
        StrFirst string `json:"strFirst"`
        StrSecond string `json:"strSecond,string"`
    }
    
    func main(){
        var s Serverslice
        s.StrFirst = `Go "1.0" `
        s.StrSecond = `Go "1.0" `
        s.Servers = append(s.Servers, Server{ServerName: "Shanghai_VPN", ServerIP: "127.0.0.1", Name:"wang"})
        s.Servers = append(s.Servers, Server{ServerName: "Beijing_VPN", ServerIP: "127.0.0.2"})
        b, err := json.Marshal(s)
        if err != nil {
            fmt.Println("json err:", err)
        }
        fmt.Println(string(b))
    
        fmt.Println("---------------Unmarshal-----------")
        str := `{"Name":"Wednesday", "Age":6, "Parents":["Gomez", "Morticia"]}`
        var f interface{}
        err = json.Unmarshal([]byte(str), &f)
        if err != nil {
            return
        }
        fmt.Println(":", f)
    
        if m, ok := f.(map[string]interface{}); ok {
            for k, v := range m {
                switch vv := v.(type){
                case string:
                    fmt.Println(k, "is string", vv)
                case int:
                    fmt.Println(k, "is int", vv)
                case float64:
                    fmt.Println(k, "is float64", vv)
                case []interface{}:
                    fmt.Println(k, "is an array:")
                    for i, u := range vv {
                        fmt.Println(i, u)
                    }
                default:
                    fmt.Println(k, "is of a type that I don't know how to handle")
                }
            }
        }
    }

    运行结果:

    $ go run assemble.go
    {"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}],"strFirst":"Go "1.0" ","strSecond":""Go \"1.0\" ""}
    ---------------Unmarshal-----------
    : map[Name:Wednesday Age:6 Parents:[Gomez Morticia]]
    Name is string Wednesday
    Age is float64 6
    Parents is an array:
    0 Gomez
    1 Morticia
    result

    1.2 interface解析

    上述代码中JSON字符串解析到interface中,通过断言输出各个数据值。

    1.3 空值处理

    struct转json子串

    当结构体tag指定",omitempty"时,空值会被舍弃,不输出到json串口。

    • bool空值为false
    • string的空值为""(字符串长度为0)
    • 切片类型为nil
    • 指针类型为nil

    注:struct在golang为值类型,零值为结构体中各成员的零值,所以当结构体未赋值时(struct{}),json串输出{},而非被舍弃,即使设置omitempty。

    json子串转struct

    字符串转struct时,结构体与JSON子串实现双向最大匹配,只解析能解析的子串。

    Json串转换为strunt后,因为struct中各成员都必须有值,那如何判定这个值是字符串输入的还是golang赋的默认初值呢???

    1)比如bool,如果值整好是false,如何判断这个false是json子串输入的(因为bool的key不论字符串是否包含false的key,转换为struct后都是false)?

    不能判断。参考:go json 字符串转struct时 如何判断 bool类型的字段是否存在?

    go 初始struct对象的时候是默认初始化里边的字段的。这意味着你不能根据json 中bool字段的存在来对应影响生成的struct对象。

    要不你把json的bool字段换成默认的go语义为空的数据类型,比如string(有局限)。或者你override go中转换struct对象的方法。

    或者 可以把struct中的bool类型改为指针类型 *bool,这样如果不存在这个字段,那么就是nil,否则就是存在,取出值即可(有局限)

    2)nil空值,如果是nil,json中肯定没有输入,如果有输入就非nil了。但是如果json串中nil的key本身就是null,依然无法判断(有局限)

    3)string的“”,如果json串中的“”的key本身值就是“”,依然无法判断(有局限)

    4)struct的null,如果本身输入的就是null,依然无法判断(有局限)

    (备注:

    如此就要求json串中不设置的值,就不要填写,特别是null,false或“”

    这样可通过与空值比较来判断是否有输入,从而清空原来的保存的数据(http的patch)。

    特别地,struct如果是可比较的,空的struct应该与struct{}比较。)

    1.4 默认值设置

    struct转换为json串时,切片的默认值是null,如何输出[]呢?

    参考: Go语言设置JSON的默认值

    给需要设置的JSON字段初试化你想设置的值就OK。

    比如我想让[]string类型的字段的默认值是[],而不是nil,那我就make([]string, 0)赋值给该字段。转成JSON输出后,就是[]

    struct test{
        Test2 []string
    }
    
    t.Test2 = make([]string, 0)

    1.5 不修改结构体情况下忽略特定字段

    将字段首字母改为小写或添加 json:"-" 标签能够在 json.Marshal() 时忽略指定字段,但此处讨论的是在不修改原 struct 结构的前提下过忽略部分字段的方法。

    参考:golang struct 转 json 时如何忽略部分字段

    1)定义新 struct,在新 struct 中只保留必要字段。

    2)定义 tag 不同结构相同的 struct。

    3)通过map转换。

    2. 其他库解析

    go-simplejson

    bitly公司开源了一个叫做simplejson的包,在处理未知结构体JSON时相当方便。

    package main
    
    import (
        "fmt"
        sj "github.com/bitly/go-simplejson"
    )
    
    func main(){
        js, err := sj.NewJson([]byte(`{
            "test":{
                "array":[1, "2", 3],
                "int": 10,
                "float": 1.10,
                "bignum": 123456,
                "string": "simplejson",
                "bool": true
            }
        }`))
        if err != nil {
            return
        }
    
        arr, _ := js.Get("test").Get("array").Array()
        i, _ := js.Get("test").Get("int").Int()
        ms := js.Get("test").Get("string").MustString()
    
        fmt.Println("arr", arr, "i", i, "ms", ms)
    }

    运行结果:

    arr [1 2 3] i 10 ms simplejson

    easyjson

    https://github.com/mailru/easyjson.git

    encoding/json采用反射设计,easyjson采用生成代码的方式(针对特定json),非常高效。

     

    参考:

    1Go Web编程 7.2 JSON处理

    2https://github.com/bitly/go-simplejson

    3. https://github.com/mailru/easyjson.git

    4. go json转换实践中遇到的坑   整数变浮点数问题   时间格式

    5. golang struct 转 json 时如何忽略部分字段  https://www.dazhuanlan.com/2019/10/15/5da55aaccfa55/

     

  • 相关阅读:
    洛谷—— P3353 在你窗外闪耀的星星
    洛谷—— P1238 走迷宫
    洛谷—— P1262 间谍网络
    9.8——模拟赛
    洛谷—— P1189 SEARCH
    算法
    May 22nd 2017 Week 21st Monday
    May 21st 2017 Week 21st Sunday
    May 20th 2017 Week 20th Saturday
    May 19th 2017 Week 20th Friday
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/11829307.html
Copyright © 2011-2022 走看看