build-web-application-with-golang
接下来的例子以下面XML描述的信息进行操作。
{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}
我们用Go的JSON包中有如下函数解析json数据
func Unmarshal(data []byte, v interface{}) error具体代码如下:
package main import ( "encoding/json" "fmt" ) type Server struct { ServerName string ServerIP string } type Serverslice struct { Servers []Server } 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) }和解析XML一样,在这里的而问题仍是go 在解析的时候,如何将json数据与struct字段相匹配呢?以json的key为Foo说明如下规则。
- 首先查找tag含有
Foo
的可导出的struct字段(首字母大写) - 其次查找字段名是
Foo
的导出字段 - 最后查找类似
FOO
或者FoO
这样的除了首字母之外其他大小写不敏感的导出字段
解析到interface
上面那种解析方式是在我们知晓被解析的JSON数据的结构的前提下采取的方案。
但有些情况总是很烦人的,额,一些情况下我们只知道有一段json数据要解析,但是并不知道这段json的具体内容。这是我们就采用下面的方法来做。
由于interface{}可以用来存储任意数据类型的对象,所以这种数据结构正好用于存储解析的未知结构的json数据的结果。JSON包中采用map[string]interface{}和[]interface{}结构来存储任意的JSON对象和数组。Go类型和JSON类型的对应关系如下:
- bool 代表 JSON booleans,
- float64 代表 JSON numbers,
- string 代表 JSON strings,
- nil 代表 JSON null
b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)如果在我们不知道他的结构的情况下,我们把他解析到interface{}里面
var f interface{} err := json.Unmarshal(b, &f)这个时候f里面存储了一个map类似,他们的key是string,值存储在空的interface{}里
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 []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")
}
}
面这个是官方提供的解决方案,其实很多时候我们通过类型断言,操作起来不是很方便,目前bitly公司开源了一个叫做simplejson
的包,在处理未知结构体的JSON时相当方便,详细例子如下所示:
js, err := NewJson([]byte(`{
"test": {
"array": [1, "2", 3],
"int": 10,
"float": 5.150,
"bignum": 9223372036854775807,
"string": "simplejson",
"bool": true
}
}`))
arr, _ := js.Get("test").Get("array").Array()
i, _ := js.Get("test").Get("int").Int()
ms := js.Get("test").Get("string").MustString()
可以看到,使用这个库操作JSON比起官方包来说,简单的多,详细的请参考如下地址:
https://github.com/bitly/go-simplejson(但是用这种方法的时候,在导包的时候老是出错。额,我也是刚接触go)
生成JSON
生成json就更简单了,用json包中的Marshal(v interface{})函数,定义如下func Marshal(v interface{}) ([]byte, error)
以下是具体代码
package main import ( "encoding/json" "fmt" ) type Server struct { ServerName string ServerIP string } type Serverslice struct { Servers []Server } 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)) }输出:
{"Servers":[{"ServerName":"Shanghai_VPN","ServerIP":"127.0.0.1"},{"ServerName":"Beijing_VPN","ServerIP":"127.0.0.2"}]}
需要注意的是:
结构体的字段必须是可导出的。
Marshal函数只有在转换成功的时候才会返回数据,在转换的过程中我们需要注意几点:
- JSON对象只支持string作为key,所以要编码一个map,那么必须是map[string]T这种类型(T是Go语言中任意的类型)
- Channel, complex和function是不能被编码成JSON的
- 嵌套的数据是不能编码的,不然会让JSON编码进入死循环
- 指针在编码的时候会输出指针指向的内容,而空指针会输出null
有疑问加站长微信联系(非本文作者)