go-web编程之处理json

摘抄自astaxie的开源书籍

 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
现在我们假设有如下的JSON数据


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

本文来自:开源中国博客

感谢作者:梁援-晋

查看原文:go-web编程之处理json

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。