{
"servers":[
{
"serverName":"Shanghai_VPN",
"serverIP":"127.0.0.1"
},
{
"serverName":"Beijing_VPN",
"serverIP":"127.0.0.2"
}
]
}
解析 json
解析到 struct
func main() {
var s Serverslice
str := `{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}`
json.Unmarshal([]byte(str), &s)
fmt.Println(s)
}
type Server struct {
ServerName string
ServerIP string
}
type Serverslice struct {
Servers []Server
}
{[{Shanghai_VPN 127.0.0.1} {Beijing_VPN 127.0.0.2}]}
在解析的时候,如何将 json 数据与 struct 字段相匹配呢?例如 json 的 key 是 Foo,那么怎么找对应的字段呢?
- 首先查找 tag 含有
Foo可导出字段(首字母大写); - 其次查找字段名是
Foo的可导出字段; - 最后查找类似
FOO或者FoO这样的除了首字母之外其他大小写不敏感的可导出字段;
解析到 interface
如果不知道被解析的数据的格式,又应该如何来解析呢?
interface{} 可以用来存储任意数据类型的对象,JSON 包中采用 map[string]interface{} 和 []interface{} 结构来存储任意的 json 对象和数组。
func main() {
b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
var f interface{}
_ = json.Unmarshal(b, &f)
// f = map[string]interface{}{
// "Name": "Wednesday",
// "Age": 6,
// "Parents": []interface{}{
// "Gomez",
// "Morticia",
// },
// }
m := f.(map[string]interface{})
for k, v := range m {
switch vv := v.(type) {
case string:
fmt.Println(k, "is string", vv)
case int:
fmt.Println(k, "is int", vv)
case float64:
fmt.Println(k, "is float64", vv)
case []interface{}:
fmt.Println(k, "is an array:")
for i, u := range vv {
fmt.Println(i, u)
}
default:
fmt.Println(k, "is of a type I don't know how to handle")
}
}
}
Parents is an array:
0 Gomez
1 Morticia
Name is string Wednesday
Age is float64 6
生成 json
func main() {
var s Serverslice
s.Servers = append(s.Servers, Server{ServerName: "Shanghai_VPN", ServerIP: "127.0.0.1"})
s.Servers = append(s.Servers, Server{ServerName: "Beijing_VPN", ServerIP: "127.0.0.2"})
b, err := json.Marshal(s)
if err != nil {
fmt.Println("json err:", err)
}
fmt.Println(string(b))
}
type Server struct {
ServerName string `json:"server_name"`
ServerIP string `json:"server_ip"`
}
type Serverslice struct {
Servers []Server `json:"servers"`
}
{"servers":[{"server_name":"Shanghai_VPN","server_ip":"127.0.0.1"},{"server_name":"Beijing_VPN","server_ip":"127.0.0.2"}]}
如果字段类型是 bool、string、int 或 int64 等,而 tag 中带有 ",string" 选项,那么这个字段在输出到 json 的时候会把该字段对应的值转换成 json 字符串。
type Server struct {
// ID 不会导出到 JSON 中
ID int `json:"-"`
ServerName string `json:"serverName"`
// ServerName2 的值会进行二次 JSON 编码
ServerName2 string `json:"serverName2,string"`
// 如果 ServerIP 为空,则不输出到 json 串中
ServerIP string `json:"serverIP,omitempty"`
}
s := Server{
ID: 3,
ServerName: `Go "1.0" `,
ServerName2: `Go "1.0" `,
ServerIP: ``,
}
b, _ := json.Marshal(s)
os.Stdout.Write(b)
{"serverName":"Go \"1.0\" ","serverName2":"\"Go \\\"1.0\\\" \""}
Marshal 函数只有在转换成功的时候才会返回数据,在转换的过程中需要注意几点:
- json 对象只支持
string作为 key,所以要编码一个 map,那么必须是map[string]T这种类型; channel、complex或function是不能被编码成 json 的;- 嵌套的数据是不能编码的,不然会让 json 编码进入死循环;
- 指针在编码的时候会输出指针指向的内容,而空指针会输出 null;
编码和解码流
json 包提供 Decoder 和 Encoder 类型来支持常用 JSON 数据流读写。NewDecoder 和 NewEncoder 函数分别封装了 io.Reader 和 io.Writer 接口。
func NewEncoder(w io.Writer) *Encoder
func (enc *Encoder) Encode(v interface{}) error
要想把 JSON 直接写入文件,可以使用 json.NewEncoder 初始化文件(或者任何实现 io.Writer 的类型),并调用 Encode();反过来与其对应的是使用 json.NewDecoder 和 Decode() 函数。
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Decode(v interface{}) error
import (
"encoding/json"
"fmt"
"log"
"os"
)
type Address struct {
Type string
City string
Country string
}
type VCard struct {
FirstName string
LastName string
Addresses []*Address
Remark string
}
func main() {
pa := &Address{"private", "Aartselaar", "Belgium"}
wa := &Address{"work", "Boom", "Belgium"}
vc := VCard{"Jan", "Kersschot", []*Address{pa, wa}, "none"}
// fmt.Printf("%v: \n", vc) // {Jan Kersschot [0x126d2b80 0x126d2be0] none}:
// JSON format:
js, _ := json.Marshal(vc)
fmt.Printf("JSON format: %s", js)
// using an encoder:
file, _ := os.OpenFile("vcard.json", os.O_CREATE|os.O_WRONLY, 0666)
defer file.Close()
enc := json.NewEncoder(file)
err := enc.Encode(vc)
if err != nil {
log.Println("Error in encoding json")
}
}