Skip to content

Commit

Permalink
Added Escape function
Browse files Browse the repository at this point in the history
This commit adds the Escape function for escaping a path
component, making it possible to directly querying keys that have
special characters like dots.

```
json := `{
  "user":{
      "first.name": "Janet",
      "last.name": "Prichard"
    }
}`
user := gjson.Get(json, "user")
println(user.Get(gjson.Escape("first.name")).String())
println(user.Get(gjson.Escape("last.name")).String())
// Output:
// Janet
// Prichard
```

See #333
  • Loading branch information
tidwall committed Sep 22, 2023
1 parent be1bb7d commit 6ee9f87
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 8 deletions.
30 changes: 22 additions & 8 deletions gjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -3410,7 +3410,7 @@ func (t Result) Path(json string) string {
if !rcomp.Exists() {
goto fail
}
comp := escapeComp(rcomp.String())
comp := Escape(rcomp.String())
path = append(path, '.')
path = append(path, comp...)
}
Expand All @@ -3425,17 +3425,31 @@ fail:
// isSafePathKeyChar returns true if the input character is safe for not
// needing escaping.
func isSafePathKeyChar(c byte) bool {
return c <= ' ' || c > '~' || c == '_' || c == '-' || c == ':' ||
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9')
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c <= ' ' || c > '~' || c == '_' ||
c == '-' || c == ':'
}

// escapeComp escaped a path compontent, making it safe for generating a
// path for later use.
func escapeComp(comp string) string {
// Escape returns an escaped path component.
//
// json := `{
// "user":{
// "first.name": "Janet",
// "last.name": "Prichard"
// }
// }`
// user := gjson.Get(json, "user")
// println(user.Get(gjson.Escape("first.name"))
// println(user.Get(gjson.Escape("last.name"))
// // Output:
// // Janet
// // Prichard
func Escape(comp string) string {
for i := 0; i < len(comp); i++ {
if !isSafePathKeyChar(comp[i]) {
ncomp := []byte(comp[:i])
ncomp := make([]byte, len(comp)+1)
copy(ncomp, comp[:i])
ncomp = ncomp[:i]
for ; i < len(comp); i++ {
if !isSafePathKeyChar(comp[i]) {
ncomp = append(ncomp, '\\')
Expand Down
13 changes: 13 additions & 0 deletions gjson_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2701,3 +2701,16 @@ func TestModDig(t *testing.T) {
assert(t, Get(json, "@dig:name").String() == `["melinda","jake"]`)
assert(t, Get(json, "@dig:secret").String() == `["password"]`)
}

func TestEscape(t *testing.T) {
json := `{
"user":{
"first.name": "Janet",
"last.name": "Prichard"
}
}`
user := Get(json, "user")
assert(t, user.Get(Escape("first.name")).String() == "Janet")
assert(t, user.Get(Escape("last.name")).String() == "Prichard")
assert(t, user.Get("first.name").String() == "")
}

0 comments on commit 6ee9f87

Please sign in to comment.