簡介
在上一篇文章中我們介紹瞭如何使用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
上面代碼通過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
Userstruct
{ Namestring
`json:"name"`
Ageint
`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"
"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
allowedin
path
複製代碼/<code>總結
sjson比較簡單易用,性能不俗。我們在確定 JSON 串合法的情況下,可使用它快速設置值。
大家如果發現好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue
作者:darjun
鏈接:
https://juejin.im/post/5e7b74f651882535db015693
來源:掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。