Golang json 解析与生成

    xiaoxiao2022-07-12  168

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

    Golang 自带的 JSON 解析库 encoding/json,可以用来将结构化数据序列化成 json 字符串或从 json 字符串中解析出我们想要的数据。

    1.解析 json

    1.1 以 map[string]interface{} 存储 json

    给一个较为复杂的 json 字符串,包含数组,数组的元素是 json 对象。我们需要取出数组第一个元素中的某一个字段值。其它的解析均可参考下面的代码。

    package main import ( "encoding/json" "fmt" ) func main() { jsonStr := []byte(`{"uin":1589276509,"feedID":10000,"videos":[{"picture":"http://qqpublic.qpic.cn/avatar.jpg","duration":"839"}]}`) var jsonMap map[string]interface{} if err := json.Unmarshal(jsonStr, &jsonMap); err!=nil { fmt.Printf("json decode failed, err=%v", err) return } if value, ok := jsonMap["videos"]; ok { fmt.Printf("value=%#v\n", value) if sliceValue, ok := value.([]interface{}); ok { if mapValue, ok := sliceValue[0].(map[string]interface{}); ok { if duration, ok := mapValue["duration"]; ok { fmt.Printf("d=%v,type=%T\n", duration, duration) } } } } }

    程序输出:

    value=[]interface {}{map[string]interface {}{"picture":"http://qqpublic.qpic.cn/avatar.jpg", "duration":"839"}} d=839,type=string

    解析 json 字符串时,需要注意如下几点: (1)Golang 类型和 JSON 类型的对应关系如下:

    map[string]interface{} 代表 JSON 对象 []interface{} 代表 JSON 数组 bool 代表 JSON boolean float64 代表 JSON number string 代表 JSON string nil 代表 JSON null

    1.2 以 struct 存储 json

    如果我们事先知道 json 的 key 名与 value 的类型,那么我们可以指定具体的 struct 来存储解析后的 json。

    package main import ( "fmt" "encoding/json" ) type FeedsItem struct { Title string `json:"string_title"` Score int `json:"uint32_score"` AiKongbuLevel int `json:"uint32_ai_kongbu_level"` AiDisuLevel int `json:"uint32_ai_disu_level"` AiBiaotidangLevel int `json:"uint32_ai_biaotidang_level"` AiUnsocialLevel int `json:"uint32_ai_unsocial_level"` } func main() { data:=`[{ "uint32_feed_pos": 1, "string_title": "它才是“天然补血王”,女性隔三差五吃,美容驻颜,气色更红润", "uint32_score": 4, "uint32_ai_kongbu_level": 0, "uint32_ai_disu_level": 0, "uint32_ai_biaotidang_level": 1, "uint32_ai_unsocial_level": 0 }, { "uint32_feed_pos": 2, "string_title": "7岁的火星男孩,顺利通过测谎仪,现在为何消失不见了?", "uint32_score": 4, "uint32_ai_kongbu_level": 0, "uint32_ai_disu_level": 0, "uint32_ai_biaotidang_level": 0, "uint32_ai_unsocial_level": 0 }]` var feedsInfo []FeedsItem //第二个参数必须是指针,否则无法接收解析后的数据 if err := json.Unmarshal([]byte(data), &feedsInfo); err != nil { fmt.Printf("json.Unmarshal() failed, err=%v data=%s\n", err, data) return } fmt.Printf("jsonMap=%#v\n", feedsInfo) }

    编译运行输出:

    jsonMap=[]main.FeedsItem{main.FeedsItem{Title:"它才是“天然补血王”,女性隔三差五吃,美容驻颜,气色更红润", Score:4, AiKongbuLevel:0, AiDisuLevel:0, AiBiaotidangLevel:1, AiUnsocialLevel:0}, main.FeedsItem{Title:"7岁的火星男孩,顺利通过测谎仪,现在为何消失不见了?", Score:4, AiKongbuLevel:0, AiDisuLevel:0, AiBiaotidangLevel:0, AiUnsocialLevel:0}}

    1.3 以 []map[string]interface{} 解析 json 数组

    如果 json 字符串是一个 json 数组,除了可以使用 struct 来解析,也可以使用 []map[string]interface{} 来解析。

    package main import ( "fmt" "encoding/json" ) func main(){ s := `[{"id":300001,"exp_layer":"string","buckets":"1,2,3"},{"id":300002,"exp_layer":"test2","buckets":"4"}]` var jsonArray []map[string]interface{} if err := json.Unmarshal([]byte(s), &jsonArray); err!=nil { fmt.Printf("json decode failed, err=%v value=%v\n", err, s) return } fmt.Printf("jsonArray=%+v\n", jsonArray) }

    输出结果:

    jsonArray=[map[exp_layer:string buckets:1,2,3 id:300001] map[id:300002 exp_layer:test2 buckets:4]]

    2.生成 json

    解析 json 时,可以使用 map[string]interface{} 或者 struct 来接收解析后的数据。同样地,我们可以将 struct 或者 map[string]interface{} 序列化为 json。

    Golang 中,json 的表示主要有两种方式,一种是 struct,另一种是 map[string]interface{}。在表示数组时,分别使用具体类型的切片和任意类型的切片 []interface{}。

    2.1 将 struct 序列化为 json

    假设我们有如下一个结构体 Student 及其一个实例对象 st,将其序列化为 json,具体实现如下:

    package main import ( "encoding/json" "fmt" ) type Student struct { Name string `json:"name"` Age int gender string Class *Class `json:"class"` } type Class struct { Name string Grade int } func main() { //实例化一个数据结构,用于生成 json 字符串 st := Student{ Name: "张三", Age: 18, gender: "男", } //指针变量 cla := new(Class) cla.Name = "1班" cla.Grade = 3 st.Class=cla //Marshal失败时 err != nil jsonStu, err := json.Marshal(st) if err != nil { fmt.Println("生成json字符串错误") } //jsonStu是[]byte类型,转化成string类型便于查看 fmt.Println(string(jsonStu)) }

    程序输出结果:

    {"name":"张三","Age":18,"class":{"Name":"1班","Grade":3}}

    阅读以上代码可以看出: (1)只要是可导出成员(变量首字母大写),都可以转成 json。因成员变量 gender 是不可导出的,故无法转成 json; (2)如果变量打上了 json 标签,如 Name 旁边的 json:"name" ,那么转化成的 json key 就用该标签 “name”,否则取字段名作为 key,如 “Age”; (3)指针变量,编码时自动转换为它所指向的值,如 Class 变量; (4)强调一句,序列化成功后的 json 字符串是纯粹的字符串。

    2.2 将 map[string]interface{} 序列化为 json

    package main import ( "encoding/json" "fmt" ) func main() { m := make(map[string]interface{}) m["Name"]="张三" m["Age"]=18 m["Gender"]="男" jsonObject := make(map[string]interface{}) jsonObject["Name"]="1班" jsonObject["Grade"]=3 m["Class"]=jsonObject //将 map[string]interface{} 转换为 json sJson, _ := json.Marshal(m) fmt.Printf("sJson=%v\n", string(sJson)) }

    编译运行输出:

    sJson={"Age":18,"Class":{"Grade":3,"Name":"1班"},"Gender":"男","Name":"张三"}

    2.3 一个较为复杂的例子

    假如需要生成如下一个较为复杂的 json:

    { "requests": [{ "positions": [{ "ads": [{ "bid_result": "1", "ecpm": "1.1", "view_id": "Y940raTWuc2bAbPtq1lEc" }, { "bid_result": "2", "ecpm": "2.2", "view_id": "L37Qw!KwBORErDPbViQ" }] }] }] }

    其中,requests 为一个数组,数组的元素是一个 json 对象,该对象只有一个成员 positions;positions 也是一个数组,数组的元素也是一个 json 对象,该对象也只有一个成员 ads;ads 同样还是数组,数组元素还是一个 json 对象。

    2.3.1 使用 struct + slice

    因为在 Golang 中,一个 json 对象可以使用 struct 表示,json 中的数组可以使用 slice 来表示,于是我们可以使用 struct 和 slice 来表示上面的 json。

    package main import ( "encoding/json" "fmt" ) type Request struct{ Requests []RequestValue `json:"requests"` } type RequestValue struct { Positions []PositionValue `json:"positions"` } type PositionValue struct { Ads []AdsValue `json:"ads"` } type AdsValue struct { Bid_result string `json:"bid_result"` Ecpm string `json:"ecpm"` View_id string `json:"view_id"` } func main() { positionValue := PositionValue{ Ads: []AdsValue{ AdsValue{ Bid_result:"1", Ecpm:"1.1", View_id:"Y940raTWuc2bAbPtq1lEc", }, AdsValue{ Bid_result:"2", Ecpm:"1.2", View_id:"L37Qw!KwBORErDPbViQ", }, }, } requestValue := RequestValue{ Positions: []PositionValue{positionValue}, } request := Request{ Requests: []RequestValue{requestValue} } //将 struct 转换为 json sJson, _ := json.Marshal(request) fmt.Printf("sJson=%v\n", string(sJson)) }

    编译运行输出:

    sJson={"requests":[{"positions":[{"ads":[{"bid_result":"1","ecpm":"1.1","view_id":"Y940raTWuc2bAbPtq1lEc"},{"bid_result":"2","ecpm":"1.2","view_id":"L37Qw!KwBORErDPbViQ"}]}]}]}

    2.3.2 使用 map[string]interface{} + []interface{}

    同样地,可以使用 map[string]interface{} 来表示任意的 json,如果元素是数组,可以使用 []interface{}。

    package main import ( "encoding/json" "fmt" ) func main() { //json 对象 adValue := make(map[string]interface{}) adValue["bid_result"]="1" adValue["ecpm"]="1.1" adValue["view_id"]="Y940raTWuc2bAbPtq1lEc" adValue1 := make(map[string]interface{}) adValue1["bid_result"]="2" adValue1["ecpm"]="1.2" adValue1["view_id"]="L37Qw!KwBORErDPbViQ" //json 对象,只有一个成员 ads,且 ads 是一个 json 对象数组 ads := make(map[string]interface{}) ads["ads"]=[]interface{}{adValue, adValue1} //json 对象,只有一个成员 positions,且 positions 是一个 json 对象数组 positions := make(map[string]interface{}) positions["positions"]=[]interface{}{ads} //json 对象,只有一个成员 requests,且 requests 是一个 json 对象数组 requests := make(map[string]interface{}) requests["requests"] = []interface{}{positions} //将 map[string]interface{} 转换为 json sJson, _ := json.Marshal(requests) fmt.Printf("sJson=%v\n", string(sJson)) }

    编译运行输出:

    sJson={"requests":[{"positions":[{"ads":[{"bid_result":"1","ecpm":"1.1","view_id":"Y940raTWuc2bAbPtq1lEc"},{"bid_result":"2","ecpm":"1.2","view_id":"L37Qw!KwBORErDPbViQ"}]}]}]}

    输出结果与使用 struct 相同。相比于 struct,使用 map[string]interface{} 更加的简洁,因为省去了 struct 的定义。


    参考文献

    [1] Golang中文官网.Package json [2] Go的json解析:Marshal与Unmarshal [3] stackoverflow.panic: json: cannot unmarshal array into Go value of type main.Structure [4] Introducing JSON

    最新回复(0)