Go语言8-Json

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语言实战》

CONTENTS