[TOC] 还有个包[https://github.com/buger/jsonparser](https://github.com/buger/jsonparser) # gjson包 ## 安装使用 ~~~ go get -u github.com/tidwall/gjson ~~~ ~~~ const json = `{"name":[{"first":"Janet","last":"Prichard"}, {"abc": 1, "e" : 2}],"age":47}` func main() { v := gjson.Get(json, "name") if v.String() == "" { fmt.Println("nil") } else { fmt.Println(v.String()) fmt.Println(v.Type) } } ~~~ ## 简单的解析和获取 有一个`Parse(json)`函数可以进行简单的解析,然后`result.Get(path)`搜索结果。 例如,所有这些都将返回相同的结果 ~~~ gjson.Parse(json).Get("name").Get("last") gjson.Get(json, "name").Get("last") gjson.Get(json, "name.last") ~~~ ## 路径匹配 路径是由点分隔的一系列键。密钥可能包含特殊的通配符'\*'和'?'。要访问数组值,请使用索引作为键。要获取数组中的元素数或访问子路径,请使用“#”字符。点和通配符可以使用'\\'进行转义 ~~~ { "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" ~~~ ## 结果类型 GJSON支持JSON类型`string`,`number`,`bool`,和`null`。数组和对象作为原始json类型返回。 该`Result`类型包含以下其中一种: ~~~ bool, for JSON booleans float64, for JSON numbers string, for JSON string literals nil, for JSON null ~~~ 要直接访问该值: ~~~ result.Type //可以是String,Number,True,False,Null或JSON result.Str //保存字符串 result.Num //保存float64数字 result.Raw //保存原始json result.Index //原始json中原始值的索引,零表示索引未知 ~~~ 有各种方便的功能可以处理结果 ~~~ result.Exists() bool result.Value() interface{} result.Int() int64 result.Uint() uint64 result.Float() float64 result.String() string result.Bool() bool result.Time() time.Time result.Array() []gjson.Result result.Map() map[string]gjson.Result result.Get(path string) Result result.ForEach(iterator func(key, value Result) bool) result.Less(token Result, caseSensitive bool) bool ~~~ 该`result.Value()`函数返回一个`interface{}`需要类型断言的函数,它是以下Go类型之一: 该`result.Array()`函数返回一组值。如果结果表示不存在的值,则返回空数组。如果结果不是JSON数组,则返回值将是包含一个结果的数组。 ~~~go boolean >> bool number >> float64 string >> string null >> nil array >> [] interface {} object >> map [ string ] interface {} ~~~ # 判断某个值是否存在: ~~~ value := gjson.Get(json, "name.last") if !value.Exists() { println("no last name") } else { println(value.String()) } // Or as one step if gjson.Get(json, "name.last").Exists() { println("has a last name") } ~~~ # 验证json格式 ~~~ if !gjson.Valid(json) { return errors.New("invalid json") } value := gjson.Get(json, "name.last") ~~~ # 修饰符和路径链接 版本1.2中的新功能支持修改器功能和路径链接。 修饰符是在json上执行自定义处理的路径组件。 可以使用管道字符将多个路径“链接”在一起。这对于从修改后的查询中获取结果非常有用。 例如,使用`@reverse`上面json文档中的内置修饰符,我们将得到`children`数组并反转顺序: ~~~ "children|@reverse" >> ["Jack","Alex","Sara"] "children|@reverse|0" >> "Jack" ~~~ 目前有三种内置修饰符: * `@reverse`:反转数组或对象的成员。 * `@ugly`:从json文档中删除所有空格。 * `@pretty`:使json文档更具人性化 # 自定义修改器 您还可以添加自定义修改器。 例如,这里我们创建一个修饰符,使整个json文档大写或小写 ~~~go gjson.AddModifier("case", func(json, arg string) string { if arg == "upper" { return strings.ToUpper(json) } if arg == "lower" { return strings.ToLower(json) } return json }) ~~~ ~~~ "children|@case:upper" >> ["SARA","ALEX","JACK"] "children|@case:lower|@reverse" >> ["jack","alex","sara"] ~~~ # 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 }) ~~~ # 获取嵌套数组值 假设您想要以下json中的所有姓氏 ~~~ { "programmers": [ { "firstName": "Janet", "lastName": "McLaughlin", }, { "firstName": "Elliotte", "lastName": "Hunter", }, { "firstName": "Jason", "lastName": "Harold", } ] } ~~~ 获取所有的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`函数允许快速迭代对象或数组。键和值将传递给对象的迭代器函数。仅为数组传递值。`false`从迭代器返回将停止迭代 ~~~ result := gjson.Get(json, "programmers") result.ForEach(func(key, value gjson.Result) bool { println(value.String()) return true // keep iterating }) ~~~ # 解开到map 解开到map\[string\]interface{} ~~~ m, ok := gjson.Parse(json).Value().(map[string]interface{}) if !ok { // not a map } ~~~ # 使用字节 如果您的JSON包含在`[]byte`切片中,那么就是[GetBytes](https://godoc.org/github.com/tidwall/gjson#GetBytes)函数。这是优先的`Get(string(data), path)` ~~~ var json []byte = ... result := gjson.GetBytes(json, path) ~~~ 如果您正在使用该`gjson.GetBytes(json, path)`功能并且想要避免转换`result.Raw`为a`[]byte`,则可以使用此模式 ~~~ var json []byte = ... result := gjson.GetBytes(json, path) var raw []byte if result.Index > 0 { raw = json[result.Index:result.Index+len(result.Raw)] } else { raw = []byte(result.Raw) } ~~~ 这是原始json的尽力而为的无分配子切片。该方法利用`result.Index`字段,该字段是原始json中原始数据的位置。有可能值`result.Index`等于零,在这种情况下`result.Raw`转换为a`[]byte` # 一次获取多个值 该`GetMany`函数可用于同时获取多个值 ~~~ results := gjson.GetMany(json, "name.first", "name.last", "age") ~~~ 返回值为a`[]Result`,它将始终包含与输入路径完全相同的项目数 # 格式化 要开始使用Pretty,请安装Go并运行`go get`: ~~~shell $ go get -u github.com/tidwall/pretty ~~~ ~~~ const json = `{ "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} ] }` func main() { var byteSlice []byte byteSlice = []byte(json) res := pretty.Pretty(byteSlice) fmt.Println(string(res)) } ~~~ 加上颜色 ~~~ result = pretty.Color(json, nil) ~~~