golang json庫gjson的使用

來源:互聯網
上載者:User

官方的json庫, 只支援整體的序列化與還原序列化. 像其它語言的庫, json庫都支援單個getValue/setValue這類操作.
找了下golang相關的開源json庫, GJSON star數不錯,支援的查詢功能很豐富. 但是沒有寫入介面. 找了一圈也沒有
找到有寫入功能的json庫. 能想到的只有定義類型序列化或map序列化了. 以下是本文, 翻譯自項目readme:

開始

開始使用GJSON之前, 先安裝Go, 然後運行go get:

$ go get -u github.com/tidwall/gjson

擷取值

Get查詢指定路徑, 通過.來區分. 比如"name.last"或者"age". 如果找到了匹配路徑, 將返回結果.

package mainimport "github.com/tidwall/gjson"const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`func main() {    value := gjson.Get(json, "name.last")    println(value.String())}

輸出結果:

Prichard

同時有 GetMany 方法批量擷取值, 也有 GetBytes 方法擷取位元組切片.

路徑解析

路徑是一系列被.分隔的key拼接而成.
路徑可能包含萬用字元'*'和'?'.
通過下標訪問數組值.
通過'#'來擷取值在元素中的排位或訪問子路徑.
.和萬用字元可以通過'\'來轉義.

{  "name": {"first": "Tom", "last": "Anderson"},  "age":37,  "children": ["Sara","Alex","Jack"],  "fav.movie": "Deer Hunter",  "friends": [    {"first": "Dale", "last": "Murphy", "age": 44},    {"first": "Roger", "last": "Craig", "age": 68},    {"first": "Jane", "last": "Murphy", "age": 47}  ]}
"name.last"          >> "Anderson""age"                >> 37"children"           >> ["Sara","Alex","Jack"]"children.#"         >> 3"children.1"         >> "Alex""child*.2"           >> "Jack""c?ildren.0"         >> "Sara""fav\.movie"         >> "Deer Hunter""friends.#.first"    >> ["Dale","Roger","Jane"]"friends.1.last"     >> "Craig"

你同樣能通過#[...]來查詢數組中的第一個匹配的項, 或通過'#[...]#'查詢所有匹配的項.
查詢支援==, !=, <, <=, >, >=比較子和'%'模糊比對.

friends.#[last=="Murphy"].first    >> "Dale"friends.#[last=="Murphy"]#.first   >> ["Dale","Jane"]friends.#[age>45]#.last            >> ["Craig","Murphy"]friends.#[first%"D*"].last         >> "Murphy"

JSON 行

同樣支援JSON Lines, 使用 .. 首碼, 把多行文檔視作數組.

比如:

{"name": "Gilbert", "age": 61}{"name": "Alexa", "age": 34}{"name": "May", "age": 57}{"name": "Deloise", "age": 44}
..#                   >> 4..1                   >> {"name": "Alexa", "age": 34}..3                   >> {"name": "Deloise", "age": 44}..#.name              >> ["Gilbert","Alexa","May","Deloise"]..#[name="May"].age   >> 57

ForEachLines 方法可以迭代json.

gjson.ForEachLine(json, func(line gjson.Result) bool{    println(line.String())    return true})

Result Type

GJSON支援json類型包括 string, number, bool, and null. 數組和對象被擋住基礎類型返回.

Result 持有如下其中一種類型:

bool, for JSON booleansfloat64, for JSON numbersstring, for JSON string literalsnil, for JSON null

直接存取value:

result.Type    // can be String, Number, True, False, Null, or JSONresult.Str     // holds the stringresult.Num     // holds the float64 numberresult.Raw     // holds the raw jsonresult.Index   // index of raw value in original json, zero means index unknown

有各種各樣的方便的函數可以擷取結果:

result.Exists() boolresult.Value() interface{}result.Int() int64result.Uint() uint64result.Float() float64result.String() stringresult.Bool() boolresult.Time() time.Timeresult.Array() []gjson.Resultresult.Map() map[string]gjson.Resultresult.Get(path string) Resultresult.ForEach(iterator func(key, value Result) bool)result.Less(token Result, caseSensitive bool) bool

result.Value() 方法返回 interface{} Go基本類型之一.

result.Array() 方法返回一組值.
如果結果是不存在的值, 將會返回空數組.
如果結果不是JSON數組, 將會返回只包含一個值的數組.

boolean >> boolnumber  >> float64string  >> stringnull    >> nilarray   >> []interface{}object  >> map[string]interface{}

64-bit integers

result.Int()result.Uint() 返回的是64位大數字.

result.Int() int64    // -9223372036854775808 to 9223372036854775807result.Uint() int64   // 0 to 18446744073709551615

讀取嵌套數組

假如你想從下列json擷取所有的lastName:

{  "programmers": [    {      "firstName": "Janet",       "lastName": "McLaughlin",     }, {      "firstName": "Elliotte",       "lastName": "Hunter",     }, {      "firstName": "Jason",       "lastName": "Harold",     }  ]}

你可以使用如下路徑programmers.#.lastName:

result := gjson.Get(json, "programmers.#.lastName")for _, name := range result.Array() {    println(name.String())}

你同樣能擷取數組裡的對象:

name := gjson.Get(json, `programmers.#[lastName="Hunter"].firstName`)println(name.String())  // prints "Elliotte"

對象或數組迭代

ForEach方法允許你快速的迭代對象或數組.
key和value被傳遞給對象的迭代器函數.
只有value被傳遞給數組. 迭代器返回false將會終止迭代.

簡易的Parse和Get

Parse(json)方法可以簡單的分析json, result.Get(path)查詢結果.

比如, 下面的幾種情況都將返回相同的結果:

gjson.Parse(json).Get("name").Get("last")gjson.Get(json, "name").Get("last")gjson.Get(json, "name.last")

檢查value是否存在

有時你想要知道值是否存在.

value := gjson.Get(json, "name.last")if !value.Exists() {    println("no last name")} else {    println(value.String())}// Or as one stepif gjson.Get(json, "name.last").Exists() {    println("has a last name")}

驗證JSON

Get*Parse* 方法預期json格式是正常的, 如果不正常, 將會返回不可預料的結果.

如果你讀取的json來源不可預料, 那麼你可以通過GJSON這麼事先驗證.

if !gjson.Valid(json) {    return errors.New("invalid json")}value := gjson.Get(json, "name.last")

還原序列化到map

還原序列化到map[string]interface{}:

m, ok := gjson.Parse(json).Value().(map[string]interface{})if !ok {    // not a map}## 處理Bytes如果你的JSON包含位元組數組切片, 與其調用`Get(string(data), path)`, 不如調用[GetBytes](https://godoc.org/github.com/tidwall/gjson#GetBytes)方法更優.```govar json []byte = ...result := gjson.GetBytes(json, path)

如果你在使用gjson.GetBytes(json, path)方法, 並且你想避免從result.Raw 轉換到 []byte, 你可以使用這種模式:

var json []byte = ...result := gjson.GetBytes(json, path)var raw []byteif result.Index > 0 {    raw = json[result.Index:result.Index+len(result.Raw)]} else {    raw = []byte(result.Raw)}

這是最好的模式, 不會為子切片重新分配記憶體. 這個模式使用了result.Index欄位, 它直接指向了raw data所處原來json中的位置.
如果result.Raw是轉換成[]byte的, result.Index將會為0.

一次擷取多個值

GetMany方法可以用於同時擷取多個值.

results := gjson.GetMany(json, "name.first", "name.last", "age")

傳回值是[]Result類型, 總是返回正傳入路徑個數的數量.

效能

測試了GJSON以及 encoding/json,
ffjson,
EasyJSON,
jsonparser,
and json-iterator

BenchmarkGJSONGet-8                  3000000        372 ns/op          0 B/op         0 allocs/opBenchmarkGJSONUnmarshalMap-8          900000       4154 ns/op       1920 B/op        26 allocs/opBenchmarkJSONUnmarshalMap-8           600000       9019 ns/op       3048 B/op        69 allocs/opBenchmarkJSONDecoder-8                300000      14120 ns/op       4224 B/op       184 allocs/opBenchmarkFFJSONLexer-8               1500000       3111 ns/op        896 B/op         8 allocs/opBenchmarkEasyJSONLexer-8             3000000        887 ns/op        613 B/op         6 allocs/opBenchmarkJSONParserGet-8             3000000        499 ns/op         21 B/op         0 allocs/opBenchmarkJSONIterator-8              3000000        812 ns/op        544 B/op         9 allocs/op

使用的JSON:

{  "widget": {    "debug": "on",    "window": {      "title": "Sample Konfabulator Widget",      "name": "main_window",      "width": 500,      "height": 500    },    "image": {       "src": "Images/Sun.png",      "hOffset": 250,      "vOffset": 250,      "alignment": "center"    },    "text": {      "data": "Click Here",      "size": 36,      "style": "bold",      "vOffset": 100,      "alignment": "center",      "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"    }  }}    

每個操作都是在以下的搜尋路徑中進行旋轉的:

widget.window.namewidget.image.hOffsetwidget.text.onMouseUp

這些基準是在MacBook Pro 15" 2.8 GHz英特爾酷睿i7上啟動並執行, 使用Go 1.8, 可以找到. here.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.