forked from mirror/gjson
Merge pull request #222 from sspaink/arrayindex
Add support to return multiple indexes when multiple matches are found
This commit is contained in:
commit
52919fa7b0
11
README.md
11
README.md
|
@ -123,11 +123,12 @@ nil, for JSON null
|
||||||
To directly access the value:
|
To directly access the value:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
result.Type // can be String, Number, True, False, Null, or JSON
|
result.Type // can be String, Number, True, False, Null, or JSON
|
||||||
result.Str // holds the string
|
result.Str // holds the string
|
||||||
result.Num // holds the float64 number
|
result.Num // holds the float64 number
|
||||||
result.Raw // holds the raw json
|
result.Raw // holds the raw json
|
||||||
result.Index // index of raw value in original json, zero means index unknown
|
result.Index // index of raw value in original json, zero means index unknown
|
||||||
|
result.Indexes // Indexes 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:
|
There are a variety of handy functions that work on a result:
|
||||||
|
|
23
gjson.go
23
gjson.go
|
@ -64,6 +64,8 @@ type Result struct {
|
||||||
Num float64
|
Num float64
|
||||||
// Index of raw value in original json, zero means index unknown
|
// Index of raw value in original json, zero means index unknown
|
||||||
Index int
|
Index int
|
||||||
|
// Indexes contains the Indexes of the elements returned by a query containing the '#' character
|
||||||
|
Indexes []int
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of the value.
|
// String returns a string representation of the value.
|
||||||
|
@ -1261,6 +1263,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
var alog []int
|
var alog []int
|
||||||
var partidx int
|
var partidx int
|
||||||
var multires []byte
|
var multires []byte
|
||||||
|
var queryIndexes []int
|
||||||
rp := parseArrayPath(path)
|
rp := parseArrayPath(path)
|
||||||
if !rp.arrch {
|
if !rp.arrch {
|
||||||
n, ok := parseUint(rp.part)
|
n, ok := parseUint(rp.part)
|
||||||
|
@ -1281,6 +1284,10 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
multires = append(multires, '[')
|
multires = append(multires, '[')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var tmp parseContext
|
||||||
|
tmp.value = qval
|
||||||
|
fillIndex(c.json, &tmp)
|
||||||
|
parentIndex := tmp.value.Index
|
||||||
var res Result
|
var res Result
|
||||||
if qval.Type == JSON {
|
if qval.Type == JSON {
|
||||||
res = qval.Get(rp.query.path)
|
res = qval.Get(rp.query.path)
|
||||||
|
@ -1312,6 +1319,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
multires = append(multires, ',')
|
multires = append(multires, ',')
|
||||||
}
|
}
|
||||||
multires = append(multires, raw...)
|
multires = append(multires, raw...)
|
||||||
|
queryIndexes = append(queryIndexes, res.Index+parentIndex)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.value = res
|
c.value = res
|
||||||
|
@ -1476,6 +1484,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
c.pipe = right
|
c.pipe = right
|
||||||
c.piped = true
|
c.piped = true
|
||||||
}
|
}
|
||||||
|
var indexes = make([]int, 0, 64)
|
||||||
var jsons = make([]byte, 0, 64)
|
var jsons = make([]byte, 0, 64)
|
||||||
jsons = append(jsons, '[')
|
jsons = append(jsons, '[')
|
||||||
for j, k := 0, 0; j < len(alog); j++ {
|
for j, k := 0, 0; j < len(alog); j++ {
|
||||||
|
@ -1490,6 +1499,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
}
|
}
|
||||||
if idx < len(c.json) && c.json[idx] != ']' {
|
if idx < len(c.json) && c.json[idx] != ']' {
|
||||||
_, res, ok := parseAny(c.json, idx, true)
|
_, res, ok := parseAny(c.json, idx, true)
|
||||||
|
parentIndex := res.Index
|
||||||
if ok {
|
if ok {
|
||||||
res := res.Get(rp.alogkey)
|
res := res.Get(rp.alogkey)
|
||||||
if res.Exists() {
|
if res.Exists() {
|
||||||
|
@ -1501,6 +1511,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
raw = res.String()
|
raw = res.String()
|
||||||
}
|
}
|
||||||
jsons = append(jsons, []byte(raw)...)
|
jsons = append(jsons, []byte(raw)...)
|
||||||
|
indexes = append(indexes, res.Index+parentIndex)
|
||||||
k++
|
k++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1509,6 +1520,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
jsons = append(jsons, ']')
|
jsons = append(jsons, ']')
|
||||||
c.value.Type = JSON
|
c.value.Type = JSON
|
||||||
c.value.Raw = string(jsons)
|
c.value.Raw = string(jsons)
|
||||||
|
c.value.Indexes = indexes
|
||||||
return i + 1, true
|
return i + 1, true
|
||||||
}
|
}
|
||||||
if rp.alogok {
|
if rp.alogok {
|
||||||
|
@ -1524,8 +1536,9 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
if !c.value.Exists() {
|
if !c.value.Exists() {
|
||||||
if len(multires) > 0 {
|
if len(multires) > 0 {
|
||||||
c.value = Result{
|
c.value = Result{
|
||||||
Raw: string(append(multires, ']')),
|
Raw: string(append(multires, ']')),
|
||||||
Type: JSON,
|
Type: JSON,
|
||||||
|
Indexes: queryIndexes,
|
||||||
}
|
}
|
||||||
} else if rp.query.all {
|
} else if rp.query.all {
|
||||||
c.value = Result{
|
c.value = Result{
|
||||||
|
@ -1806,6 +1819,7 @@ func Get(json, path string) Result {
|
||||||
if len(path) > 0 && (path[0] == '|' || path[0] == '.') {
|
if len(path) > 0 && (path[0] == '|' || path[0] == '.') {
|
||||||
res := Get(rjson, path[1:])
|
res := Get(rjson, path[1:])
|
||||||
res.Index = 0
|
res.Index = 0
|
||||||
|
res.Indexes = nil
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
return Parse(rjson)
|
return Parse(rjson)
|
||||||
|
@ -2046,7 +2060,10 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
|
||||||
res.Raw = val
|
res.Raw = val
|
||||||
res.Type = JSON
|
res.Type = JSON
|
||||||
}
|
}
|
||||||
return i, res, true
|
var tmp parseContext
|
||||||
|
tmp.value = res
|
||||||
|
fillIndex(json, &tmp)
|
||||||
|
return i, tmp.value, true
|
||||||
}
|
}
|
||||||
if json[i] <= ' ' {
|
if json[i] <= ' ' {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1291,10 +1291,10 @@ func TestArrayValues(t *testing.T) {
|
||||||
}
|
}
|
||||||
expect := strings.Join([]string{
|
expect := strings.Join([]string{
|
||||||
`gjson.Result{Type:3, Raw:"\"PERSON1\"", Str:"PERSON1", Num:0, ` +
|
`gjson.Result{Type:3, Raw:"\"PERSON1\"", Str:"PERSON1", Num:0, ` +
|
||||||
`Index:0}`,
|
`Index:0, Indexes:[]int(nil)}`,
|
||||||
`gjson.Result{Type:3, Raw:"\"PERSON2\"", Str:"PERSON2", Num:0, ` +
|
`gjson.Result{Type:3, Raw:"\"PERSON2\"", Str:"PERSON2", Num:0, ` +
|
||||||
`Index:0}`,
|
`Index:0, Indexes:[]int(nil)}`,
|
||||||
`gjson.Result{Type:2, Raw:"0", Str:"", Num:0, Index:0}`,
|
`gjson.Result{Type:2, Raw:"0", Str:"", Num:0, Index:0, Indexes:[]int(nil)}`,
|
||||||
}, "\n")
|
}, "\n")
|
||||||
if output != expect {
|
if output != expect {
|
||||||
t.Fatalf("expected '%v', got '%v'", expect, output)
|
t.Fatalf("expected '%v', got '%v'", expect, output)
|
||||||
|
@ -2119,4 +2119,80 @@ func TestModifierDoubleQuotes(t *testing.T) {
|
||||||
`{"name":"Product P4","value":"{\"productId\":\"1cc3\",\"vendorId\":\"20de\"}"},`+
|
`{"name":"Product P4","value":"{\"productId\":\"1cc3\",\"vendorId\":\"20de\"}"},`+
|
||||||
`{"name":"Product P4","value":"{\"productId\":\"1dd3\",\"vendorId\":\"30de\"}"}`+
|
`{"name":"Product P4","value":"{\"productId\":\"1dd3\",\"vendorId\":\"30de\"}"}`+
|
||||||
`]`)
|
`]`)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIndexes(t *testing.T) {
|
||||||
|
var exampleJSON = `{
|
||||||
|
"vals": [
|
||||||
|
[1,66,{test: 3}],
|
||||||
|
[4,5,[6]]
|
||||||
|
],
|
||||||
|
"objectArray":[
|
||||||
|
{"first": "Dale", "age": 44},
|
||||||
|
{"first": "Roger", "age": 68},
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
path string
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
`vals.#.1`,
|
||||||
|
[]string{`6`, "5"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`vals.#.2`,
|
||||||
|
[]string{"{", "["},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`objectArray.#(age>43)#.first`,
|
||||||
|
[]string{`"`, `"`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`objectArray.@reverse.#.first`,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
r := Get(exampleJSON, tc.path)
|
||||||
|
|
||||||
|
assert(t, len(r.Indexes) == len(tc.expected))
|
||||||
|
|
||||||
|
for i, a := range r.Indexes {
|
||||||
|
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 {
|
||||||
|
if value.IsArray() {
|
||||||
|
value.ForEach(func(_, v Result) bool {
|
||||||
|
if v.IsArray() {
|
||||||
|
v.ForEach(func(_, sv Result) bool {
|
||||||
|
if sv.IsObject() {
|
||||||
|
assert(t, string(exampleJSON[r.Indexes[0]:r.Indexes[0]+len(sv.Raw)]) == sv.Raw)
|
||||||
|
}
|
||||||
|
if sv.IsArray() {
|
||||||
|
assert(t, string(exampleJSON[r.Indexes[1]:r.Indexes[1]+len(sv.Raw)]) == sv.Raw)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue