diff --git a/README.md b/README.md index 35c175d..276b05d 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,9 @@ The dot and wildcard characters can be escaped with '\'. "children": ["Sara","Alex","Jack"], "fav.movie": "Deer Hunter", "friends": [ - {"first": "James", "last": "Murphy"}, - {"first": "Roger", "last": "Craig"} + {"first": "Dale", "last": "Murphy"}, + {"first": "Roger", "last": "Craig"}, + {"first": "Jane", "last": "Murphy"} ] } ``` @@ -80,12 +81,16 @@ The dot and wildcard characters can be escaped with '\'. "child*.2" >> "Jack" "c?ildren.0" >> "Sara" "fav\.movie" >> "Deer Hunter" -"friends.#.first" >> ["James","Roger"] +"friends.#.first" >> ["Dale","Roger","Jane"] "friends.1.last" >> "Craig" ``` -To query an array: +To query an array for the first match: ``` -`friends.#[last="Murphy"].first` >> "James" +`friends.#[last="Murphy"].first` >> "Dale" +``` +To query an array for all matches: +``` +`friends.#[last="Murphy"]#.first` >> ["Dale","Jane"] ``` ## Result Type diff --git a/gjson.go b/gjson.go index f538bfa..1f077fa 100644 --- a/gjson.go +++ b/gjson.go @@ -554,6 +554,7 @@ type arrayPathResult struct { path string op string value string + all bool } } @@ -644,6 +645,9 @@ func parseArrayPath(path string) (r arrayPathResult) { } } } else if path[i] == ']' { + if i+1 < len(path) && path[i+1] == '#' { + r.query.all = true + } break } } @@ -975,6 +979,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { var h int var alog []int var partidx int + var multires []byte rp := parseArrayPath(path) if !rp.arrch { n, err := strconv.ParseUint(rp.part, 10, 64) @@ -1031,12 +1036,21 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { res := Get(val, rp.query.path) if queryMatches(&rp, res) { if rp.more { - c.value = Get(val, rp.path) + res = Get(val, rp.path) } else { - c.value.Raw = val - c.value.Type = JSON + res = Result{Raw: val, Type: JSON} + } + if rp.query.all { + if len(multires) == 0 { + multires = append(multires, '[') + } else { + multires = append(multires, ',') + } + multires = append(multires, res.Raw...) + } else { + c.value = res + return i, true } - return i, true } } else if hit { if rp.alogok { @@ -1123,6 +1137,12 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { return i + 1, true } } + if len(multires) > 0 && !c.value.Exists() { + c.value = Result{ + Raw: string(append(multires, ']')), + Type: JSON, + } + } return i + 1, false } break diff --git a/gjson_test.go b/gjson_test.go index e051ffb..466dd2e 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -107,17 +107,20 @@ var basicJSON = `{"age":100, "name":{"here":"B\\\"R"}, { "firstName": "Brett", "lastName": "McLaughlin", - "email": "aaaa" + "email": "aaaa", + "tag": "good" }, { "firstName": "Jason", "lastName": "Hunter", - "email": "bbbb" + "email": "bbbb", + "tag": "bad" }, { "firstName": "Elliotte", "lastName": "Harold", - "email": "cccc" + "email": "cccc", + "tag":, "good" }, { "firstName": 1002.3, @@ -152,10 +155,17 @@ func get(json, path string) Result { func TestBasic(t *testing.T) { var mtok Result - + mtok = get(basicJSON, `loggy.programmers.#[tag="good"].firstName`) + if mtok.String() != "Brett" { + t.Fatalf("expected %v, got %v", "Brett", mtok.String()) + } + mtok = get(basicJSON, `loggy.programmers.#[tag="good"]#.firstName`) + if mtok.String() != `["Brett","Elliotte"]` { + t.Fatalf("expected %v, got %v", `["Brett","Elliotte"]`, mtok.String()) + } mtok = get(basicJSON, `loggy.programmers.#[age=101].firstName`) if mtok.String() != "1002.3" { - t.Fatalf("expected %v, got %v", "1002,3", mtok.String()) + t.Fatalf("expected %v, got %v", "1002.3", mtok.String()) } mtok = get(basicJSON, `loggy.programmers.#[firstName == "Brett"].email`)