文章目录
- 1.解析 JSON
- 1.1 map[string]any 存储 json
- 1.2 struct 存储 json
- 1.3 []map[string]any 解析 json 数组
- 2.生成 JSON
- 2.1 struct 序列化为 json
- 2.2 map[string]any 序列化为 json
- 2.3 一个较为复杂的例子
- 2.3.1 使用 struct + slice
- 2.3.2 使用 map[string]any + []any
- 参考文献
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]any 存储 json
给一个较为复杂的 json 字符串,包含数组,数组的元素是 json 对象。我们需要取出数组第一个元素中的某一个字段值。其它的解析均可参考下面的代码。
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonStr := []byte(`{"uin":1589276509,"feedID":10000,"videos":[{"picture":"/","duration":"839"}]}`)
var jsonMap map[string]any
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.([]iany); ok {
if mapValue, ok := sliceValue[0].(map[string]any); ok {
if duration, ok := mapValue["duration"]; ok {
fmt.Printf("d=%v,type=%T\n", duration, duration)
}
}
}
}
}
程序输出:
value=[]interface {}{map[string]interface {}{"picture":"/", "duration":"839"}}
d=839,type=string
解析 json 字符串时,需要注意如下几点:
(1)Golang 类型和 JSON 类型的对应关系如下:
map[string]any 代表 JSON 对象
[]any 代表 JSON 数组
bool 代表 JSON boolean
float64 代表 JSON number
string 代表 JSON string
nil 代表 JSON null
1.2 struct 存储 json
如果我们事先知道 JSON 串,那么可以指定具体的 struct 来存储解析后的 json。可以通过在线工具Golang: Convert JSON to Struct快速将 JOSN 转为 Go struct。
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("() failed, err=%v data=%s\n", err, data)
return
}
fmt.Printf("jsonMap=%#v\n", feedsInfo)
}
编译运行输出:
jsonMap=[]{{Title:"它才是“天然补血王”,女性隔三差五吃,美容驻颜,气色更红润", Score:4, AiKongbuLevel:0, AiDisuLevel:0, AiBiaotidangLevel:1, AiUnsocialLevel:0}, {Title:"7岁的火星男孩,顺利通过测谎仪,现在为何消失不见了?", Score:4, AiKongbuLevel:0, AiDisuLevel:0, AiBiaotidangLevel:0, AiUnsocialLevel:0}}
1.3 []map[string]any 解析 json 数组
如果 json 字符串是一个 json 数组,除了可以使用 struct 来解析,也可以使用 []map[string]any来解析。
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]any
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]any 或者 struct 来存储解析后的数据。同样地,我们可以将任意 Golang 对象序列化为 JSON。
Golang 中,JSON 对象表示主要有两种方式,一种是 struct,另一种是 map[string]any。在表示数组时,分别使用具体类型的切片和任意类型的切片 []any。
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]any 序列化为 json
package main
import (
"encoding/json"
"fmt"
)
func main() {
m := make(map[string]any)
m["Name"]="张三"
m["Age"]=18
m["Gender"]="男"
jsonObject := make(map[string]any)
jsonObject["Name"]="1班"
jsonObject["Grade"]=3
m["Class"]=jsonObject
//将 map[string]any 转换为 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]any + []any
同样地,可以使用 map[string]any 来表示任意的 json,如果元素是数组,可以使用 []any。
package main
import (
"encoding/json"
"fmt"
)
func main() {
//json 对象
adValue := make(map[string]any)
adValue["bid_result"]="1"
adValue["ecpm"]="1.1"
adValue["view_id"]="Y940raTWuc2bAbPtq1lEc"
adValue1 := make(map[string]any)
adValue1["bid_result"]="2"
adValue1["ecpm"]="1.2"
adValue1["view_id"]="L37Qw!KwBORErDPbViQ"
//json 对象,只有一个成员 ads,且 ads 是一个 json 对象数组
ads := make(map[string]any)
ads["ads"]=[]any{adValue, adValue1}
//json 对象,只有一个成员 positions,且 positions 是一个 json 对象数组
positions := make(map[string]any)
positions["positions"]=[]any{ads}
//json 对象,只有一个成员 requests,且 requests 是一个 json 对象数组
requests := make(map[string]any)
requests["requests"] = []any{positions}
//将 map[string]any 转换为 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]any 更加的简洁,因为省去了 struct 的定义。
参考文献
Go的json解析:Marshal与Unmarshal
: json: cannot unmarshal array into Go value of type
Introducing JSON -