Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f042915ca1 | ||
|
c041e47f8a | ||
|
1879ad91cd | ||
|
0439aef712 | ||
|
0360deb6d8 | ||
|
d10932a0d0 | ||
|
12826915de | ||
|
c9f07c7971 | ||
|
8e8823353c | ||
|
5c2e4b3824 | ||
|
c34bf81952 | ||
|
94e070960b | ||
|
1471a933ec | ||
|
1c258afe09 | ||
|
c5e72cdf74 | ||
|
dea71f728d | ||
|
1e964df7d9 | ||
|
90ca17622f | ||
|
4d138e058b | ||
|
d7c940e593 | ||
|
3b5bf6bb5e | ||
|
001444ea45 | ||
|
6781e4ee59 | ||
|
f8322e865d | ||
|
f7c1980254 | ||
|
ae482cd23d | ||
|
f73dd9bfd8 | ||
|
ebf0b3fb77 | ||
|
00b15d756e | ||
|
d95cbcaa9d | ||
|
e91a88bec4 | ||
|
6eb62ca33f | ||
|
7660d0f79f | ||
|
7b8705a6b6 | ||
|
b877bd43b1 | ||
|
89b19799ff | ||
|
40764d5d56 | ||
|
fb8e539484 | ||
|
181e11634d | ||
|
eee0b6226f | ||
|
1ed2249f74 | ||
|
5d7556ad3d | ||
|
5a96cfda70 | ||
|
081192fa2e | ||
|
1bd06b6ad9 | ||
|
cced0fa719 | ||
|
4c7d6ff4a9 |
172
README.md
172
README.md
|
@ -55,6 +55,9 @@ Prichard
|
||||||
|
|
||||||
## Path Syntax
|
## Path Syntax
|
||||||
|
|
||||||
|
Below is a quick overview of the path syntax, for more complete information please
|
||||||
|
check out [GJSON Syntax](SYNTAX.md).
|
||||||
|
|
||||||
A path is a series of keys separated by a dot.
|
A path is a series of keys separated by a dot.
|
||||||
A key may contain special wildcard characters '\*' and '?'.
|
A key may contain special wildcard characters '\*' and '?'.
|
||||||
To access an array value use the index as the key.
|
To access an array value use the index as the key.
|
||||||
|
@ -68,9 +71,9 @@ The dot and wildcard characters can be escaped with '\\'.
|
||||||
"children": ["Sara","Alex","Jack"],
|
"children": ["Sara","Alex","Jack"],
|
||||||
"fav.movie": "Deer Hunter",
|
"fav.movie": "Deer Hunter",
|
||||||
"friends": [
|
"friends": [
|
||||||
{"first": "Dale", "last": "Murphy", "age": 44},
|
{"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
|
||||||
{"first": "Roger", "last": "Craig", "age": 68},
|
{"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
|
||||||
{"first": "Jane", "last": "Murphy", "age": 47}
|
{"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -87,45 +90,24 @@ The dot and wildcard characters can be escaped with '\\'.
|
||||||
"friends.1.last" >> "Craig"
|
"friends.1.last" >> "Craig"
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also query an array for the first match by using `#[...]`, or find all matches with `#[...]#`.
|
You can also query an array for the first match by using `#(...)`, or find all
|
||||||
Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators and the simple pattern matching `%` operator.
|
matches with `#(...)#`. Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=`
|
||||||
|
comparison operators and the simple pattern matching `%` (like) and `!%`
|
||||||
|
(not like) operators.
|
||||||
|
|
||||||
```
|
```
|
||||||
friends.#[last=="Murphy"].first >> "Dale"
|
friends.#(last=="Murphy").first >> "Dale"
|
||||||
friends.#[last=="Murphy"]#.first >> ["Dale","Jane"]
|
friends.#(last=="Murphy")#.first >> ["Dale","Jane"]
|
||||||
friends.#[age>45]#.last >> ["Craig","Murphy"]
|
friends.#(age>45)#.last >> ["Craig","Murphy"]
|
||||||
friends.#[first%"D*"].last >> "Murphy"
|
friends.#(first%"D*").last >> "Murphy"
|
||||||
|
friends.#(first!%"D*").last >> "Craig"
|
||||||
|
friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
|
||||||
```
|
```
|
||||||
|
|
||||||
## JSON Lines
|
*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
|
||||||
|
changed in v1.3.0 as to avoid confusion with the new
|
||||||
There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array.
|
[multipath](SYNTAX.md#multipaths) syntax. For backwards compatibility,
|
||||||
|
`#[...]` will continue to work until the next major release.*
|
||||||
For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
{"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
|
|
||||||
```
|
|
||||||
|
|
||||||
The `ForEachLines` function will iterate through JSON lines.
|
|
||||||
|
|
||||||
```go
|
|
||||||
gjson.ForEachLine(json, func(line gjson.Result) bool{
|
|
||||||
println(line.String())
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Result Type
|
## Result Type
|
||||||
|
|
||||||
|
@ -193,6 +175,118 @@ result.Int() int64 // -9223372036854775808 to 9223372036854775807
|
||||||
result.Uint() int64 // 0 to 18446744073709551615
|
result.Uint() int64 // 0 to 18446744073709551615
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Modifiers and path chaining
|
||||||
|
|
||||||
|
New in version 1.2 is support for modifier functions and path chaining.
|
||||||
|
|
||||||
|
A modifier is a path component that performs custom processing on the
|
||||||
|
json.
|
||||||
|
|
||||||
|
Multiple paths can be "chained" together using the pipe character.
|
||||||
|
This is useful for getting results from a modified query.
|
||||||
|
|
||||||
|
For example, using the built-in `@reverse` modifier on the above json document,
|
||||||
|
we'll get `children` array and reverse the order:
|
||||||
|
|
||||||
|
```
|
||||||
|
"children|@reverse" >> ["Jack","Alex","Sara"]
|
||||||
|
"children|@reverse|0" >> "Jack"
|
||||||
|
```
|
||||||
|
|
||||||
|
There are currently the following built-in modifiers:
|
||||||
|
|
||||||
|
- `@reverse`: Reverse an array or the members of an object.
|
||||||
|
- `@ugly`: Remove all whitespace from a json document.
|
||||||
|
- `@pretty`: Make the json document more human readable.
|
||||||
|
- `@this`: Returns the current element. It can be used to retrieve the root element.
|
||||||
|
- `@valid`: Ensure the json document is valid.
|
||||||
|
- `@flatten`: Flattens an array.
|
||||||
|
- `@join`: Joins multiple objects into a single object.
|
||||||
|
|
||||||
|
### Modifier arguments
|
||||||
|
|
||||||
|
A modifier may accept an optional argument. The argument can be a valid JSON
|
||||||
|
document or just characters.
|
||||||
|
|
||||||
|
For example, the `@pretty` modifier takes a json object as its argument.
|
||||||
|
|
||||||
|
```
|
||||||
|
@pretty:{"sortKeys":true}
|
||||||
|
```
|
||||||
|
|
||||||
|
Which makes the json pretty and orders all of its keys.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"age":37,
|
||||||
|
"children": ["Sara","Alex","Jack"],
|
||||||
|
"fav.movie": "Deer Hunter",
|
||||||
|
"friends": [
|
||||||
|
{"age": 44, "first": "Dale", "last": "Murphy"},
|
||||||
|
{"age": 68, "first": "Roger", "last": "Craig"},
|
||||||
|
{"age": 47, "first": "Jane", "last": "Murphy"}
|
||||||
|
],
|
||||||
|
"name": {"first": "Tom", "last": "Anderson"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
|
||||||
|
Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
|
||||||
|
|
||||||
|
### Custom modifiers
|
||||||
|
|
||||||
|
You can also add custom modifiers.
|
||||||
|
|
||||||
|
For example, here we create a modifier that makes the entire json document upper
|
||||||
|
or lower case.
|
||||||
|
|
||||||
|
```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
|
||||||
|
|
||||||
|
There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"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
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ForEachLines` function will iterate through JSON lines.
|
||||||
|
|
||||||
|
```go
|
||||||
|
gjson.ForEachLine(json, func(line gjson.Result) bool{
|
||||||
|
println(line.String())
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
## Get nested array values
|
## Get nested array values
|
||||||
|
|
||||||
Suppose you want all the last names from the following json:
|
Suppose you want all the last names from the following json:
|
||||||
|
@ -226,7 +320,7 @@ for _, name := range result.Array() {
|
||||||
You can also query an object inside an array:
|
You can also query an object inside an array:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
name := gjson.Get(json, `programmers.#[lastName="Hunter"].firstName`)
|
name := gjson.Get(json, `programmers.#(lastName="Hunter").firstName`)
|
||||||
println(name.String()) // prints "Elliotte"
|
println(name.String()) // prints "Elliotte"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
277
SYNTAX.md
Normal file
277
SYNTAX.md
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
# GJSON Path Syntax
|
||||||
|
|
||||||
|
A GJSON Path is a text string syntax that describes a search pattern for quickly retreiving values from a JSON payload.
|
||||||
|
|
||||||
|
This document is designed to explain the structure of a GJSON Path through examples.
|
||||||
|
|
||||||
|
- [Path structure](#path-structure)
|
||||||
|
- [Basic](#basic)
|
||||||
|
- [Wildcards](#wildcards)
|
||||||
|
- [Escape Character](#escape-character)
|
||||||
|
- [Arrays](#arrays)
|
||||||
|
- [Queries](#queries)
|
||||||
|
- [Dot vs Pipe](#dot-vs-pipe)
|
||||||
|
- [Modifiers](#modifiers)
|
||||||
|
- [Multipaths](#multipaths)
|
||||||
|
|
||||||
|
The definitive implemenation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson).
|
||||||
|
Use the [GJSON Playground](https://gjson.dev) to experiment with the syntax online.
|
||||||
|
|
||||||
|
|
||||||
|
## Path structure
|
||||||
|
|
||||||
|
A GJSON Path is intended to be easily expressed as a series of components seperated by a `.` character.
|
||||||
|
|
||||||
|
Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, and `?`.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Given this JSON
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": {"first": "Tom", "last": "Anderson"},
|
||||||
|
"age":37,
|
||||||
|
"children": ["Sara","Alex","Jack"],
|
||||||
|
"fav.movie": "Deer Hunter",
|
||||||
|
"friends": [
|
||||||
|
{"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
|
||||||
|
{"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
|
||||||
|
{"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The following GJSON Paths evaluate to the accompanying values.
|
||||||
|
|
||||||
|
### Basic
|
||||||
|
|
||||||
|
In many cases you'll just want to retreive values by object name or array index.
|
||||||
|
|
||||||
|
```go
|
||||||
|
name.last "Anderson"
|
||||||
|
name.first "Tom"
|
||||||
|
age 37
|
||||||
|
children ["Sara","Alex","Jack"]
|
||||||
|
children.0 "Sara"
|
||||||
|
children.1 "Alex"
|
||||||
|
friends.1 {"first": "Roger", "last": "Craig", "age": 68}
|
||||||
|
friends.1.first "Roger"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wildcards
|
||||||
|
|
||||||
|
A key may contain the special wildcard characters `*` and `?`.
|
||||||
|
The `*` will match on any zero+ characters, and `?` matches on any one character.
|
||||||
|
|
||||||
|
```go
|
||||||
|
child*.2 "Jack"
|
||||||
|
c?ildren.0 "Sara"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Escape character
|
||||||
|
|
||||||
|
Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`.
|
||||||
|
|
||||||
|
```go
|
||||||
|
fav\.movie "Deer Hunter"
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in source code.
|
||||||
|
|
||||||
|
```go
|
||||||
|
res := gjson.Get(json, "fav\\.movie") // must escape the slash
|
||||||
|
res := gjson.Get(json, `fav\.movie`) // no need to escape the slash
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arrays
|
||||||
|
|
||||||
|
The `#` character allows for digging into JSON Arrays.
|
||||||
|
|
||||||
|
To get the length of an array you'll just use the `#` all by itself.
|
||||||
|
|
||||||
|
```go
|
||||||
|
friends.# 3
|
||||||
|
friends.#.age [44,68,47]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Queries
|
||||||
|
|
||||||
|
You can also query an array for the first match by using `#(...)`, or find all matches with `#(...)#`.
|
||||||
|
Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators,
|
||||||
|
and the simple pattern matching `%` (like) and `!%` (not like) operators.
|
||||||
|
|
||||||
|
```go
|
||||||
|
friends.#(last=="Murphy").first "Dale"
|
||||||
|
friends.#(last=="Murphy")#.first ["Dale","Jane"]
|
||||||
|
friends.#(age>45)#.last ["Craig","Murphy"]
|
||||||
|
friends.#(first%"D*").last "Murphy"
|
||||||
|
friends.#(first!%"D*").last "Craig"
|
||||||
|
```
|
||||||
|
|
||||||
|
To query for a non-object value in an array, you can forgo the string to the right of the operator.
|
||||||
|
|
||||||
|
```go
|
||||||
|
children.#(!%"*a*") "Alex"
|
||||||
|
children.#(%"*a*")# ["Sara","Jack"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Nested queries are allowed.
|
||||||
|
|
||||||
|
```go
|
||||||
|
friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
|
||||||
|
```
|
||||||
|
|
||||||
|
*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
|
||||||
|
changed in v1.3.0 as to avoid confusion with the new [multipath](#multipaths)
|
||||||
|
syntax. For backwards compatibility, `#[...]` will continue to work until the
|
||||||
|
next major release.*
|
||||||
|
|
||||||
|
### Dot vs Pipe
|
||||||
|
|
||||||
|
The `.` is standard separator, but it's also possible to use a `|`.
|
||||||
|
In most cases they both end up returning the same results.
|
||||||
|
The cases where`|` differs from `.` is when it's used after the `#` for [Arrays](#arrays) and [Queries](#queries).
|
||||||
|
|
||||||
|
Here are some examples
|
||||||
|
|
||||||
|
```go
|
||||||
|
friends.0.first "Dale"
|
||||||
|
friends|0.first "Dale"
|
||||||
|
friends.0|first "Dale"
|
||||||
|
friends|0|first "Dale"
|
||||||
|
friends|# 3
|
||||||
|
friends.# 3
|
||||||
|
friends.#(last="Murphy")# [{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
|
||||||
|
friends.#(last="Murphy")#.first ["Dale","Jane"]
|
||||||
|
friends.#(last="Murphy")#|first <non-existent>
|
||||||
|
friends.#(last="Murphy")#.0 []
|
||||||
|
friends.#(last="Murphy")#|0 {"first": "Dale", "last": "Murphy", "age": 44}
|
||||||
|
friends.#(last="Murphy")#.# []
|
||||||
|
friends.#(last="Murphy")#|# 2
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's break down a few of these.
|
||||||
|
|
||||||
|
The path `friends.#(last="Murphy")#` all by itself results in
|
||||||
|
|
||||||
|
```json
|
||||||
|
[{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
|
||||||
|
```
|
||||||
|
|
||||||
|
The `.first` suffix will process the `first` path on each array element *before* returning the results. Which becomes
|
||||||
|
|
||||||
|
```json
|
||||||
|
["Dale","Jane"]
|
||||||
|
```
|
||||||
|
|
||||||
|
But the `|first` suffix actually processes the `first` path *after* the previous result.
|
||||||
|
Since the previous result is an array, not an object, it's not possible to process
|
||||||
|
because `first` does not exist.
|
||||||
|
|
||||||
|
Yet, `|0` suffix returns
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"first": "Dale", "last": "Murphy", "age": 44}
|
||||||
|
```
|
||||||
|
|
||||||
|
Because `0` is the first index of the previous result.
|
||||||
|
|
||||||
|
### Modifiers
|
||||||
|
|
||||||
|
A modifier is a path component that performs custom processing on the JSON.
|
||||||
|
|
||||||
|
For example, using the built-in `@reverse` modifier on the above JSON payload will reverse the `children` array:
|
||||||
|
|
||||||
|
```go
|
||||||
|
children.@reverse ["Jack","Alex","Sara"]
|
||||||
|
children.@reverse.0 "Jack"
|
||||||
|
```
|
||||||
|
|
||||||
|
There are currently the following built-in modifiers:
|
||||||
|
|
||||||
|
- `@reverse`: Reverse an array or the members of an object.
|
||||||
|
- `@ugly`: Remove all whitespace from JSON.
|
||||||
|
- `@pretty`: Make the JSON more human readable.
|
||||||
|
- `@this`: Returns the current element. It can be used to retrieve the root element.
|
||||||
|
- `@valid`: Ensure the json document is valid.
|
||||||
|
- `@flatten`: Flattens an array.
|
||||||
|
- `@join`: Joins multiple objects into a single object.
|
||||||
|
|
||||||
|
#### Modifier arguments
|
||||||
|
|
||||||
|
A modifier may accept an optional argument. The argument can be a valid JSON payload or just characters.
|
||||||
|
|
||||||
|
For example, the `@pretty` modifier takes a json object as its argument.
|
||||||
|
|
||||||
|
```
|
||||||
|
@pretty:{"sortKeys":true}
|
||||||
|
```
|
||||||
|
|
||||||
|
Which makes the json pretty and orders all of its keys.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"age":37,
|
||||||
|
"children": ["Sara","Alex","Jack"],
|
||||||
|
"fav.movie": "Deer Hunter",
|
||||||
|
"friends": [
|
||||||
|
{"age": 44, "first": "Dale", "last": "Murphy"},
|
||||||
|
{"age": 68, "first": "Roger", "last": "Craig"},
|
||||||
|
{"age": 47, "first": "Jane", "last": "Murphy"}
|
||||||
|
],
|
||||||
|
"name": {"first": "Tom", "last": "Anderson"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
|
||||||
|
Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
|
||||||
|
|
||||||
|
#### Custom modifiers
|
||||||
|
|
||||||
|
You can also add custom modifiers.
|
||||||
|
|
||||||
|
For example, here we create a modifier which makes the entire JSON payload upper or lower case.
|
||||||
|
|
||||||
|
```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"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multipaths
|
||||||
|
|
||||||
|
Starting with v1.3.0, GJSON added the ability to join multiple paths together
|
||||||
|
to form new documents. Wrapping comma-separated paths between `{...}` or
|
||||||
|
`[...]` will result in a new array or object, respectively.
|
||||||
|
|
||||||
|
For example, using the given multipath
|
||||||
|
|
||||||
|
```
|
||||||
|
{name.first,age,"the_murphys":friends.#(last="Murphy")#.first}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here we selected the first name, age, and the first name for friends with the
|
||||||
|
last name "Murphy".
|
||||||
|
|
||||||
|
You'll notice that an optional key can be provided, in this case
|
||||||
|
"the_murphys", to force assign a key to a value. Otherwise, the name of the
|
||||||
|
actual field will be used, in this case "first". If a name cannot be
|
||||||
|
determined, then "_" is used.
|
||||||
|
|
||||||
|
This results in
|
||||||
|
|
||||||
|
```
|
||||||
|
{"first":"Tom","age":37,"the_murphys":["Dale","Jane"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
10
gjson_gae.go
10
gjson_gae.go
|
@ -1,10 +0,0 @@
|
||||||
//+build appengine
|
|
||||||
|
|
||||||
package gjson
|
|
||||||
|
|
||||||
func getBytes(json []byte, path string) Result {
|
|
||||||
return Get(string(json), path)
|
|
||||||
}
|
|
||||||
func fillIndex(json string, c *parseContext) {
|
|
||||||
// noop. Use zero for the Index value.
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
//+build !appengine
|
|
||||||
|
|
||||||
package gjson
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// getBytes casts the input json bytes to a string and safely returns the
|
|
||||||
// results as uniquely allocated data. This operation is intended to minimize
|
|
||||||
// copies and allocations for the large json string->[]byte.
|
|
||||||
func getBytes(json []byte, path string) Result {
|
|
||||||
var result Result
|
|
||||||
if json != nil {
|
|
||||||
// unsafe cast to string
|
|
||||||
result = Get(*(*string)(unsafe.Pointer(&json)), path)
|
|
||||||
result = fromBytesGet(result)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func fromBytesGet(result Result) Result {
|
|
||||||
// safely get the string headers
|
|
||||||
rawhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Raw))
|
|
||||||
strhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Str))
|
|
||||||
// create byte slice headers
|
|
||||||
rawh := reflect.SliceHeader{Data: rawhi.Data, Len: rawhi.Len}
|
|
||||||
strh := reflect.SliceHeader{Data: strhi.Data, Len: strhi.Len}
|
|
||||||
if strh.Data == 0 {
|
|
||||||
// str is nil
|
|
||||||
if rawh.Data == 0 {
|
|
||||||
// raw is nil
|
|
||||||
result.Raw = ""
|
|
||||||
} else {
|
|
||||||
// raw has data, safely copy the slice header to a string
|
|
||||||
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
|
||||||
}
|
|
||||||
result.Str = ""
|
|
||||||
} else if rawh.Data == 0 {
|
|
||||||
// raw is nil
|
|
||||||
result.Raw = ""
|
|
||||||
// str has data, safely copy the slice header to a string
|
|
||||||
result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
|
|
||||||
} else if strh.Data >= rawh.Data &&
|
|
||||||
int(strh.Data)+strh.Len <= int(rawh.Data)+rawh.Len {
|
|
||||||
// Str is a substring of Raw.
|
|
||||||
start := int(strh.Data - rawh.Data)
|
|
||||||
// safely copy the raw slice header
|
|
||||||
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
|
||||||
// substring the raw
|
|
||||||
result.Str = result.Raw[start : start+strh.Len]
|
|
||||||
} else {
|
|
||||||
// safely copy both the raw and str slice headers to strings
|
|
||||||
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
|
|
||||||
result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// fillIndex finds the position of Raw data and assigns it to the Index field
|
|
||||||
// of the resulting value. If the position cannot be found then Index zero is
|
|
||||||
// used instead.
|
|
||||||
func fillIndex(json string, c *parseContext) {
|
|
||||||
if len(c.value.Raw) > 0 && !c.calcd {
|
|
||||||
jhdr := *(*reflect.StringHeader)(unsafe.Pointer(&json))
|
|
||||||
rhdr := *(*reflect.StringHeader)(unsafe.Pointer(&(c.value.Raw)))
|
|
||||||
c.value.Index = int(rhdr.Data - jhdr.Data)
|
|
||||||
if c.value.Index < 0 || c.value.Index >= len(json) {
|
|
||||||
c.value.Index = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
883
gjson_test.go
883
gjson_test.go
File diff suppressed because it is too large
Load Diff
8
go.mod
Normal file
8
go.mod
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module github.com/tidwall/gjson
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/tidwall/match v1.0.1
|
||||||
|
github.com/tidwall/pretty v1.0.0
|
||||||
|
)
|
4
go.sum
Normal file
4
go.sum
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
||||||
|
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||||
|
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||||
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
Loading…
Reference in New Issue
Block a user