diff --git a/gjson.go b/gjson.go index 8e6c099..fa73c7e 100644 --- a/gjson.go +++ b/gjson.go @@ -64,6 +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 } // String returns a string representation of the value. @@ -1476,6 +1478,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { c.pipe = right c.piped = true } + var arrayIndex = make([]int, 0, 64) var jsons = make([]byte, 0, 64) jsons = append(jsons, '[') for j, k := 0, 0; j < len(alog); j++ { @@ -1490,6 +1493,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } if idx < len(c.json) && c.json[idx] != ']' { _, res, ok := parseAny(c.json, idx, true) + parentIndex := res.Index if ok { res := res.Get(rp.alogkey) if res.Exists() { @@ -1501,6 +1505,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) k++ } } @@ -1509,6 +1514,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 return i + 1, true } if rp.alogok { @@ -2046,7 +2052,10 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { res.Raw = val res.Type = JSON } - return i, res, true + var c parseContext + c.value = res + fillIndex(json, &c) + return i, c.value, true } if json[i] <= ' ' { continue diff --git a/gjson_test.go b/gjson_test.go index 6bc445e..9c650e5 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -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"} @@ -922,7 +922,7 @@ var complicatedJSON = ` "nestedTagged": { "Green": "Green", "Map": { - "this": "that", + "this": "that", "and": "the other thing" }, "Ints": { @@ -1492,7 +1492,7 @@ func TestDeepSelectors(t *testing.T) { } }, { - "first": "Roger", "last": "Craig", + "first": "Roger", "last": "Craig", "extra": [40,50,60], "details": { "city": "Phoenix", @@ -2119,4 +2119,51 @@ func TestModifierDoubleQuotes(t *testing.T) { `{"name":"Product P4","value":"{\"productId\":\"1cc3\",\"vendorId\":\"20de\"}"},`+ `{"name":"Product P4","value":"{\"productId\":\"1dd3\",\"vendorId\":\"30de\"}"}`+ `]`) + +} + +func TestArrayIndex(t *testing.T) { + json := `{ + "vals": [ + [ + 2, + 2, + { + "wut", + "yup" + } + ], + [ + 4, + 5, + 6 + ] + ] + }` + r := Get(json, `vals.#.2`) + fmt.Println(r.ArrayIndex) + fmt.Println(string(json[37])) + + all := Get(json, `@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)])) + return true + }) + } + return true + }) + } + return true // keep iterating + }) }