Go 每日一库之 sjson

简介

上一篇文章中咱们介绍了如何使用gjson快速读取 JSON 串中的值。为了内容的完整性,今天咱们介绍一下如何使用sjson快速设置 JSON 串中的值。git

快速使用

先安装:github

$ go get github.com/tidwall/sjson

后使用:json

package mainimport (  "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 串。最终程序输出:数组

{"name":{"first":"li","last":"dajun"},"age":18}

支持的类型

sjson支持的类型包括nil/bool/int/float/string等。若是传入sjson不支持的类型,sjson会调用json.Marshal,而后将生成的字符串设置到对应的键路径上:微信

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)}

注意,咱们传入一个空字符串,sjson.Set()会生成一个空对象,而后按照键路径依次设置值。下面分析上述程序输出:app

  • nil:在 JSON 中用null表示,输出{"key":null}
  • false:在 JSON 中布尔值用true/false表示,输出{"key":false}
  • 110.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值。

看下面示例:学习

func main() {  fruits := `{"fruits":["apple", "orange", "banana"]}`  var newValue string  newValue, _ = sjson.Delete(fruits, "fruits.1")  fmt.Println(newValue)  newValue, _ = sjson.Delete(fruits, "fruits.-1")  fmt.Println(newValue)  newValue, _ = sjson.Set(fruits, "fruits.5")  fmt.Println(newValue)}
  • 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()无效果:ui

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)}
  • 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 串不会。spa

非法 JSON 串

gjson同样,sjson一样不会检查传入的 JSON 串的合法性,它假设传入的是合法的串。若是传入一个非法的 JSON 串,程序输出不肯定的结果:

func main() {  user := `{"name":dj,age:18}`  newValue, err := sjson.Set(user, "name", "dajun")  fmt.Println(err, newValue)}

上面程序中,我故意传入一个非法的 JSON 串(djage漏掉了双引号)。最终程序输出:

<nil> {"name":dj,age:"dajun"}

age变为了dajun,显然不正确。然而此时返回的err = nil

非法键路径

gjson相比,sjson能使用的键路径语法比较有限,不能使用通配符和一些条件语法。若是传入的键路径非法,将返回非空的错误值:

func main() {  user := `{"name":"dj","age":18}`  newValue, err := sjson.Set(user, "na?e", "dajun")  fmt.Println(err, newValue)}

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

wildcard characters not allowed in path

总结

sjson比较简单易用,性能不俗。咱们在肯定 JSON 串合法的状况下,可以使用它快速设置值。

你们若是发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue😄

参考

  1. sjson GitHub:https://github.com/tidwall/sjson
  2. Go 每日一库 GitHub:https://github.com/darjun/go-daily-lib


-

个人博客:https://darjun.github.io

欢迎关注个人微信公众号【GoUpUp】,共同窗习,一块儿进步~

相关文章
相关标签/搜索