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).*