Json作为如今最流行的数据格式,本文看看如何使用GO处理Json。
解码
先来看示例,访问github api,解析成struct。 curl -s https://api.github.com/users/ThoreauZZ |jq
{
"login": "ThoreauZZ",
"id": 10337273,
"avatar_url": "https://avatars1.githubusercontent.com/u/10337273?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/ThoreauZZ",
"html_url": "https://github.com/ThoreauZZ",
"followers_url": "https://api.github.com/users/ThoreauZZ/followers",
"following_url": "https://api.github.com/users/ThoreauZZ/following{/other_user}",
"gists_url": "https://api.github.com/users/ThoreauZZ/gists{/gist_id}",
"starred_url": "https://api.github.com/users/ThoreauZZ/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/ThoreauZZ/subscriptions",
"organizations_url": "https://api.github.com/users/ThoreauZZ/orgs",
"repos_url": "https://api.github.com/users/ThoreauZZ/repos",
"events_url": "https://api.github.com/users/ThoreauZZ/events{/privacy}",
"received_events_url": "https://api.github.com/users/ThoreauZZ/received_events",
"type": "User",
"site_admin": false,
"name": "thoreau",
"company": null,
"blog": "",
"location": null,
"email": null,
"hireable": null,
"bio": null,
"public_repos": 29,
"public_gists": 0,
"followers": 9,
"following": 4,
"created_at": "2014-12-29T08:15:41Z",
"updated_at": "2017-10-14T14:19:05Z"
}
下面把这个json转成struct,代码如下:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type rstBody struct {
Login string `json:"login"`
Id int `json:"id"`
Gravatar_id string `json:"gravatar_id"`
Url string `json:"url"`
Html_url string `json:"html_url"`
}
func main() {
uri := "https://api.github.com/users/ThoreauZZ"
resp, err := http.Get(uri)
if err != nil {
log.Println("get api error", err)
}
defer resp.Body.Close()
var rst rstBody
err = json.NewDecoder(resp.Body).Decode(&rst)
if err != nil {
log.Println("error", err)
}
fmt.Println(rst)
}
使用http包请求获取body(ReadCloser),使用NewDecoder函数和Decode方法。为了方便,我只解析部分字段。这个特别需要注意的是,rstBody的每个属性首字母必须大写,否则解析器访问不了,就像java对象没有get、set方法一样。但是大写和返回json不匹配。可以使用struct的tag,给每个字段添加元信息,使之和json一一映射。
NewDecoder 函数接受一个实现了 io.Reader 接口类型的作为参数,返回Decoder指针,支持interface参数进行解析。
上面的示例是从Reader中读取数据解析,也可能我们是从一个字符串反序列化。此时使用Unmarshal
函数。
type user struct {
Name string `json:"name"`
Password string `json:"password"`
Age int `json:"age"`
}
var JSON = `{"name":"thoreau","password":"123","age":22}`
var u user
json.Unmarshal([]byte(JSON),&u)
fmt.Println(u)
在第一个示例中,只是写了几个字段映射,如果想全部映射但又不想写struct,可以借助map
var c map[string] interface{}
err = json.NewDecoder(resp.Body).Decode(&c)
if err != nil {
log.Println("error", err)
}
fmt.Println(c)
使用map是灵活,但解析后使用不方便。
编码
还是先看示例,把map转为json:
mymap := make(map[string]interface{})
mymap["name"] ="thoreau"
mymap["password"] ="123"
mymap["age"] =22
data,err :=json.Marshal(mymap)
if err != nil {
fmt.Println("error")
return
}
fmt.Println(string(data))
函数 MarshalIndent 返回一个 byte 切片,用来保存 JSON 字符串和一个 error 。如果想加前缀和indent,可以使用函数MarshalIndent
。
data,err :=json.MarshalIndent(mymap,""," ")
参考: [1]. 《Go语言实战》