github.com/fufuok/utils@v1.0.10/xjson/gjson/README.md (about) 1 <p align="center"> 2 <img 3 src="logo.png" 4 width="240" height="78" border="0" alt="GJSON"> 5 <br> 6 <a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a> 7 <a href="https://tidwall.com/gjson-play"><img src="https://img.shields.io/badge/%F0%9F%8F%90-playground-9900cc.svg?style=flat-square" alt="GJSON Playground"></a> 8 <a href="SYNTAX.md"><img src="https://img.shields.io/badge/{}-syntax-33aa33.svg?style=flat-square" alt="GJSON Syntax"></a> 9 10 </p> 11 12 <p align="center">get json values quickly</a></p> 13 14 GJSON is a Go package that provides a [fast](#performance) and [simple](#get-a-value) way to get values from a json document. 15 It has features such as [one line retrieval](#get-a-value), [dot notation paths](#path-syntax), [iteration](#iterate-through-an-object-or-array), and [parsing json lines](#json-lines). 16 17 Also check out [SJSON](https://github.com/tidwall/sjson) for modifying json, and the [JJ](https://github.com/tidwall/jj) command line tool. 18 19 This README is a quick overview of how to use GJSON, for more information check out [GJSON Syntax](SYNTAX.md). 20 21 Getting Started 22 =============== 23 24 ## Installing 25 26 To start using GJSON, install Go and run `go get`: 27 28 ```sh 29 $ go get -u github.com/tidwall/gjson 30 ``` 31 32 This will retrieve the library. 33 34 ## Get a value 35 Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". When the value is found it's returned immediately. 36 37 ```go 38 package main 39 40 import "github.com/tidwall/gjson" 41 42 const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}` 43 44 func main() { 45 value := gjson.Get(json, "name.last") 46 println(value.String()) 47 } 48 ``` 49 50 This will print: 51 52 ``` 53 Prichard 54 ``` 55 *There's also the [GetMany](#get-multiple-values-at-once) function to get multiple values at once, and [GetBytes](#working-with-bytes) for working with JSON byte slices.* 56 57 ## Path Syntax 58 59 Below is a quick overview of the path syntax, for more complete information please 60 check out [GJSON Syntax](SYNTAX.md). 61 62 A path is a series of keys separated by a dot. 63 A key may contain special wildcard characters '\*' and '?'. 64 To access an array value use the index as the key. 65 To get the number of elements in an array or to access a child path, use the '#' character. 66 The dot and wildcard characters can be escaped with '\\'. 67 68 ```json 69 { 70 "name": {"first": "Tom", "last": "Anderson"}, 71 "age":37, 72 "children": ["Sara","Alex","Jack"], 73 "fav.movie": "Deer Hunter", 74 "friends": [ 75 {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]}, 76 {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]}, 77 {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]} 78 ] 79 } 80 ``` 81 ``` 82 "name.last" >> "Anderson" 83 "age" >> 37 84 "children" >> ["Sara","Alex","Jack"] 85 "children.#" >> 3 86 "children.1" >> "Alex" 87 "child*.2" >> "Jack" 88 "c?ildren.0" >> "Sara" 89 "fav\.movie" >> "Deer Hunter" 90 "friends.#.first" >> ["Dale","Roger","Jane"] 91 "friends.1.last" >> "Craig" 92 ``` 93 94 You can also query an array for the first match by using `#(...)`, or find all 95 matches with `#(...)#`. Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` 96 comparison operators and the simple pattern matching `%` (like) and `!%` 97 (not like) operators. 98 99 ``` 100 friends.#(last=="Murphy").first >> "Dale" 101 friends.#(last=="Murphy")#.first >> ["Dale","Jane"] 102 friends.#(age>45)#.last >> ["Craig","Murphy"] 103 friends.#(first%"D*").last >> "Murphy" 104 friends.#(first!%"D*").last >> "Craig" 105 friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"] 106 ``` 107 108 *Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was 109 changed in v1.3.0 as to avoid confusion with the new 110 [multipath](SYNTAX.md#multipaths) syntax. For backwards compatibility, 111 `#[...]` will continue to work until the next major release.* 112 113 ## Result Type 114 115 GJSON supports the json types `string`, `number`, `bool`, and `null`. 116 Arrays and Objects are returned as their raw json types. 117 118 The `Result` type holds one of these: 119 120 ``` 121 bool, for JSON booleans 122 float64, for JSON numbers 123 string, for JSON string literals 124 nil, for JSON null 125 ``` 126 127 To directly access the value: 128 129 ```go 130 result.Type // can be String, Number, True, False, Null, or JSON 131 result.Str // holds the string 132 result.Num // holds the float64 number 133 result.Raw // holds the raw json 134 result.Index // index of raw value in original json, zero means index unknown 135 result.Indexes // indexes of all the elements that match on a path containing the '#' query character. 136 ``` 137 138 There are a variety of handy functions that work on a result: 139 140 ```go 141 result.Exists() bool 142 result.Value() interface{} 143 result.Int() int64 144 result.Uint() uint64 145 result.Float() float64 146 result.String() string 147 result.Bool() bool 148 result.Time() time.Time 149 result.Array() []gjson.Result 150 result.Map() map[string]gjson.Result 151 result.Get(path string) Result 152 result.ForEach(iterator func(key, value Result) bool) 153 result.Less(token Result, caseSensitive bool) bool 154 ``` 155 156 The `result.Value()` function returns an `interface{}` which requires type assertion and is one of the following Go types: 157 158 ```go 159 boolean >> bool 160 number >> float64 161 string >> string 162 null >> nil 163 array >> []interface{} 164 object >> map[string]interface{} 165 ``` 166 167 The `result.Array()` function returns back an array of values. 168 If the result represents a non-existent value, then an empty array will be returned. 169 If the result is not a JSON array, the return value will be an array containing one result. 170 171 ### 64-bit integers 172 173 The `result.Int()` and `result.Uint()` calls are capable of reading all 64 bits, allowing for large JSON integers. 174 175 ```go 176 result.Int() int64 // -9223372036854775808 to 9223372036854775807 177 result.Uint() int64 // 0 to 18446744073709551615 178 ``` 179 180 ## Modifiers and path chaining 181 182 New in version 1.2 is support for modifier functions and path chaining. 183 184 A modifier is a path component that performs custom processing on the 185 json. 186 187 Multiple paths can be "chained" together using the pipe character. 188 This is useful for getting results from a modified query. 189 190 For example, using the built-in `@reverse` modifier on the above json document, 191 we'll get `children` array and reverse the order: 192 193 ``` 194 "children|@reverse" >> ["Jack","Alex","Sara"] 195 "children|@reverse|0" >> "Jack" 196 ``` 197 198 There are currently the following built-in modifiers: 199 200 - `@reverse`: Reverse an array or the members of an object. 201 - `@ugly`: Remove all whitespace from a json document. 202 - `@pretty`: Make the json document more human readable. 203 - `@this`: Returns the current element. It can be used to retrieve the root element. 204 - `@valid`: Ensure the json document is valid. 205 - `@flatten`: Flattens an array. 206 - `@join`: Joins multiple objects into a single object. 207 - `@keys`: Returns an array of keys for an object. 208 - `@values`: Returns an array of values for an object. 209 - `@tostr`: Converts json to a string. Wraps a json string. 210 - `@fromstr`: Converts a string from json. Unwraps a json string. 211 - `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db). 212 213 ### Modifier arguments 214 215 A modifier may accept an optional argument. The argument can be a valid JSON 216 document or just characters. 217 218 For example, the `@pretty` modifier takes a json object as its argument. 219 220 ``` 221 @pretty:{"sortKeys":true} 222 ``` 223 224 Which makes the json pretty and orders all of its keys. 225 226 ```json 227 { 228 "age":37, 229 "children": ["Sara","Alex","Jack"], 230 "fav.movie": "Deer Hunter", 231 "friends": [ 232 {"age": 44, "first": "Dale", "last": "Murphy"}, 233 {"age": 68, "first": "Roger", "last": "Craig"}, 234 {"age": 47, "first": "Jane", "last": "Murphy"} 235 ], 236 "name": {"first": "Tom", "last": "Anderson"} 237 } 238 ``` 239 240 *The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`. 241 Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.* 242 243 ### Custom modifiers 244 245 You can also add custom modifiers. 246 247 For example, here we create a modifier that makes the entire json document upper 248 or lower case. 249 250 ```go 251 gjson.AddModifier("case", func(json, arg string) string { 252 if arg == "upper" { 253 return strings.ToUpper(json) 254 } 255 if arg == "lower" { 256 return strings.ToLower(json) 257 } 258 return json 259 }) 260 ``` 261 262 ``` 263 "children|@case:upper" >> ["SARA","ALEX","JACK"] 264 "children|@case:lower|@reverse" >> ["jack","alex","sara"] 265 ``` 266 267 ## JSON Lines 268 269 There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array. 270 271 For example: 272 273 ``` 274 {"name": "Gilbert", "age": 61} 275 {"name": "Alexa", "age": 34} 276 {"name": "May", "age": 57} 277 {"name": "Deloise", "age": 44} 278 ``` 279 280 ``` 281 ..# >> 4 282 ..1 >> {"name": "Alexa", "age": 34} 283 ..3 >> {"name": "Deloise", "age": 44} 284 ..#.name >> ["Gilbert","Alexa","May","Deloise"] 285 ..#(name="May").age >> 57 286 ``` 287 288 The `ForEachLines` function will iterate through JSON lines. 289 290 ```go 291 gjson.ForEachLine(json, func(line gjson.Result) bool{ 292 println(line.String()) 293 return true 294 }) 295 ``` 296 297 ## Get nested array values 298 299 Suppose you want all the last names from the following json: 300 301 ```json 302 { 303 "programmers": [ 304 { 305 "firstName": "Janet", 306 "lastName": "McLaughlin", 307 }, { 308 "firstName": "Elliotte", 309 "lastName": "Hunter", 310 }, { 311 "firstName": "Jason", 312 "lastName": "Harold", 313 } 314 ] 315 } 316 ``` 317 318 You would use the path "programmers.#.lastName" like such: 319 320 ```go 321 result := gjson.Get(json, "programmers.#.lastName") 322 for _, name := range result.Array() { 323 println(name.String()) 324 } 325 ``` 326 327 You can also query an object inside an array: 328 329 ```go 330 name := gjson.Get(json, `programmers.#(lastName="Hunter").firstName`) 331 println(name.String()) // prints "Elliotte" 332 ``` 333 334 ## Iterate through an object or array 335 336 The `ForEach` function allows for quickly iterating through an object or array. 337 The key and value are passed to the iterator function for objects. 338 Only the value is passed for arrays. 339 Returning `false` from an iterator will stop iteration. 340 341 ```go 342 result := gjson.Get(json, "programmers") 343 result.ForEach(func(key, value gjson.Result) bool { 344 println(value.String()) 345 return true // keep iterating 346 }) 347 ``` 348 349 ## Simple Parse and Get 350 351 There's a `Parse(json)` function that will do a simple parse, and `result.Get(path)` that will search a result. 352 353 For example, all of these will return the same result: 354 355 ```go 356 gjson.Parse(json).Get("name").Get("last") 357 gjson.Get(json, "name").Get("last") 358 gjson.Get(json, "name.last") 359 ``` 360 361 ## Check for the existence of a value 362 363 Sometimes you just want to know if a value exists. 364 365 ```go 366 value := gjson.Get(json, "name.last") 367 if !value.Exists() { 368 println("no last name") 369 } else { 370 println(value.String()) 371 } 372 373 // Or as one step 374 if gjson.Get(json, "name.last").Exists() { 375 println("has a last name") 376 } 377 ``` 378 379 ## Validate JSON 380 381 The `Get*` and `Parse*` functions expects that the json is well-formed. Bad json will not panic, but it may return back unexpected results. 382 383 If you are consuming JSON from an unpredictable source then you may want to validate prior to using GJSON. 384 385 ```go 386 if !gjson.Valid(json) { 387 return errors.New("invalid json") 388 } 389 value := gjson.Get(json, "name.last") 390 ``` 391 392 ## Unmarshal to a map 393 394 To unmarshal to a `map[string]interface{}`: 395 396 ```go 397 m, ok := gjson.Parse(json).Value().(map[string]interface{}) 398 if !ok { 399 // not a map 400 } 401 ``` 402 403 ## Working with Bytes 404 405 If your JSON is contained in a `[]byte` slice, there's the [GetBytes](https://godoc.org/github.com/tidwall/gjson#GetBytes) function. This is preferred over `Get(string(data), path)`. 406 407 ```go 408 var json []byte = ... 409 result := gjson.GetBytes(json, path) 410 ``` 411 412 If you are using the `gjson.GetBytes(json, path)` function and you want to avoid converting `result.Raw` to a `[]byte`, then you can use this pattern: 413 414 ```go 415 var json []byte = ... 416 result := gjson.GetBytes(json, path) 417 var raw []byte 418 if result.Index > 0 { 419 raw = json[result.Index:result.Index+len(result.Raw)] 420 } else { 421 raw = []byte(result.Raw) 422 } 423 ``` 424 425 This is a best-effort no allocation sub slice of the original json. This method utilizes the `result.Index` field, which is the position of the raw data in the original json. It's possible that the value of `result.Index` equals zero, in which case the `result.Raw` is converted to a `[]byte`. 426 427 ## Get multiple values at once 428 429 The `GetMany` function can be used to get multiple values at the same time. 430 431 ```go 432 results := gjson.GetMany(json, "name.first", "name.last", "age") 433 ``` 434 435 The return value is a `[]Result`, which will always contain exactly the same number of items as the input paths. 436 437 ## Performance 438 439 Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/), 440 [ffjson](https://github.com/pquerna/ffjson), 441 [EasyJSON](https://github.com/mailru/easyjson), 442 [jsonparser](https://github.com/buger/jsonparser), 443 and [json-iterator](https://github.com/json-iterator/go) 444 445 ``` 446 BenchmarkGJSONGet-16 11644512 311 ns/op 0 B/op 0 allocs/op 447 BenchmarkGJSONUnmarshalMap-16 1122678 3094 ns/op 1920 B/op 26 allocs/op 448 BenchmarkJSONUnmarshalMap-16 516681 6810 ns/op 2944 B/op 69 allocs/op 449 BenchmarkJSONUnmarshalStruct-16 697053 5400 ns/op 928 B/op 13 allocs/op 450 BenchmarkJSONDecoder-16 330450 10217 ns/op 3845 B/op 160 allocs/op 451 BenchmarkFFJSONLexer-16 1424979 2585 ns/op 880 B/op 8 allocs/op 452 BenchmarkEasyJSONLexer-16 3000000 729 ns/op 501 B/op 5 allocs/op 453 BenchmarkJSONParserGet-16 3000000 366 ns/op 21 B/op 0 allocs/op 454 BenchmarkJSONIterator-16 3000000 869 ns/op 693 B/op 14 allocs/op 455 ``` 456 457 JSON document used: 458 459 ```json 460 { 461 "widget": { 462 "debug": "on", 463 "window": { 464 "title": "Sample Konfabulator Widget", 465 "name": "main_window", 466 "width": 500, 467 "height": 500 468 }, 469 "image": { 470 "src": "Images/Sun.png", 471 "hOffset": 250, 472 "vOffset": 250, 473 "alignment": "center" 474 }, 475 "text": { 476 "data": "Click Here", 477 "size": 36, 478 "style": "bold", 479 "vOffset": 100, 480 "alignment": "center", 481 "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" 482 } 483 } 484 } 485 ``` 486 487 Each operation was rotated through one of the following search paths: 488 489 ``` 490 widget.window.name 491 widget.image.hOffset 492 widget.text.onMouseUp 493 ``` 494 495 *These benchmarks were run on a MacBook Pro 16" 2.4 GHz Intel Core i9 using Go 1.17 and can be found [here](https://github.com/tidwall/gjson-benchmarks).*