diff --git a/gjson.go b/gjson.go index 7ab8c54..a48b687 100644 --- a/gjson.go +++ b/gjson.go @@ -714,10 +714,10 @@ type arrayPathResult struct { alogkey string query struct { on bool + all bool path string op string value string - all bool } } @@ -750,14 +750,23 @@ func parseArrayPath(path string) (r arrayPathResult) { } else if path[1] == '[' || path[1] == '(' { // query r.query.on = true - qpath, op, value, _, fi, ok := parseQuery(path[i:]) + qpath, op, value, _, fi, vesc, ok := + parseQuery(path[i:]) if !ok { // bad query, end now break } + if len(value) > 2 && value[0] == '"' && + value[len(value)-1] == '"' { + value = value[1 : len(value)-1] + if vesc { + value = unescape(value) + } + } r.query.path = qpath r.query.op = op r.query.value = value + i = fi - 1 if i+1 < len(path) && path[i+1] == '#' { r.query.all = true @@ -787,11 +796,11 @@ func parseArrayPath(path string) (r arrayPathResult) { // # middle // .cap # right func parseQuery(query string) ( - path, op, value, remain string, i int, ok bool, + path, op, value, remain string, i int, vesc, ok bool, ) { if len(query) < 2 || query[0] != '#' || (query[1] != '(' && query[1] != '[') { - return "", "", "", "", i, false + return "", "", "", "", i, false, false } i = 2 j := 0 // start of value part @@ -819,6 +828,7 @@ func parseQuery(query string) ( i++ for ; i < len(query); i++ { if query[i] == '\\' { + vesc = true i++ } else if query[i] == '"' { break @@ -827,7 +837,7 @@ func parseQuery(query string) ( } } if depth > 0 { - return "", "", "", "", i, false + return "", "", "", "", i, false, false } if j > 0 { path = trim(query[2:j]) @@ -864,7 +874,7 @@ func parseQuery(query string) ( path = trim(query[2:i]) remain = query[i+1:] } - return path, op, value, remain, i + 1, true + return path, op, value, remain, i + 1, vesc, true } func trim(s string) string { @@ -1164,9 +1174,6 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } func queryMatches(rp *arrayPathResult, value Result) bool { rpv := rp.query.value - if len(rpv) > 2 && rpv[0] == '"' && rpv[len(rpv)-1] == '"' { - rpv = rpv[1 : len(rpv)-1] - } if !value.Exists() { return false } diff --git a/gjson_test.go b/gjson_test.go index 0c723f7..90173e6 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -1741,7 +1741,7 @@ func TestParseQuery(t *testing.T) { var path, op, value, remain string var ok bool - path, op, value, remain, _, ok = + path, op, value, remain, _, _, ok = parseQuery(`#(service_roles.#(=="one").()==asdf).cap`) assert(t, ok && path == `service_roles.#(=="one").()` && @@ -1749,28 +1749,28 @@ func TestParseQuery(t *testing.T) { value == `asdf` && remain == `.cap`) - path, op, value, remain, _, ok = parseQuery(`#(first_name%"Murphy").last`) + path, op, value, remain, _, _, ok = parseQuery(`#(first_name%"Murphy").last`) assert(t, ok && path == `first_name` && op == `%` && value == `"Murphy"` && remain == `.last`) - path, op, value, remain, _, ok = parseQuery(`#( first_name !% "Murphy" ).last`) + path, op, value, remain, _, _, ok = parseQuery(`#( first_name !% "Murphy" ).last`) assert(t, ok && path == `first_name` && op == `!%` && value == `"Murphy"` && remain == `.last`) - path, op, value, remain, _, ok = parseQuery(`#(service_roles.#(=="one"))`) + path, op, value, remain, _, _, ok = parseQuery(`#(service_roles.#(=="one"))`) assert(t, ok && path == `service_roles.#(=="one")` && op == `` && value == `` && remain == ``) - path, op, value, remain, _, ok = + path, op, value, remain, _, _, ok = parseQuery(`#(a\("\"(".#(=="o\"(ne")%"ab\")").remain`) assert(t, ok && path == `a\("\"(".#(=="o\"(ne")` && @@ -2052,3 +2052,15 @@ func TestPipeEmptyArray(t *testing.T) { raw := Get("[]", `#(hello)#`).Raw assert(t, raw == "[]") } + +func TestEncodedQueryString(t *testing.T) { + json := `{ + "friends": [ + {"first": "Dale", "last": "Mur\nphy", "age": 44}, + {"first": "Roger", "last": "Craig", "age": 68}, + {"first": "Jane", "last": "Murphy", "age": 47} + ] + }` + assert(t, Get(json, `friends.#(last=="Mur\nphy").age`).Int() == 44) + assert(t, Get(json, `friends.#(last=="Murphy").age`).Int() == 47) +}