Does JsonPath supports escaping?
paulo-raca opened this issue ยท 13 comments
I Know that JsonPath syntax is not very strictly defined ๐, but is it possible to select weird field names (containing '
and \
)?
My preliminary tests suggest it doesn't work. Am I doing something wrong?
func TestEscaping(t *testing.T) {
data := map[string]any{
`\`: "ok",
}
expr, err := jp.ParseString(`$['\\']`)
assert.NoError(t, err)
assert.Equal(t, []any{"ok"}, expr.Get(data))
}
Thanks!
Sorry for the slow reply. The block syntax is what you want to use as you figured out. I expect that to work so let me look into it and get it fixed.
https://datatracker.ietf.org/doc/draft-ietf-jsonpath-base is the most comprehensive spec so far for JSONPath.
I can confirm it is a bug. I'll try to get it fixed this weekend.
Sorry for the slow reply
Not slow at all. Thank you very much! ๐
Please try the jsonpath-escape branch. I have to add more tests to get the coverage back up but I believe the issue is fixed.
Tests added and ready to merge.
Awesome, thank you! ๐
I looked briefly at your branch and it looks great
The only thing I'm not sure about is if you would need to check out-of-bound when handling escaped chars in readEscStr()
. E.g., \
, \x
, \x1
, \u123
Awesome, thank you! ๐
I looked briefly at your branch and it looks great
The only thing I'm not sure about is if you would need to check out-of-bound when handling escaped chars in readEscStr()
. E.g., \
, \x
, \x1
, \u123
I added a few tests to make sure that was covered. It should be in the release I make tonight.
Released v1.18.2
Thanks you!
Hey, @ohler55 :
I have a complimentary question, is there a function to build JsonPaths?
In particular the escaping bit is never trivial :)
What I have right now is this:
// Valid identifiers in `.fieldName` syntax are not clearly defined anywhere,
// so we use a generic/conservative pattern and fallback to ['fieldName'] otherwise
var validNameRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z_0-9]*$")
func NewJsonPathString(path ...any) string {
ret := "$"
for _, v := range path {
switch vv := (v).(type) {
case int, int8, int16, int32, int64:
// Array index, use `[index]` syntax
ret = fmt.Sprintf("%s[%d]", ret, vv)
case string:
if validNameRegex.Match([]byte(vv)) {
// Simple field name, `.fieldName` syntax
ret = fmt.Sprintf("%s.%s", ret, v)
} else {
// Complex field name, use `['fieldName']` syntax
// FIXME, this is terrible
vv = strings.ReplaceAll(vv, `\`, `\\`)
vv = strings.ReplaceAll(vv, `'`, `\'`)
ret = fmt.Sprintf("%s['%s']", ret, vv)
}
default:
panic(fmt.Errorf("Invalid JSON Path token: %v", v))
}
}
return ret
}
Example:
NewJsonPathString("foo_bar56", 19, "๐", 1, "5")
-> "$.foo_bar56[19]['๐'][1]['5']"
This is a completely different issue. Well not really and issue more like a question. Yes there are functions to build JSONPaths. Looks at the Expr functions here: https://pkg.go.dev/github.com/ohler55/ojg/jp
I'll close this issue later today. If you still have questions please start a discussion instead.
Thanks for the pointers!
And sorry for reusing it this issue, I'll open a new one to continue