golang 開源json庫使用筆記

前言,最近項目中須要動態解析json字符串,可是golang標準庫提供的json須要事先定義好結構體,不太靈活,所以須要調研不依賴於結構體的json庫

目前golang開源json庫各自的優缺點

  • encoding/json, 官方自帶的, 文檔最多, 易用性差, 性能差
  • go-simplejson, gabs, jason等衍生包, 簡單且易用, 易於閱讀, 便於維護, 但性能最差
  • easyjson, ffjson此類包, 適合固定結構的json, 易用性通常, 維護成本高, 性能特別好
  • jsonparser 適合動態和固定結構的json, 簡單且易用, 維護成本低, 性能極好

以性能的高低排序: jsonparser > easyjson > encoding/json > go-simplejson, gabs, jasongit

性能測試, 可見jsonparser的github
buger/jsonparsergithub


golang simplejson使用筆記

  • 介紹:

golang標準庫的json須要預先定義好結構體,而後才能將json字符串轉化爲golang的結構體;simplejson這個開源的庫能夠在不知道json字符串具體結構的狀況下進行編碼和解碼golang

  • 使用:

import (
    simplejson "github.com/bitly/go-simplejson"
)

func case1() {
    //初始化*simpleJson.Json對象
    sj, err := simplejson.NewJson([]byte(jsonStr))

    var v *simpleJson.Json
    
    //獲取字段,若是有多級,能夠層層嵌套獲取
    v = sj.Get(字段名1).Get(字段名2)
    
    //將v的值轉化爲具體類型的值,MustXXX方法必定能夠轉化成功
    //若轉化不成功,則轉化爲該類型的零值
    result := v.MustString()
}

func case2() {
    //檢查某個字段是否存在 
    _, ok := js.Get("字段名1").CheckGet("字段名2") 
    if ok { 
        fmt.Println("存在!") 
    } else { 
        fmt.Println("不存在") 
    }
    
}
  • 總結:

雖然simplejson能夠轉化一個未知的json,但想要獲取到具體的值,仍然須要知道它的類型,這樣最後一步轉換才能成功json

golang jsonparser使用筆記

import "github.com/buger/jsonparser"

...

data := []byte(`{
  "person": {
    "name": {
      "first": "Leonid",
      "last": "Bugaev",
      "fullName": "Leonid Bugaev"
    },
    "github": {
      "handle": "buger",
      "followers": 109
    },
    "avatars": [
      { "url": "https://avatars1.githubusercontent.com/u/14009?v=3&s=460", "type": "thumbnail" }
    ]
  },
  "company": {
    "name": "Acme"
  }
}`)

//根據層級關係取特定的字段名對應的值
jsonparser.Get(data, "person", "name", "fullName")

//若是知道須要取的目標字段的值的類型,能夠使用詳細的GetXXX方法
jsonparser.GetInt(data, "person", "github", "followers")

// When you try to get object, it will return you []byte slice pointer to data containing it
// In `company` it will be `{"name": "Acme"}`
jsonparser.Get(data, "company")

// If the key doesn't exist it will throw an error
var size int64
if value, err := jsonparser.GetInt(data, "company", "size"); err == nil {
  size = value
}

// You can use `ArrayEach` helper to iterate items [item1, item2 .... itemN]
jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
    fmt.Println(jsonparser.Get(value, "url"))
}, "person", "avatars")

// Or use can access fields by index!
jsonparser.GetInt("person", "avatars", "[0]", "url")

// You can use `ObjectEach` helper to iterate objects { "key1":object1, "key2":object2, .... "keyN":objectN }
jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
        fmt.Printf("Key: '%s'\n Value: '%s'\n Type: %s\n", string(key), string(value), dataType)
    return nil
}, "person", "name")

// The most efficient way to extract multiple keys is `EachKey`

paths := [][]string{
  []string{"person", "name", "fullName"},
  []string{"person", "avatars", "[0]", "url"},
  []string{"company", "url"},
}
jsonparser.EachKey(data, func(idx int, value []byte, vt jsonparser.ValueType, err error){
  switch idx {
  case 0: // []string{"person", "name", "fullName"}
    ...
  case 1: // []string{"person", "avatars", "[0]", "url"}
    ...
  case 2: // []string{"company", "url"},
    ...
  }
}, paths...)

詳細解讀

若是隻是單純使用Get,返回值有四個,分別是:數組

value []byte, dataType ValueType, offset int, err error

能夠發現,value是一個[]byte類型,實際取值須要手動將其轉換爲對應的類型;性能

第二個參數是自動推導的類型,支持的推導類型有:測試

const (
      NotExist = ValueType(iota)
      String
      Number
      Object
      Array
      Boolean
      Null 
      Unknown                                              
  )
  • 比較有意思的是,它支持經過索引下標去獲取數組數據
ret, err := jsonparser.GetInt(data, "person", "avatars", "[0]", "index")
  • 能夠遍歷一個key下的全部key的值
err = jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
          fmt.Printf("Key: '%s'\t Value: '%s'\t Type: %s\n", string(key), string(value), dataType)                         
          return nil 
      }, "person", "name")

結果:jsonp

Key: 'first'     Value: 'Leonid'         Type: string
Key: 'last'      Value: 'Bugaev'         Type: string
Key: 'fullName'  Value: 'Leonid Bugaev'  Type: string
  • 若遍歷的key的值不是一個基礎類型的數據,例如:
err = jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
          fmt.Printf("Key: '%s'\t Value: '%s'\t Type: %s\n", string(key), string(value), dataType)
          return nil 
      }, "person")

結果:編碼

Key: 'name'      Value: '{
                "first": "Leonid",
                "last": "Bugaev",
                "fullName": "Leonid Bugaev"
                }'       Type: object
Key: 'github'    Value: '{
                "handle": "buger",
                "followers": 109
                }'       Type: object
Key: 'avatars'   Value: '[
                {"index":100},
                { "url": "https://avatars1.githubusercontent.com/u/14009?v=3&s=460", "type": "thumbnail" },               
                { "url1": "https://avatars2.githubusercontent.com/u/14009?v=3&s=460", "type": "thumbnail" }               
                ]'       Type: array
  • 若須要遍歷一個數組:
_, err = jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, e error) {
          fmt.Printf("each, Value: '%s'\t Type: %s\n", string(value), dataType)
      }, "person", "avatars")

結果url

each, Value: '{"index":100}'     Type: object
each, Value: '{ "url": "https://avatars1.githubusercontent.com/u/14009?v=3&s=460", "type": "thumbnail" }'        Type: object
each, Value: '{ "url1": "https://avatars2.githubusercontent.com/u/14009?v=3&s=460", "type": "thumbnail" }'       Type: object
相關文章
相關標籤/搜索