mirror of https://github.com/tidwall/gjson.git
Support queries
This commit is contained in:
parent
34ea511746
commit
73b86a9fc9
11
README.md
11
README.md
|
@ -123,11 +123,12 @@ nil, for JSON null
|
|||
To directly access the value:
|
||||
|
||||
```go
|
||||
result.Type // can be String, Number, True, False, Null, or JSON
|
||||
result.Str // holds the string
|
||||
result.Num // holds the float64 number
|
||||
result.Raw // holds the raw json
|
||||
result.Index // index of raw value in original json, zero means index unknown
|
||||
result.Type // can be String, Number, True, False, Null, or JSON
|
||||
result.Str // holds the string
|
||||
result.Num // holds the float64 number
|
||||
result.Raw // holds the raw json
|
||||
result.Index // index of raw value in original json, zero means index unknown
|
||||
result.HashtagIndexes // hashtagIndexes contains the indexes of the elements returned by a query containing the '#' character
|
||||
```
|
||||
|
||||
There are a variety of handy functions that work on a result:
|
||||
|
|
29
gjson.go
29
gjson.go
|
@ -64,8 +64,8 @@ type Result struct {
|
|||
Num float64
|
||||
// Index of raw value in original json, zero means index unknown
|
||||
Index int
|
||||
// ArrayIndex is the Index of each returned element in the original json
|
||||
ArrayIndex []int
|
||||
// HashtagIndexes contains the Indexes of the elements returned by a query containing the '#' character
|
||||
HashtagIndexes []int
|
||||
}
|
||||
|
||||
// String returns a string representation of the value.
|
||||
|
@ -1263,6 +1263,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
var alog []int
|
||||
var partidx int
|
||||
var multires []byte
|
||||
var hashtagQueryIndex []int
|
||||
rp := parseArrayPath(path)
|
||||
if !rp.arrch {
|
||||
n, ok := parseUint(rp.part)
|
||||
|
@ -1283,6 +1284,10 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
multires = append(multires, '[')
|
||||
}
|
||||
}
|
||||
var tmp parseContext
|
||||
tmp.value = qval
|
||||
fillIndex(c.json, &tmp)
|
||||
parentIndex := tmp.value.Index
|
||||
var res Result
|
||||
if qval.Type == JSON {
|
||||
res = qval.Get(rp.query.path)
|
||||
|
@ -1314,6 +1319,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
multires = append(multires, ',')
|
||||
}
|
||||
multires = append(multires, raw...)
|
||||
hashtagQueryIndex = append(hashtagQueryIndex, res.Index+parentIndex)
|
||||
}
|
||||
} else {
|
||||
c.value = res
|
||||
|
@ -1478,7 +1484,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
c.pipe = right
|
||||
c.piped = true
|
||||
}
|
||||
var arrayIndex = make([]int, 0, 64)
|
||||
var hashtagIndexes = make([]int, 0, 64)
|
||||
var jsons = make([]byte, 0, 64)
|
||||
jsons = append(jsons, '[')
|
||||
for j, k := 0, 0; j < len(alog); j++ {
|
||||
|
@ -1505,7 +1511,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
raw = res.String()
|
||||
}
|
||||
jsons = append(jsons, []byte(raw)...)
|
||||
arrayIndex = append(arrayIndex, res.Index+parentIndex)
|
||||
hashtagIndexes = append(hashtagIndexes, res.Index+parentIndex)
|
||||
k++
|
||||
}
|
||||
}
|
||||
|
@ -1514,7 +1520,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
jsons = append(jsons, ']')
|
||||
c.value.Type = JSON
|
||||
c.value.Raw = string(jsons)
|
||||
c.value.ArrayIndex = arrayIndex
|
||||
c.value.HashtagIndexes = hashtagIndexes
|
||||
return i + 1, true
|
||||
}
|
||||
if rp.alogok {
|
||||
|
@ -1530,8 +1536,9 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
if !c.value.Exists() {
|
||||
if len(multires) > 0 {
|
||||
c.value = Result{
|
||||
Raw: string(append(multires, ']')),
|
||||
Type: JSON,
|
||||
Raw: string(append(multires, ']')),
|
||||
Type: JSON,
|
||||
HashtagIndexes: hashtagQueryIndex,
|
||||
}
|
||||
} else if rp.query.all {
|
||||
c.value = Result{
|
||||
|
@ -2052,10 +2059,10 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
|
|||
res.Raw = val
|
||||
res.Type = JSON
|
||||
}
|
||||
var c parseContext
|
||||
c.value = res
|
||||
fillIndex(json, &c)
|
||||
return i, c.value, true
|
||||
var tmp parseContext
|
||||
tmp.value = res
|
||||
fillIndex(json, &tmp)
|
||||
return i, tmp.value, true
|
||||
}
|
||||
if json[i] <= ' ' {
|
||||
continue
|
||||
|
|
|
@ -859,9 +859,9 @@ func TestIssue20(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIssue21(t *testing.T) {
|
||||
json := `{ "Level1Field1":3,
|
||||
"Level1Field4":4,
|
||||
"Level1Field2":{ "Level2Field1":[ "value1", "value2" ],
|
||||
json := `{ "Level1Field1":3,
|
||||
"Level1Field4":4,
|
||||
"Level1Field2":{ "Level2Field1":[ "value1", "value2" ],
|
||||
"Level2Field2":{ "Level3Field1":[ { "key1":"value1" } ] } } }`
|
||||
paths := []string{"Level1Field1", "Level1Field2.Level2Field1",
|
||||
"Level1Field2.Level2Field2.Level3Field1", "Level1Field4"}
|
||||
|
@ -1492,7 +1492,7 @@ func TestDeepSelectors(t *testing.T) {
|
|||
}
|
||||
},
|
||||
{
|
||||
"first": "Roger", "last": "Craig",
|
||||
"first": "Roger", "last": "Craig",
|
||||
"extra": [40,50,60],
|
||||
"details": {
|
||||
"city": "Phoenix",
|
||||
|
@ -2122,48 +2122,73 @@ func TestModifierDoubleQuotes(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestArrayIndex(t *testing.T) {
|
||||
json := `{
|
||||
func TestHashtagIndexes(t *testing.T) {
|
||||
var exampleJSON = `{
|
||||
"vals": [
|
||||
[
|
||||
2,
|
||||
2,
|
||||
{
|
||||
"wut",
|
||||
"yup"
|
||||
}
|
||||
],
|
||||
[
|
||||
4,
|
||||
5,
|
||||
6
|
||||
]
|
||||
[1,66,{test: 3}],
|
||||
[4,5,[6]]
|
||||
],
|
||||
"objectArray":[
|
||||
{"first": "Dale", "age": 44},
|
||||
{"first": "Roger", "age": 68},
|
||||
]
|
||||
}`
|
||||
r := Get(json, `vals.#.2`)
|
||||
fmt.Println(r.ArrayIndex)
|
||||
fmt.Println(string(json[37]))
|
||||
|
||||
all := Get(json, `@this`)
|
||||
testCases := []struct {
|
||||
path string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
`vals.#.1`,
|
||||
[]string{`6`, "5"},
|
||||
},
|
||||
{
|
||||
`vals.#.2`,
|
||||
[]string{"{", "["},
|
||||
},
|
||||
{
|
||||
`objectArray.#(age>43)#.first`,
|
||||
[]string{`"`, `"`},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
r := Get(exampleJSON, tc.path)
|
||||
|
||||
assert(t, len(r.HashtagIndexes) == len(tc.expected))
|
||||
|
||||
for i, a := range r.HashtagIndexes {
|
||||
assert(t, string(exampleJSON[a]) == tc.expected[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashtagIndexesMatchesRaw(t *testing.T) {
|
||||
var exampleJSON = `{
|
||||
"objectArray":[
|
||||
{"first": "Dale", "age": 44},
|
||||
{"first": "Roger", "age": 68},
|
||||
]
|
||||
}`
|
||||
r := Get(exampleJSON, `objectArray.#(age>43)#.first`)
|
||||
all := Get(exampleJSON, `@this`)
|
||||
all.ForEach(func(_, value Result) bool {
|
||||
println(value.Raw, "index", value.Index)
|
||||
println(string(json[value.Index : value.Index+len(value.Raw)]))
|
||||
if value.IsArray() {
|
||||
value.ForEach(func(_, v Result) bool {
|
||||
println(v.Raw, "index", v.Index)
|
||||
parentIndex := value.Index + v.Index
|
||||
println(string(json[parentIndex : parentIndex+len(v.Raw)]))
|
||||
|
||||
if v.IsArray() {
|
||||
v.ForEach(func(_, sv Result) bool {
|
||||
println(sv.Raw, "index", sv.Index+parentIndex)
|
||||
println(string(json[sv.Index+parentIndex : sv.Index+parentIndex+len(sv.Raw)]))
|
||||
if sv.IsObject() {
|
||||
assert(t, string(exampleJSON[r.HashtagIndexes[0]:r.HashtagIndexes[0]+len(sv.Raw)]) == sv.Raw)
|
||||
}
|
||||
if sv.IsArray() {
|
||||
assert(t, string(exampleJSON[r.HashtagIndexes[1]:r.HashtagIndexes[1]+len(sv.Raw)]) == sv.Raw)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
return true // keep iterating
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue