通常使用Golangencoding/json标准库可以方便的编码/解析JSON数据,但是前提需要定义struct数据结构。特别是解析未知结构的JSON数据时,原有方法很难满足需求了,本文主要介绍动态解析JSON格式。

1、传统方法
比如User数据结构如下:

type User struct {
    Name string `json:"name"`
    Age int     `json:"age"`
}

在定义struct字段的时候,可以在字段后面添加tag,来控制encode/decode的过程:是否要 decode/encode 某个字段,JSON 中的字段名称是什么。字段名首字母控制字段的可见性,若要输出到JSON,首字母需要大写。
三种tag:
-:不要解析这个字段
omitempty:当字段为空(默认值)时,不要解析这个字段。比如 false、0、nil、长度为 0 的 array,map,slice,string
FieldName:当解析 json 的时候,使用这个名字

举例来说吧:

// 解析的时候忽略该字段。默认情况下会解析这个字段,因为它是大写字母开头的
Field int   `json:"-"`
// 解析(encode/decode) 的时候,使用 `other_name`,而不是 `Field`
Field int   `json:"other_name"`
// 解析的时候使用 `other_name`,如果struct 中这个值为空,就忽略它
Field int   `json:"other_name,omitempty"`

(1)encode

user := User{Name: "test", Age:23}
data, err := json.Marshal(user)
if err != nil {
    fmt.Println(string(data))
}

data 就是 []byte 类型的数组,里面包含了解析为 JSON 之后的数据,可以使用string(data)转型为string。
(2)decode
要把JSON数据转换成Go类型的值(Decode),可以使用json.Unmarshal

var user User
err = json.Unmarshal(data, &user)
if err != nil {
    fmt.Errorf("Can not decode data: %v\n", err)
}

2、动态解析
动态JSON结构未知,若使用前面方法需要事先定义数据结构,这与PHP/Python JSON处理非常不同。若不考虑性能,使用simplejson。
(1)simplejson

js, err := simplejson.NewJson([]byte(`{
    "test": {
      "string_array": ["asdf", "zxcv"],
      "array": [1, "2", 3],
      "arraywithsubs": [{"subkeyone": 1},
      "bignum": 9223372036854775807,
      "string": "simplejson",
      "bool": true
    }
  }`))
  if err != nil {
     panic("json format error")
  }
  //获取某个字段值
  s, err := js.Get("test").Get("string").String()
  if err != nil {
      panic(err)
  }
  fmt.Println(s)
  //检查某个字段是否存在
  _, ok := js.Get("test").CheckGet("string2")
  if ok {
      fmt.Println("存在!")
  } else {
      fmt.Println("不存在")
  }

(2)interface
比如JSON有以下两种类型:

{"Type":"sound","Msg":{"Description":"dynamite","Authority":"the Bruce Dickinson"}}
{"Type":"cowbell","Msg":{"More":true}}

Msg具体什么类型实现无法判断,Msg being a map[string]interface{}

type Envelope struct {
    Type string
    Msg  interface{}
}

var env Envelope
if err := json.Unmarshal([]byte(input), &env); err != nil {
        log.Fatal(err)
    }
// for the love of Gopher DO NOT DO THIS
var desc string = env.Msg.(map[string]interface{})["description"].(string)
fmt.Println(desc)

参考:
https://godoc.org/github.com/bitly/go-simplejson
https://gocn.io/question/548
http://www.cnblogs.com/bvac/p/6293667.html
http://eagain.net/articles/go-dynamic-json/

标签: golang, json

评论已关闭