package main import ( "encoding/json" "fmt" _ "os" ) type Address struct { Type string City string Country string } type Card struct { Name string Age int Addresses []*Address } func main() { pa := &Address{"private", "Shanghai", "China"} pu := &Address{"work", "Beijing", "China"} c := Card{"Xin", 32, []*Address{pa, pu}} js, _ := json.Marshal(c) fmt.Printf("Json: %s", js) }
利用json.Marshal
,可将结构体转为JSON数据:golang
Json: {"Name":"Xin","Age":32,"Addresses":[{"Type":"private","City":"Shanghai","Country":"China"},{"Type":"work","City":"Beijing","Country":"China"}]}
而json.MarshalIndent(c, "", " ")
能够将json代码格式化:web
Json: { "Name": "Xin", "Age": 32, "Addresses": [ { "Type": "private", "City": "Shanghai", "Country": "China" }, { "Type": "work", "City": "Beijing", "Country": "China" } ] }
json.MarshalforHTML()
函数,会对数据执行HTML转码。若是事先知道 JSON 数据的结构,能够事先定义一个结构来存储反序列化后的结果。如,对这样一段 json:json
b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`)
咱们定义这样一个数据结构:数组
type FamilyMember struct { Name string Age int Parents []string }
而后能够将其反序列化:缓存
var m FamilyMember err := json.Unmarshal(b, &m)
完整的程序:数据结构
package main import ( "encoding/json" "fmt" ) type FamilyMember struct { Name string Age int Parents []string } func main() { b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`) var m FamilyMember // json.Unmarshal 用于解码 json 串 err := json.Unmarshal(b, &m) if err == nil { fmt.Printf("name: %s\nAge: %d\nParents: %v\n", m.Name, m.Age, m.Parents) } }
执行后输出:ide
name: Wednesday Age: 6 Parents: [Gomez Morticia]
json 包使用 map[string]interface{} 和 []interface{} 储存任意的 JSON 对象和数组。一样是上面的 JSON 串:函数
b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`)
用下面的代码进行解码:ui
var f interface{} err := json.Unmarshal(b, &f)
会获得:编码
map[string]interface{} { "Name": "Wednesday", "Age": 6, "Parents": []interface{} { "Gomez", "Morticia", }, }
对于这类的数据,可使用switch
来判断节点的类型来遍历数据。
Golang中使用 fmt.Sprintf 格式化 `JSON Data %s %d %f` 动态变动JSON数据.
其等效做用是, 采用struct转换, 更改结构体数据, 而后Marshal成JSON, 用于 http处理
const jsonRes = ` { "server": { "name": "ty", "imageRef": "f9436296-854f-4fe2-939d-eb667b245b78", "fmtSprintf": "%s", "max_count": 1, "min_count": 1, "networks": [ { "uuid": "1e16b87f-ef66-4f0d-ba3d-d93234159076" } ], "metadata": { "ENV1": "100", "ENV2": "1000", "entrypoint": "/bin/sh -c 'while true; do echo hello world; sleep 99999d; done'" } } } `
func fmtSprintfJson() error { //var datm map[string]interface{} var datm interface{} const jsonRes = ` { "server": { "name": "ty", "imageRef": "f9436296-854f-4fe2-939d-eb667b245b78", "fmtSprintf": "%s", "max_count": 1, "min_count": 1, "networks": [ { "uuid": "1e16b87f-ef66-4f0d-ba3d-d93234159076" } ], "metadata": { "ENV1": "100", "ENV2": "1000", "entrypoint": "/bin/sh -c 'while true; do echo hello world; sleep 99999d; done'" } } } ` jsonResSprintf := fmt.Sprintf(jsonRes, "test") fmt.Println("jsonResSprintf = ", jsonResSprintf) err := json.Unmarshal([]byte(jsonResSprintf), &datm) if err != nil { fmt.Println("json.Unmarshal([]byte(json), createRequests) , Error : ", err) return err } fmt.Println("struct request = ", datm) return nil}
上面全部的 JSON 数据来源都是预先定义的 []byte
缓存,在不少时候,若是能读取/写入其余地方的数据就行了。encoding/json
库中有两个专门处理这个事情的结构:Decoder
和 Encoder
:
// Decoder 从 r io.Reader 中读取数据,`Decode(v interface{})` 方法把数据转换成对应的数据结构 func NewDecoder(r io.Reader) *Decoder // Encoder 的 `Encode(v interface{})` 把数据结构转换成对应的 JSON 数据,而后写入到 w io.Writer 中 func NewEncoder(w io.Writer) *Encoder
下面的例子就是从标准输入流中读取数据,解析成数据结构,删除全部键不是 Name
的字段,而后再 encode 成 JSON 数据,打印到标准输出。
package main import ( "encoding/json" "log" "os" ) func main() { dec := json.NewDecoder(os.Stdin) enc := json.NewEncoder(os.Stdout) for { var v map[string]interface{} if err := dec.Decode(&v); err != nil { log.Println(err) return } for k := range v { if k != "Name" { delete(v, k) } } if err := enc.Encode(&v); err != nil { log.Println(err) } } }
在定义 struct 字段的时候,能够在字段后面添加 tag,来控制 encode/decode 的过程:是否要 decode/encode 某个字段,JSON 中的字段名称是什么。
能够选择的控制字段有三种:
-
:不要解析这个字段omitempty
:当字段为空(默认值)时,不要解析这个字段。好比 false、0、nil、长度为 0 的 array,map,slice,stringFieldName
:当解析 json 的时候,使用这个名字举例来讲吧:
// 解析的时候忽略该字段。默认状况下会解析这个字段,由于它是大写字母开头的 Field int `json:"-"` // 解析(encode/decode) 的时候,使用 `other_name`,而不是 `Field` Field int `json:"other_name"` // 解析的时候使用 `other_name`,若是struct 中这个值为空,就忽略它 Field int `json:"other_name,omitempty"`
在解析的时候,还能够把某部分先保留为 JSON 数据不要解析,等到后面获得更多信息的时候再去解析。继续拿 User
举例,好比咱们要添加认证的信息,认证能够是用户名和密码,也能够是 token 认证。
type BasicAuth struct { Email string Password string } type TokenAuth struct { Token string } type User struct { Name string IsAdmin bool Followers uint Auth json.RawMessage }
咱们在定义 User
结构体的时候,把认证字段的类型定义为 json.RawMessage
,这样解析 JSON 数据的时候,对应的字段会先不急着转换成 Go 数据结构。而后咱们能够本身去再次调用 Unmarshal
去读取里面的值:
data := []byte(`{"Name":"cizixs","IsAdmin":true,"Followers":36}`)err := json.Unmarshal(data, &basicAuth)if basicAuth.Email != "" { // 这是用户名/密码认证方式,在这里继续作一些处理} else { json.Unmarshal(data, &tokenAuth) if tokenAuth.Token != "" { // 这是 token 认证方法 }}
若是但愿本身控制怎么解析成 JSON,或者把 JSON 解析成自定义的类型,只须要实现对应的接口(interface)。encoding/json
提供了两个接口:Marshaler
和 Unmarshaler
:
// Marshaler 接口定义了怎么把某个类型 encode 成 JSON 数据 type Marshaler interface { MarshalJSON() ([]byte, error) } // Unmarshaler 接口定义了怎么把 JSON 数据 decode 成特定的类型数据。若是后续还要使用 JSON 数据,必须把数据拷贝一份 type Unmarshaler interface { UnmarshalJSON([]byte) error }
标准库 time.Time
就实现了这两个接口。另一个简单的例子(这个例子来自于参考资料中 Go and JSON 文章):
type Month struct { MonthNumber int YearNumber int } func (m Month) MarshalJSON() ([]byte, error){ return []byte(fmt.Sprintf("%d/%d", m.MonthNumber, m.YearNumber)), nil } func (m *Month) UnmarshalJSON(value []byte) error { parts := strings.Split(string(value), "/") m.MonthNumber = strconv.ParseInt(parts[0], 10, 32) m.YearNumber = strconv.ParseInt(parts[1], 10, 32) return nil }