Go 每日一庫之 sjson

簡介

在上一篇文章中我們介紹瞭如何使用gjson快速讀取 JSON 串中的值。為了內容的完整性,今天我們介紹一下如何使用sjson快速設置 JSON 串中的值。

快速使用

先安裝:

<code>$ go 

get

github.com/tidwall/sjson 複製代碼/<code>

後使用:

<code>

package main

import

(

"fmt"

"github.com/tidwall/sjson"

)

const

json = `{

"name"

:{

"first"

:

"li"

,

"last"

:

"dj"

},

"age"

:

18

}`

func

main

(

) {

value

, _ := sjson.Set(json,

"name.last"

,

"dajun"

) fmt.Println(

value

) } 複製代碼/<code>

上面代碼通過sjson.Set()將 JSON 串中name.last對應的值設置為dajun。與gjson一樣,sjson也通過鍵路徑指定具體的位置,鍵路徑即為一系列以.分隔的鍵。sjson支持的鍵路徑語法是gjson的一個子集,具體鍵路徑的語法可以參見上一篇文章。sjson.Set()返回設置之後的 JSON 串。最終程序輸出:

<code>{

"name"

:{

"first"

:

"li"

,

"last"

:

"dajun"

},

"age"

:18} 複製代碼/<code>

支持的類型

sjson支持的類型包括nil/bool/int/float/string等。如果傳入sjson不支持的類型,sjson會調用json.Marshal,然後將生成的字符串設置到對應的鍵路徑上:

<code>

type

User

struct

{ Name

string

`json:"name"`

Age

int

`json:"age"`

}

func

main

()

{ nilJSON, _ := sjson.Set(

""

,

"key"

,

nil

) fmt.Println(nilJSON) boolJSON, _ := sjson.Set(

""

,

"key"

,

false

) fmt.Println(boolJSON) intJSON, _ := sjson.Set(

""

,

"key"

,

1

) fmt.Println(intJSON) floatJSON, _ := sjson.Set(

""

,

"key"

,

10.5

) fmt.Println(floatJSON) strJSON, _ := sjson.Set(

""

,

"key"

,

"hello"

) fmt.Println(strJSON) mapJSON, _ := sjson.Set(

""

,

"key"

,

map

[

string

]

interface

{}{

"hello"

:

"world"

}) fmt.Println(mapJSON) u := User{Name:

"dj"

, Age:

18

} structJSON, _ := sjson.Set(

""

,

"key"

, u) fmt.Println(structJSON) } 複製代碼/<code>

注意,我們傳入一個空字符串,sjson.Set()會生成一個空對象,然後按照鍵路徑依次設置值。下面分析上述程序輸出:

  • nil:在 JSON 中用null表示,輸出{"key":null};
  • false:在 JSON 中布爾值用true/false表示,輸出{"key":false};
  • 1和10.5:整數和浮點數在 JSON 中都用number表示,分別輸出{"key":1}和{"key":10.5};
  • hello:輸出{"key":"hello"};
  • map[string]interface{}:sjson並不原生支持map類型,故通過json.Marshal將其序列化為{"hello":"world"}再設置到鍵key上,輸出{"key":{"hello":"world"}};
  • User對象:先通過json.Marshal序列化為{"name":"dj","age":18}再設置;

修改數組

修改數組可以通過在鍵路徑後添加索引,有兩種特殊情況:

  • 使用-1或數組長度為索引表示在數組後添加一個新元素;
  • 使用的索引超出數組的長度,會在數組中添加很多null值。

看下面示例:

<code>

func

main

()

{ fruits := `{

"fruits"

:[

"apple"

,

"orange"

,

"banana"

]}`

var

newValue string newValue,

_

= sjson.

Set

(fruits,

"fruits.1"

,

"grape"

) fmt.

Println

(newValue) newValue,

_

= sjson.

Set

(fruits,

"fruits.3"

,

"pear"

) fmt.

Println

(newValue) newValue,

_

= sjson.

Set

(fruits,

"fruits.-1"

,

"strawberry"

) fmt.

Println

(newValue) newValue,

_

= sjson.

Set

(fruits,

"fruits.5"

,

"watermelon"

) fmt.

Println

(newValue) } 複製代碼/<code>
  • fruits.1:設置第二個水果為grape(索引從 0 開始),輸出{"fruits":["apple", "grape", "banana"]};
  • fruits.3:由於數組長度為 3,使用 3 表示在數組後添加一個元素,輸出{"fruits":["apple","orange","banana","pear"]};
  • fruits.-1:使用-1同樣表示在數組後添加一個元素,輸出{"fruits":["apple", "orange", "banana","strawberry"]};
  • fruits.5:索引 5 已經大於數組長度 3 了,所以會多出兩個null,輸出{"fruits":["apple","orange","banana",null,null,"watermelon"]}。

刪除

刪除數組元素需要調用sjson.Delete()方法,鍵路徑語法相同。如果鍵路徑對應的值不存在,則Delete()無效果:

<code>

func

main

()

{

var

newValue string user := `{

"name"

:{

"first"

:

"li"

,

"last"

:

"dj"

},

"age"

:

18

}` newValue,

_

= sjson.

Delete

(user,

"name.first"

) fmt.

Println

(newValue) newValue,

_

= sjson.

Delete

(user,

"name.full"

) fmt.

Println

(newValue) fruits := `{

"fruits"

:[

"apple"

,

"orange"

,

"banana"

]}` newValue,

_

= sjson.

Delete

(fruits,

"fruits.1"

) fmt.

Println

(newValue) newValue,

_

= sjson.

Delete

(fruits,

"fruits.-1"

) fmt.

Println

(newValue) newValue,

_

= sjson.

Delete

(fruits,

"fruits.5"

) fmt.

Println

(newValue) } 複製代碼/<code>
  • name.first:刪除字段name.first,輸出{"name":{"last":"dj"},"age":18};
  • name.full:由於字段name.full不存在,無效果,輸出{"name":{"first":"li","last":"dj"},"age":18};
  • fruits.1:刪除數組fruits的第二個元素,輸出{"fruits":["apple", "banana"]};
  • fruits.-1:刪除數組最後一個元素,輸出{"fruits":["apple", "orange"]};
  • fruits.5:索引 5 超出數組長度 3,無效果,輸出{"fruits":["apple", "orange", "banana"]}。

錯誤處理

使用sjson出現的錯誤分為兩種,一種是傳入的 JSON 串不是合法的串,另一種是鍵路徑語法錯誤。Set()和Delete()方法返回的第二個參數為錯誤,只有非法的鍵路徑會返回錯誤,非法 JSON 串不會。

非法 JSON 串

同gjson一樣,sjson同樣不會檢查傳入的 JSON 串的合法性,它假設傳入的是合法的串。如果傳入一個非法的 JSON 串,程序輸出不確定的結果:

<code>

func

main

()

{ user :=

`{"name":dj,age:18}`

newValue, err := sjson.Set(user,

"name"

,

"dajun"

) fmt.Println(err, newValue) } 複製代碼/<code>

上面程序中,我故意傳入一個非法的 JSON 串(dj和age漏掉了雙引號)。最終程序輸出:

<code><

nil

> {

"name"

:dj

,

age:

"dajun"

} 複製代碼/<code>

將age變為了dajun,顯然不正確。然而此時返回的err = nil。

非法鍵路徑

與gjson相比,sjson能使用的鍵路徑語法比較有限,不能使用通配符和一些條件語法。如果傳入的鍵路徑非法,將返回非空的錯誤值:

<code>

func

main

()

{ user :=

`{"name":"dj","age":18}`

newValue, err := sjson.Set(user,

"na?e"

,

"dajun"

) fmt.Println(err, newValue) } 複製代碼/<code>

上次使用通配符?,輸出:

<code>wildcard characters 

not

allowed

in

path

複製代碼/<code>

總結

sjson比較簡單易用,性能不俗。我們在確定 JSON 串合法的情況下,可使用它快速設置值。

大家如果發現好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue


作者:darjun
鏈接:


https://juejin.im/post/5e7b74f651882535db015693
來源:掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。


分享到:


相關文章: