1// Package gjson provides searching for json strings.
2package gjson
3
4import (
5 "strconv"
6 "strings"
7 "time"
8 "unicode/utf16"
9 "unicode/utf8"
10 "unsafe"
11
12 "github.com/tidwall/match"
13 "github.com/tidwall/pretty"
14)
15
16// Type is Result type
17type Type int
18
19const (
20 // Null is a null json value
21 Null Type = iota
22 // False is a json false boolean
23 False
24 // Number is json number
25 Number
26 // String is a json string
27 String
28 // True is a json true boolean
29 True
30 // JSON is a raw block of JSON
31 JSON
32)
33
34// String returns a string representation of the type.
35func (t Type) String() string {
36 switch t {
37 default:
38 return ""
39 case Null:
40 return "Null"
41 case False:
42 return "False"
43 case Number:
44 return "Number"
45 case String:
46 return "String"
47 case True:
48 return "True"
49 case JSON:
50 return "JSON"
51 }
52}
53
54// Result represents a json value that is returned from Get().
55type Result struct {
56 // Type is the json type
57 Type Type
58 // Raw is the raw json
59 Raw string
60 // Str is the json string
61 Str string
62 // Num is the json number
63 Num float64
64 // Index of raw value in original json, zero means index unknown
65 Index int
66 // Indexes of all the elements that match on a path containing the '#'
67 // query character.
68 Indexes []int
69}
70
71// String returns a string representation of the value.
72func (t Result) String() string {
73 switch t.Type {
74 default:
75 return ""
76 case False:
77 return "false"
78 case Number:
79 if len(t.Raw) == 0 {
80 // calculated result
81 return strconv.FormatFloat(t.Num, 'f', -1, 64)
82 }
83 var i int
84 if t.Raw[0] == '-' {
85 i++
86 }
87 for ; i < len(t.Raw); i++ {
88 if t.Raw[i] < '0' || t.Raw[i] > '9' {
89 return strconv.FormatFloat(t.Num, 'f', -1, 64)
90 }
91 }
92 return t.Raw
93 case String:
94 return t.Str
95 case JSON:
96 return t.Raw
97 case True:
98 return "true"
99 }
100}
101
102// Bool returns an boolean representation.
103func (t Result) Bool() bool {
104 switch t.Type {
105 default:
106 return false
107 case True:
108 return true
109 case String:
110 b, _ := strconv.ParseBool(strings.ToLower(t.Str))
111 return b
112 case Number:
113 return t.Num != 0
114 }
115}
116
117// Int returns an integer representation.
118func (t Result) Int() int64 {
119 switch t.Type {
120 default:
121 return 0
122 case True:
123 return 1
124 case String:
125 n, _ := parseInt(t.Str)
126 return n
127 case Number:
128 // try to directly convert the float64 to int64
129 i, ok := safeInt(t.Num)
130 if ok {
131 return i
132 }
133 // now try to parse the raw string
134 i, ok = parseInt(t.Raw)
135 if ok {
136 return i
137 }
138 // fallback to a standard conversion
139 return int64(t.Num)
140 }
141}
142
143// Uint returns an unsigned integer representation.
144func (t Result) Uint() uint64 {
145 switch t.Type {
146 default:
147 return 0
148 case True:
149 return 1
150 case String:
151 n, _ := parseUint(t.Str)
152 return n
153 case Number:
154 // try to directly convert the float64 to uint64
155 i, ok := safeInt(t.Num)
156 if ok && i >= 0 {
157 return uint64(i)
158 }
159 // now try to parse the raw string
160 u, ok := parseUint(t.Raw)
161 if ok {
162 return u
163 }
164 // fallback to a standard conversion
165 return uint64(t.Num)
166 }
167}
168
169// Float returns an float64 representation.
170func (t Result) Float() float64 {
171 switch t.Type {
172 default:
173 return 0
174 case True:
175 return 1
176 case String:
177 n, _ := strconv.ParseFloat(t.Str, 64)
178 return n
179 case Number:
180 return t.Num
181 }
182}
183
184// Time returns a time.Time representation.
185func (t Result) Time() time.Time {
186 res, _ := time.Parse(time.RFC3339, t.String())
187 return res
188}
189
190// Array returns back an array of values.
191// If the result represents a null value or is non-existent, then an empty
192// array will be returned.
193// If the result is not a JSON array, the return value will be an
194// array containing one result.
195func (t Result) Array() []Result {
196 if t.Type == Null {
197 return []Result{}
198 }
199 if !t.IsArray() {
200 return []Result{t}
201 }
202 r := t.arrayOrMap('[', false)
203 return r.a
204}
205
206// IsObject returns true if the result value is a JSON object.
207func (t Result) IsObject() bool {
208 return t.Type == JSON && len(t.Raw) > 0 && t.Raw[0] == '{'
209}
210
211// IsArray returns true if the result value is a JSON array.
212func (t Result) IsArray() bool {
213 return t.Type == JSON && len(t.Raw) > 0 && t.Raw[0] == '['
214}
215
216// IsBool returns true if the result value is a JSON boolean.
217func (t Result) IsBool() bool {
218 return t.Type == True || t.Type == False
219}
220
221// ForEach iterates through values.
222// If the result represents a non-existent value, then no values will be
223// iterated. If the result is an Object, the iterator will pass the key and
224// value of each item. If the result is an Array, the iterator will only pass
225// the value of each item. If the result is not a JSON array or object, the
226// iterator will pass back one value equal to the result.
227func (t Result) ForEach(iterator func(key, value Result) bool) {
228 if !t.Exists() {
229 return
230 }
231 if t.Type != JSON {
232 iterator(Result{}, t)
233 return
234 }
235 json := t.Raw
236 var obj bool
237 var i int
238 var key, value Result
239 for ; i < len(json); i++ {
240 if json[i] == '{' {
241 i++
242 key.Type = String
243 obj = true
244 break
245 } else if json[i] == '[' {
246 i++
247 key.Type = Number
248 key.Num = -1
249 break
250 }
251 if json[i] > ' ' {
252 return
253 }
254 }
255 var str string
256 var vesc bool
257 var ok bool
258 var idx int
259 for ; i < len(json); i++ {
260 if obj {
261 if json[i] != '"' {
262 continue
263 }
264 s := i
265 i, str, vesc, ok = parseString(json, i+1)
266 if !ok {
267 return
268 }
269 if vesc {
270 key.Str = unescape(str[1 : len(str)-1])
271 } else {
272 key.Str = str[1 : len(str)-1]
273 }
274 key.Raw = str
275 key.Index = s + t.Index
276 } else {
277 key.Num += 1
278 }
279 for ; i < len(json); i++ {
280 if json[i] <= ' ' || json[i] == ',' || json[i] == ':' {
281 continue
282 }
283 break
284 }
285 s := i
286 i, value, ok = parseAny(json, i, true)
287 if !ok {
288 return
289 }
290 if t.Indexes != nil {
291 if idx < len(t.Indexes) {
292 value.Index = t.Indexes[idx]
293 }
294 } else {
295 value.Index = s + t.Index
296 }
297 if !iterator(key, value) {
298 return
299 }
300 idx++
301 }
302}
303
304// Map returns back a map of values. The result should be a JSON object.
305// If the result is not a JSON object, the return value will be an empty map.
306func (t Result) Map() map[string]Result {
307 if t.Type != JSON {
308 return map[string]Result{}
309 }
310 r := t.arrayOrMap('{', false)
311 return r.o
312}
313
314// Get searches result for the specified path.
315// The result should be a JSON array or object.
316func (t Result) Get(path string) Result {
317 r := Get(t.Raw, path)
318 if r.Indexes != nil {
319 for i := 0; i < len(r.Indexes); i++ {
320 r.Indexes[i] += t.Index
321 }
322 } else {
323 r.Index += t.Index
324 }
325 return r
326}
327
328type arrayOrMapResult struct {
329 a []Result
330 ai []interface{}
331 o map[string]Result
332 oi map[string]interface{}
333 vc byte
334}
335
336func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
337 var json = t.Raw
338 var i int
339 var value Result
340 var count int
341 var key Result
342 if vc == 0 {
343 for ; i < len(json); i++ {
344 if json[i] == '{' || json[i] == '[' {
345 r.vc = json[i]
346 i++
347 break
348 }
349 if json[i] > ' ' {
350 goto end
351 }
352 }
353 } else {
354 for ; i < len(json); i++ {
355 if json[i] == vc {
356 i++
357 break
358 }
359 if json[i] > ' ' {
360 goto end
361 }
362 }
363 r.vc = vc
364 }
365 if r.vc == '{' {
366 if valueize {
367 r.oi = make(map[string]interface{})
368 } else {
369 r.o = make(map[string]Result)
370 }
371 } else {
372 if valueize {
373 r.ai = make([]interface{}, 0)
374 } else {
375 r.a = make([]Result, 0)
376 }
377 }
378 for ; i < len(json); i++ {
379 if json[i] <= ' ' {
380 continue
381 }
382 // get next value
383 if json[i] == ']' || json[i] == '}' {
384 break
385 }
386 switch json[i] {
387 default:
388 if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
389 value.Type = Number
390 value.Raw, value.Num = tonum(json[i:])
391 value.Str = ""
392 } else {
393 continue
394 }
395 case '{', '[':
396 value.Type = JSON
397 value.Raw = squash(json[i:])
398 value.Str, value.Num = "", 0
399 case 'n':
400 value.Type = Null
401 value.Raw = tolit(json[i:])
402 value.Str, value.Num = "", 0
403 case 't':
404 value.Type = True
405 value.Raw = tolit(json[i:])
406 value.Str, value.Num = "", 0
407 case 'f':
408 value.Type = False
409 value.Raw = tolit(json[i:])
410 value.Str, value.Num = "", 0
411 case '"':
412 value.Type = String
413 value.Raw, value.Str = tostr(json[i:])
414 value.Num = 0
415 }
416 value.Index = i + t.Index
417
418 i += len(value.Raw) - 1
419
420 if r.vc == '{' {
421 if count%2 == 0 {
422 key = value
423 } else {
424 if valueize {
425 if _, ok := r.oi[key.Str]; !ok {
426 r.oi[key.Str] = value.Value()
427 }
428 } else {
429 if _, ok := r.o[key.Str]; !ok {
430 r.o[key.Str] = value
431 }
432 }
433 }
434 count++
435 } else {
436 if valueize {
437 r.ai = append(r.ai, value.Value())
438 } else {
439 r.a = append(r.a, value)
440 }
441 }
442 }
443end:
444 if t.Indexes != nil {
445 if len(t.Indexes) != len(r.a) {
446 for i := 0; i < len(r.a); i++ {
447 r.a[i].Index = 0
448 }
449 } else {
450 for i := 0; i < len(r.a); i++ {
451 r.a[i].Index = t.Indexes[i]
452 }
453 }
454 }
455 return
456}
457
458// Parse parses the json and returns a result.
459//
460// This function expects that the json is well-formed, and does not validate.
461// Invalid json will not panic, but it may return back unexpected results.
462// If you are consuming JSON from an unpredictable source then you may want to
463// use the Valid function first.
464func Parse(json string) Result {
465 var value Result
466 i := 0
467 for ; i < len(json); i++ {
468 if json[i] == '{' || json[i] == '[' {
469 value.Type = JSON
470 value.Raw = json[i:] // just take the entire raw
471 break
472 }
473 if json[i] <= ' ' {
474 continue
475 }
476 switch json[i] {
477 case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
478 'i', 'I', 'N':
479 value.Type = Number
480 value.Raw, value.Num = tonum(json[i:])
481 case 'n':
482 if i+1 < len(json) && json[i+1] != 'u' {
483 // nan
484 value.Type = Number
485 value.Raw, value.Num = tonum(json[i:])
486 } else {
487 // null
488 value.Type = Null
489 value.Raw = tolit(json[i:])
490 }
491 case 't':
492 value.Type = True
493 value.Raw = tolit(json[i:])
494 case 'f':
495 value.Type = False
496 value.Raw = tolit(json[i:])
497 case '"':
498 value.Type = String
499 value.Raw, value.Str = tostr(json[i:])
500 default:
501 return Result{}
502 }
503 break
504 }
505 if value.Exists() {
506 value.Index = i
507 }
508 return value
509}
510
511// ParseBytes parses the json and returns a result.
512// If working with bytes, this method preferred over Parse(string(data))
513func ParseBytes(json []byte) Result {
514 return Parse(string(json))
515}
516
517func squash(json string) string {
518 // expects that the lead character is a '[' or '{' or '(' or '"'
519 // squash the value, ignoring all nested arrays and objects.
520 var i, depth int
521 if json[0] != '"' {
522 i, depth = 1, 1
523 }
524 for ; i < len(json); i++ {
525 if json[i] >= '"' && json[i] <= '}' {
526 switch json[i] {
527 case '"':
528 i++
529 s2 := i
530 for ; i < len(json); i++ {
531 if json[i] > '\\' {
532 continue
533 }
534 if json[i] == '"' {
535 // look for an escaped slash
536 if json[i-1] == '\\' {
537 n := 0
538 for j := i - 2; j > s2-1; j-- {
539 if json[j] != '\\' {
540 break
541 }
542 n++
543 }
544 if n%2 == 0 {
545 continue
546 }
547 }
548 break
549 }
550 }
551 if depth == 0 {
552 if i >= len(json) {
553 return json
554 }
555 return json[:i+1]
556 }
557 case '{', '[', '(':
558 depth++
559 case '}', ']', ')':
560 depth--
561 if depth == 0 {
562 return json[:i+1]
563 }
564 }
565 }
566 }
567 return json
568}
569
570func tonum(json string) (raw string, num float64) {
571 for i := 1; i < len(json); i++ {
572 // less than dash might have valid characters
573 if json[i] <= '-' {
574 if json[i] <= ' ' || json[i] == ',' {
575 // break on whitespace and comma
576 raw = json[:i]
577 num, _ = strconv.ParseFloat(raw, 64)
578 return
579 }
580 // could be a '+' or '-'. let's assume so.
581 } else if json[i] == ']' || json[i] == '}' {
582 // break on ']' or '}'
583 raw = json[:i]
584 num, _ = strconv.ParseFloat(raw, 64)
585 return
586 }
587 }
588 raw = json
589 num, _ = strconv.ParseFloat(raw, 64)
590 return
591}
592
593func tolit(json string) (raw string) {
594 for i := 1; i < len(json); i++ {
595 if json[i] < 'a' || json[i] > 'z' {
596 return json[:i]
597 }
598 }
599 return json
600}
601
602func tostr(json string) (raw string, str string) {
603 // expects that the lead character is a '"'
604 for i := 1; i < len(json); i++ {
605 if json[i] > '\\' {
606 continue
607 }
608 if json[i] == '"' {
609 return json[:i+1], json[1:i]
610 }
611 if json[i] == '\\' {
612 i++
613 for ; i < len(json); i++ {
614 if json[i] > '\\' {
615 continue
616 }
617 if json[i] == '"' {
618 // look for an escaped slash
619 if json[i-1] == '\\' {
620 n := 0
621 for j := i - 2; j > 0; j-- {
622 if json[j] != '\\' {
623 break
624 }
625 n++
626 }
627 if n%2 == 0 {
628 continue
629 }
630 }
631 return json[:i+1], unescape(json[1:i])
632 }
633 }
634 var ret string
635 if i+1 < len(json) {
636 ret = json[:i+1]
637 } else {
638 ret = json[:i]
639 }
640 return ret, unescape(json[1:i])
641 }
642 }
643 return json, json[1:]
644}
645
646// Exists returns true if value exists.
647//
648// if gjson.Get(json, "name.last").Exists(){
649// println("value exists")
650// }
651func (t Result) Exists() bool {
652 return t.Type != Null || len(t.Raw) != 0
653}
654
655// Value returns one of these types:
656//
657// bool, for JSON booleans
658// float64, for JSON numbers
659// Number, for JSON numbers
660// string, for JSON string literals
661// nil, for JSON null
662// map[string]interface{}, for JSON objects
663// []interface{}, for JSON arrays
664func (t Result) Value() interface{} {
665 if t.Type == String {
666 return t.Str
667 }
668 switch t.Type {
669 default:
670 return nil
671 case False:
672 return false
673 case Number:
674 return t.Num
675 case JSON:
676 r := t.arrayOrMap(0, true)
677 if r.vc == '{' {
678 return r.oi
679 } else if r.vc == '[' {
680 return r.ai
681 }
682 return nil
683 case True:
684 return true
685 }
686}
687
688func parseString(json string, i int) (int, string, bool, bool) {
689 var s = i
690 for ; i < len(json); i++ {
691 if json[i] > '\\' {
692 continue
693 }
694 if json[i] == '"' {
695 return i + 1, json[s-1 : i+1], false, true
696 }
697 if json[i] == '\\' {
698 i++
699 for ; i < len(json); i++ {
700 if json[i] > '\\' {
701 continue
702 }
703 if json[i] == '"' {
704 // look for an escaped slash
705 if json[i-1] == '\\' {
706 n := 0
707 for j := i - 2; j > 0; j-- {
708 if json[j] != '\\' {
709 break
710 }
711 n++
712 }
713 if n%2 == 0 {
714 continue
715 }
716 }
717 return i + 1, json[s-1 : i+1], true, true
718 }
719 }
720 break
721 }
722 }
723 return i, json[s-1:], false, false
724}
725
726func parseNumber(json string, i int) (int, string) {
727 var s = i
728 i++
729 for ; i < len(json); i++ {
730 if json[i] <= ' ' || json[i] == ',' || json[i] == ']' ||
731 json[i] == '}' {
732 return i, json[s:i]
733 }
734 }
735 return i, json[s:]
736}
737
738func parseLiteral(json string, i int) (int, string) {
739 var s = i
740 i++
741 for ; i < len(json); i++ {
742 if json[i] < 'a' || json[i] > 'z' {
743 return i, json[s:i]
744 }
745 }
746 return i, json[s:]
747}
748
749type arrayPathResult struct {
750 part string
751 path string
752 pipe string
753 piped bool
754 more bool
755 alogok bool
756 arrch bool
757 alogkey string
758 query struct {
759 on bool
760 all bool
761 path string
762 op string
763 value string
764 }
765}
766
767func parseArrayPath(path string) (r arrayPathResult) {
768 for i := 0; i < len(path); i++ {
769 if path[i] == '|' {
770 r.part = path[:i]
771 r.pipe = path[i+1:]
772 r.piped = true
773 return
774 }
775 if path[i] == '.' {
776 r.part = path[:i]
777 if !r.arrch && i < len(path)-1 && isDotPiperChar(path[i+1:]) {
778 r.pipe = path[i+1:]
779 r.piped = true
780 } else {
781 r.path = path[i+1:]
782 r.more = true
783 }
784 return
785 }
786 if path[i] == '#' {
787 r.arrch = true
788 if i == 0 && len(path) > 1 {
789 if path[1] == '.' {
790 r.alogok = true
791 r.alogkey = path[2:]
792 r.path = path[:1]
793 } else if path[1] == '[' || path[1] == '(' {
794 // query
795 r.query.on = true
796 qpath, op, value, _, fi, vesc, ok :=
797 parseQuery(path[i:])
798 if !ok {
799 // bad query, end now
800 break
801 }
802 if len(value) >= 2 && value[0] == '"' &&
803 value[len(value)-1] == '"' {
804 value = value[1 : len(value)-1]
805 if vesc {
806 value = unescape(value)
807 }
808 }
809 r.query.path = qpath
810 r.query.op = op
811 r.query.value = value
812
813 i = fi - 1
814 if i+1 < len(path) && path[i+1] == '#' {
815 r.query.all = true
816 }
817 }
818 }
819 continue
820 }
821 }
822 r.part = path
823 r.path = ""
824 return
825}
826
827// splitQuery takes a query and splits it into three parts:
828//
829// path, op, middle, and right.
830//
831// So for this query:
832//
833// #(first_name=="Murphy").last
834//
835// Becomes
836//
837// first_name # path
838// =="Murphy" # middle
839// .last # right
840//
841// Or,
842//
843// #(service_roles.#(=="one")).cap
844//
845// Becomes
846//
847// service_roles.#(=="one") # path
848// # middle
849// .cap # right
850func parseQuery(query string) (
851 path, op, value, remain string, i int, vesc, ok bool,
852) {
853 if len(query) < 2 || query[0] != '#' ||
854 (query[1] != '(' && query[1] != '[') {
855 return "", "", "", "", i, false, false
856 }
857 i = 2
858 j := 0 // start of value part
859 depth := 1
860 for ; i < len(query); i++ {
861 if depth == 1 && j == 0 {
862 switch query[i] {
863 case '!', '=', '<', '>', '%':
864 // start of the value part
865 j = i
866 continue
867 }
868 }
869 if query[i] == '\\' {
870 i++
871 } else if query[i] == '[' || query[i] == '(' {
872 depth++
873 } else if query[i] == ']' || query[i] == ')' {
874 depth--
875 if depth == 0 {
876 break
877 }
878 } else if query[i] == '"' {
879 // inside selector string, balance quotes
880 i++
881 for ; i < len(query); i++ {
882 if query[i] == '\\' {
883 vesc = true
884 i++
885 } else if query[i] == '"' {
886 break
887 }
888 }
889 }
890 }
891 if depth > 0 {
892 return "", "", "", "", i, false, false
893 }
894 if j > 0 {
895 path = trim(query[2:j])
896 value = trim(query[j:i])
897 remain = query[i+1:]
898 // parse the compare op from the value
899 var opsz int
900 switch {
901 case len(value) == 1:
902 opsz = 1
903 case value[0] == '!' && value[1] == '=':
904 opsz = 2
905 case value[0] == '!' && value[1] == '%':
906 opsz = 2
907 case value[0] == '<' && value[1] == '=':
908 opsz = 2
909 case value[0] == '>' && value[1] == '=':
910 opsz = 2
911 case value[0] == '=' && value[1] == '=':
912 value = value[1:]
913 opsz = 1
914 case value[0] == '<':
915 opsz = 1
916 case value[0] == '>':
917 opsz = 1
918 case value[0] == '=':
919 opsz = 1
920 case value[0] == '%':
921 opsz = 1
922 }
923 op = value[:opsz]
924 value = trim(value[opsz:])
925 } else {
926 path = trim(query[2:i])
927 remain = query[i+1:]
928 }
929 return path, op, value, remain, i + 1, vesc, true
930}
931
932func trim(s string) string {
933left:
934 if len(s) > 0 && s[0] <= ' ' {
935 s = s[1:]
936 goto left
937 }
938right:
939 if len(s) > 0 && s[len(s)-1] <= ' ' {
940 s = s[:len(s)-1]
941 goto right
942 }
943 return s
944}
945
946// peek at the next byte and see if it's a '@', '[', or '{'.
947func isDotPiperChar(s string) bool {
948 if DisableModifiers {
949 return false
950 }
951 c := s[0]
952 if c == '@' {
953 // check that the next component is *not* a modifier.
954 i := 1
955 for ; i < len(s); i++ {
956 if s[i] == '.' || s[i] == '|' || s[i] == ':' {
957 break
958 }
959 }
960 _, ok := modifiers[s[1:i]]
961 return ok
962 }
963 return c == '[' || c == '{'
964}
965
966type objectPathResult struct {
967 part string
968 path string
969 pipe string
970 piped bool
971 wild bool
972 more bool
973}
974
975func parseObjectPath(path string) (r objectPathResult) {
976 for i := 0; i < len(path); i++ {
977 if path[i] == '|' {
978 r.part = path[:i]
979 r.pipe = path[i+1:]
980 r.piped = true
981 return
982 }
983 if path[i] == '.' {
984 r.part = path[:i]
985 if i < len(path)-1 && isDotPiperChar(path[i+1:]) {
986 r.pipe = path[i+1:]
987 r.piped = true
988 } else {
989 r.path = path[i+1:]
990 r.more = true
991 }
992 return
993 }
994 if path[i] == '*' || path[i] == '?' {
995 r.wild = true
996 continue
997 }
998 if path[i] == '\\' {
999 // go into escape mode. this is a slower path that
1000 // strips off the escape character from the part.
1001 epart := []byte(path[:i])
1002 i++
1003 if i < len(path) {
1004 epart = append(epart, path[i])
1005 i++
1006 for ; i < len(path); i++ {
1007 if path[i] == '\\' {
1008 i++
1009 if i < len(path) {
1010 epart = append(epart, path[i])
1011 }
1012 continue
1013 } else if path[i] == '.' {
1014 r.part = string(epart)
1015 if i < len(path)-1 && isDotPiperChar(path[i+1:]) {
1016 r.pipe = path[i+1:]
1017 r.piped = true
1018 } else {
1019 r.path = path[i+1:]
1020 r.more = true
1021 }
1022 return
1023 } else if path[i] == '|' {
1024 r.part = string(epart)
1025 r.pipe = path[i+1:]
1026 r.piped = true
1027 return
1028 } else if path[i] == '*' || path[i] == '?' {
1029 r.wild = true
1030 }
1031 epart = append(epart, path[i])
1032 }
1033 }
1034 // append the last part
1035 r.part = string(epart)
1036 return
1037 }
1038 }
1039 r.part = path
1040 return
1041}
1042
1043var vchars = [256]byte{
1044 '"': 2, '{': 3, '(': 3, '[': 3, '}': 1, ')': 1, ']': 1,
1045}
1046
1047func parseSquash(json string, i int) (int, string) {
1048 // expects that the lead character is a '[' or '{' or '('
1049 // squash the value, ignoring all nested arrays and objects.
1050 // the first '[' or '{' or '(' has already been read
1051 s := i
1052 i++
1053 depth := 1
1054 var c byte
1055 for i < len(json) {
1056 for i < len(json)-8 {
1057 jslice := json[i : i+8]
1058 c = vchars[jslice[0]]
1059 if c != 0 {
1060 i += 0
1061 goto token
1062 }
1063 c = vchars[jslice[1]]
1064 if c != 0 {
1065 i += 1
1066 goto token
1067 }
1068 c = vchars[jslice[2]]
1069 if c != 0 {
1070 i += 2
1071 goto token
1072 }
1073 c = vchars[jslice[3]]
1074 if c != 0 {
1075 i += 3
1076 goto token
1077 }
1078 c = vchars[jslice[4]]
1079 if c != 0 {
1080 i += 4
1081 goto token
1082 }
1083 c = vchars[jslice[5]]
1084 if c != 0 {
1085 i += 5
1086 goto token
1087 }
1088 c = vchars[jslice[6]]
1089 if c != 0 {
1090 i += 6
1091 goto token
1092 }
1093 c = vchars[jslice[7]]
1094 if c != 0 {
1095 i += 7
1096 goto token
1097 }
1098 i += 8
1099 }
1100 c = vchars[json[i]]
1101 if c == 0 {
1102 i++
1103 continue
1104 }
1105 token:
1106 if c == 2 {
1107 // '"' string
1108 i++
1109 s2 := i
1110 nextquote:
1111 for i < len(json)-8 {
1112 jslice := json[i : i+8]
1113 if jslice[0] == '"' {
1114 i += 0
1115 goto strchkesc
1116 }
1117 if jslice[1] == '"' {
1118 i += 1
1119 goto strchkesc
1120 }
1121 if jslice[2] == '"' {
1122 i += 2
1123 goto strchkesc
1124 }
1125 if jslice[3] == '"' {
1126 i += 3
1127 goto strchkesc
1128 }
1129 if jslice[4] == '"' {
1130 i += 4
1131 goto strchkesc
1132 }
1133 if jslice[5] == '"' {
1134 i += 5
1135 goto strchkesc
1136 }
1137 if jslice[6] == '"' {
1138 i += 6
1139 goto strchkesc
1140 }
1141 if jslice[7] == '"' {
1142 i += 7
1143 goto strchkesc
1144 }
1145 i += 8
1146 }
1147 goto strchkstd
1148 strchkesc:
1149 if json[i-1] != '\\' {
1150 i++
1151 continue
1152 }
1153 strchkstd:
1154 for i < len(json) {
1155 if json[i] > '\\' || json[i] != '"' {
1156 i++
1157 continue
1158 }
1159 // look for an escaped slash
1160 if json[i-1] == '\\' {
1161 n := 0
1162 for j := i - 2; j > s2-1; j-- {
1163 if json[j] != '\\' {
1164 break
1165 }
1166 n++
1167 }
1168 if n%2 == 0 {
1169 i++
1170 goto nextquote
1171 }
1172 }
1173 break
1174 }
1175 } else {
1176 // '{', '[', '(', '}', ']', ')'
1177 // open close tokens
1178 depth += int(c) - 2
1179 if depth == 0 {
1180 i++
1181 return i, json[s:i]
1182 }
1183 }
1184 i++
1185 }
1186 return i, json[s:]
1187}
1188
1189func parseObject(c *parseContext, i int, path string) (int, bool) {
1190 var pmatch, kesc, vesc, ok, hit bool
1191 var key, val string
1192 rp := parseObjectPath(path)
1193 if !rp.more && rp.piped {
1194 c.pipe = rp.pipe
1195 c.piped = true
1196 }
1197 for i < len(c.json) {
1198 for ; i < len(c.json); i++ {
1199 if c.json[i] == '"' {
1200 // parse_key_string
1201 // this is slightly different from getting s string value
1202 // because we don't need the outer quotes.
1203 i++
1204 var s = i
1205 for ; i < len(c.json); i++ {
1206 if c.json[i] > '\\' {
1207 continue
1208 }
1209 if c.json[i] == '"' {
1210 i, key, kesc, ok = i+1, c.json[s:i], false, true
1211 goto parse_key_string_done
1212 }
1213 if c.json[i] == '\\' {
1214 i++
1215 for ; i < len(c.json); i++ {
1216 if c.json[i] > '\\' {
1217 continue
1218 }
1219 if c.json[i] == '"' {
1220 // look for an escaped slash
1221 if c.json[i-1] == '\\' {
1222 n := 0
1223 for j := i - 2; j > 0; j-- {
1224 if c.json[j] != '\\' {
1225 break
1226 }
1227 n++
1228 }
1229 if n%2 == 0 {
1230 continue
1231 }
1232 }
1233 i, key, kesc, ok = i+1, c.json[s:i], true, true
1234 goto parse_key_string_done
1235 }
1236 }
1237 break
1238 }
1239 }
1240 key, kesc, ok = c.json[s:], false, false
1241 parse_key_string_done:
1242 break
1243 }
1244 if c.json[i] == '}' {
1245 return i + 1, false
1246 }
1247 }
1248 if !ok {
1249 return i, false
1250 }
1251 if rp.wild {
1252 if kesc {
1253 pmatch = matchLimit(unescape(key), rp.part)
1254 } else {
1255 pmatch = matchLimit(key, rp.part)
1256 }
1257 } else {
1258 if kesc {
1259 pmatch = rp.part == unescape(key)
1260 } else {
1261 pmatch = rp.part == key
1262 }
1263 }
1264 hit = pmatch && !rp.more
1265 for ; i < len(c.json); i++ {
1266 var num bool
1267 switch c.json[i] {
1268 default:
1269 continue
1270 case '"':
1271 i++
1272 i, val, vesc, ok = parseString(c.json, i)
1273 if !ok {
1274 return i, false
1275 }
1276 if hit {
1277 if vesc {
1278 c.value.Str = unescape(val[1 : len(val)-1])
1279 } else {
1280 c.value.Str = val[1 : len(val)-1]
1281 }
1282 c.value.Raw = val
1283 c.value.Type = String
1284 return i, true
1285 }
1286 case '{':
1287 if pmatch && !hit {
1288 i, hit = parseObject(c, i+1, rp.path)
1289 if hit {
1290 return i, true
1291 }
1292 } else {
1293 i, val = parseSquash(c.json, i)
1294 if hit {
1295 c.value.Raw = val
1296 c.value.Type = JSON
1297 return i, true
1298 }
1299 }
1300 case '[':
1301 if pmatch && !hit {
1302 i, hit = parseArray(c, i+1, rp.path)
1303 if hit {
1304 return i, true
1305 }
1306 } else {
1307 i, val = parseSquash(c.json, i)
1308 if hit {
1309 c.value.Raw = val
1310 c.value.Type = JSON
1311 return i, true
1312 }
1313 }
1314 case 'n':
1315 if i+1 < len(c.json) && c.json[i+1] != 'u' {
1316 num = true
1317 break
1318 }
1319 fallthrough
1320 case 't', 'f':
1321 vc := c.json[i]
1322 i, val = parseLiteral(c.json, i)
1323 if hit {
1324 c.value.Raw = val
1325 switch vc {
1326 case 't':
1327 c.value.Type = True
1328 case 'f':
1329 c.value.Type = False
1330 }
1331 return i, true
1332 }
1333 case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1334 'i', 'I', 'N':
1335 num = true
1336 }
1337 if num {
1338 i, val = parseNumber(c.json, i)
1339 if hit {
1340 c.value.Raw = val
1341 c.value.Type = Number
1342 c.value.Num, _ = strconv.ParseFloat(val, 64)
1343 return i, true
1344 }
1345 }
1346 break
1347 }
1348 }
1349 return i, false
1350}
1351
1352// matchLimit will limit the complexity of the match operation to avoid ReDos
1353// attacks from arbitrary inputs.
1354// See the github.com/tidwall/match.MatchLimit function for more information.
1355func matchLimit(str, pattern string) bool {
1356 matched, _ := match.MatchLimit(str, pattern, 10000)
1357 return matched
1358}
1359
1360func falseish(t Result) bool {
1361 switch t.Type {
1362 case Null:
1363 return true
1364 case False:
1365 return true
1366 case String:
1367 b, err := strconv.ParseBool(strings.ToLower(t.Str))
1368 if err != nil {
1369 return false
1370 }
1371 return !b
1372 case Number:
1373 return t.Num == 0
1374 default:
1375 return false
1376 }
1377}
1378
1379func trueish(t Result) bool {
1380 switch t.Type {
1381 case True:
1382 return true
1383 case String:
1384 b, err := strconv.ParseBool(strings.ToLower(t.Str))
1385 if err != nil {
1386 return false
1387 }
1388 return b
1389 case Number:
1390 return t.Num != 0
1391 default:
1392 return false
1393 }
1394}
1395
1396func nullish(t Result) bool {
1397 return t.Type == Null
1398}
1399
1400func queryMatches(rp *arrayPathResult, value Result) bool {
1401 rpv := rp.query.value
1402 if len(rpv) > 0 {
1403 if rpv[0] == '~' {
1404 // convert to bool
1405 rpv = rpv[1:]
1406 var ish, ok bool
1407 switch rpv {
1408 case "*":
1409 ish, ok = value.Exists(), true
1410 case "null":
1411 ish, ok = nullish(value), true
1412 case "true":
1413 ish, ok = trueish(value), true
1414 case "false":
1415 ish, ok = falseish(value), true
1416 }
1417 if ok {
1418 rpv = "true"
1419 if ish {
1420 value = Result{Type: True}
1421 } else {
1422 value = Result{Type: False}
1423 }
1424 } else {
1425 rpv = ""
1426 value = Result{}
1427 }
1428 }
1429 }
1430 if !value.Exists() {
1431 return false
1432 }
1433 if rp.query.op == "" {
1434 // the query is only looking for existence, such as:
1435 // friends.#(name)
1436 // which makes sure that the array "friends" has an element of
1437 // "name" that exists
1438 return true
1439 }
1440 switch value.Type {
1441 case String:
1442 switch rp.query.op {
1443 case "=":
1444 return value.Str == rpv
1445 case "!=":
1446 return value.Str != rpv
1447 case "<":
1448 return value.Str < rpv
1449 case "<=":
1450 return value.Str <= rpv
1451 case ">":
1452 return value.Str > rpv
1453 case ">=":
1454 return value.Str >= rpv
1455 case "%":
1456 return matchLimit(value.Str, rpv)
1457 case "!%":
1458 return !matchLimit(value.Str, rpv)
1459 }
1460 case Number:
1461 rpvn, _ := strconv.ParseFloat(rpv, 64)
1462 switch rp.query.op {
1463 case "=":
1464 return value.Num == rpvn
1465 case "!=":
1466 return value.Num != rpvn
1467 case "<":
1468 return value.Num < rpvn
1469 case "<=":
1470 return value.Num <= rpvn
1471 case ">":
1472 return value.Num > rpvn
1473 case ">=":
1474 return value.Num >= rpvn
1475 }
1476 case True:
1477 switch rp.query.op {
1478 case "=":
1479 return rpv == "true"
1480 case "!=":
1481 return rpv != "true"
1482 case ">":
1483 return rpv == "false"
1484 case ">=":
1485 return true
1486 }
1487 case False:
1488 switch rp.query.op {
1489 case "=":
1490 return rpv == "false"
1491 case "!=":
1492 return rpv != "false"
1493 case "<":
1494 return rpv == "true"
1495 case "<=":
1496 return true
1497 }
1498 }
1499 return false
1500}
1501func parseArray(c *parseContext, i int, path string) (int, bool) {
1502 var pmatch, vesc, ok, hit bool
1503 var val string
1504 var h int
1505 var alog []int
1506 var partidx int
1507 var multires []byte
1508 var queryIndexes []int
1509 rp := parseArrayPath(path)
1510 if !rp.arrch {
1511 n, ok := parseUint(rp.part)
1512 if !ok {
1513 partidx = -1
1514 } else {
1515 partidx = int(n)
1516 }
1517 }
1518 if !rp.more && rp.piped {
1519 c.pipe = rp.pipe
1520 c.piped = true
1521 }
1522
1523 procQuery := func(qval Result) bool {
1524 if rp.query.all {
1525 if len(multires) == 0 {
1526 multires = append(multires, '[')
1527 }
1528 }
1529 var tmp parseContext
1530 tmp.value = qval
1531 fillIndex(c.json, &tmp)
1532 parentIndex := tmp.value.Index
1533 var res Result
1534 if qval.Type == JSON {
1535 res = qval.Get(rp.query.path)
1536 } else {
1537 if rp.query.path != "" {
1538 return false
1539 }
1540 res = qval
1541 }
1542 if queryMatches(&rp, res) {
1543 if rp.more {
1544 left, right, ok := splitPossiblePipe(rp.path)
1545 if ok {
1546 rp.path = left
1547 c.pipe = right
1548 c.piped = true
1549 }
1550 res = qval.Get(rp.path)
1551 } else {
1552 res = qval
1553 }
1554 if rp.query.all {
1555 raw := res.Raw
1556 if len(raw) == 0 {
1557 raw = res.String()
1558 }
1559 if raw != "" {
1560 if len(multires) > 1 {
1561 multires = append(multires, ',')
1562 }
1563 multires = append(multires, raw...)
1564 queryIndexes = append(queryIndexes, res.Index+parentIndex)
1565 }
1566 } else {
1567 c.value = res
1568 return true
1569 }
1570 }
1571 return false
1572 }
1573 for i < len(c.json)+1 {
1574 if !rp.arrch {
1575 pmatch = partidx == h
1576 hit = pmatch && !rp.more
1577 }
1578 h++
1579 if rp.alogok {
1580 alog = append(alog, i)
1581 }
1582 for ; ; i++ {
1583 var ch byte
1584 if i > len(c.json) {
1585 break
1586 } else if i == len(c.json) {
1587 ch = ']'
1588 } else {
1589 ch = c.json[i]
1590 }
1591 var num bool
1592 switch ch {
1593 default:
1594 continue
1595 case '"':
1596 i++
1597 i, val, vesc, ok = parseString(c.json, i)
1598 if !ok {
1599 return i, false
1600 }
1601 if rp.query.on {
1602 var qval Result
1603 if vesc {
1604 qval.Str = unescape(val[1 : len(val)-1])
1605 } else {
1606 qval.Str = val[1 : len(val)-1]
1607 }
1608 qval.Raw = val
1609 qval.Type = String
1610 if procQuery(qval) {
1611 return i, true
1612 }
1613 } else if hit {
1614 if rp.alogok {
1615 break
1616 }
1617 if vesc {
1618 c.value.Str = unescape(val[1 : len(val)-1])
1619 } else {
1620 c.value.Str = val[1 : len(val)-1]
1621 }
1622 c.value.Raw = val
1623 c.value.Type = String
1624 return i, true
1625 }
1626 case '{':
1627 if pmatch && !hit {
1628 i, hit = parseObject(c, i+1, rp.path)
1629 if hit {
1630 if rp.alogok {
1631 break
1632 }
1633 return i, true
1634 }
1635 } else {
1636 i, val = parseSquash(c.json, i)
1637 if rp.query.on {
1638 if procQuery(Result{Raw: val, Type: JSON}) {
1639 return i, true
1640 }
1641 } else if hit {
1642 if rp.alogok {
1643 break
1644 }
1645 c.value.Raw = val
1646 c.value.Type = JSON
1647 return i, true
1648 }
1649 }
1650 case '[':
1651 if pmatch && !hit {
1652 i, hit = parseArray(c, i+1, rp.path)
1653 if hit {
1654 if rp.alogok {
1655 break
1656 }
1657 return i, true
1658 }
1659 } else {
1660 i, val = parseSquash(c.json, i)
1661 if rp.query.on {
1662 if procQuery(Result{Raw: val, Type: JSON}) {
1663 return i, true
1664 }
1665 } else if hit {
1666 if rp.alogok {
1667 break
1668 }
1669 c.value.Raw = val
1670 c.value.Type = JSON
1671 return i, true
1672 }
1673 }
1674 case 'n':
1675 if i+1 < len(c.json) && c.json[i+1] != 'u' {
1676 num = true
1677 break
1678 }
1679 fallthrough
1680 case 't', 'f':
1681 vc := c.json[i]
1682 i, val = parseLiteral(c.json, i)
1683 if rp.query.on {
1684 var qval Result
1685 qval.Raw = val
1686 switch vc {
1687 case 't':
1688 qval.Type = True
1689 case 'f':
1690 qval.Type = False
1691 }
1692 if procQuery(qval) {
1693 return i, true
1694 }
1695 } else if hit {
1696 if rp.alogok {
1697 break
1698 }
1699 c.value.Raw = val
1700 switch vc {
1701 case 't':
1702 c.value.Type = True
1703 case 'f':
1704 c.value.Type = False
1705 }
1706 return i, true
1707 }
1708 case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1709 'i', 'I', 'N':
1710 num = true
1711 case ']':
1712 if rp.arrch && rp.part == "#" {
1713 if rp.alogok {
1714 left, right, ok := splitPossiblePipe(rp.alogkey)
1715 if ok {
1716 rp.alogkey = left
1717 c.pipe = right
1718 c.piped = true
1719 }
1720 var indexes = make([]int, 0, 64)
1721 var jsons = make([]byte, 0, 64)
1722 jsons = append(jsons, '[')
1723 for j, k := 0, 0; j < len(alog); j++ {
1724 idx := alog[j]
1725 for idx < len(c.json) {
1726 switch c.json[idx] {
1727 case ' ', '\t', '\r', '\n':
1728 idx++
1729 continue
1730 }
1731 break
1732 }
1733 if idx < len(c.json) && c.json[idx] != ']' {
1734 _, res, ok := parseAny(c.json, idx, true)
1735 if ok {
1736 res := res.Get(rp.alogkey)
1737 if res.Exists() {
1738 if k > 0 {
1739 jsons = append(jsons, ',')
1740 }
1741 raw := res.Raw
1742 if len(raw) == 0 {
1743 raw = res.String()
1744 }
1745 jsons = append(jsons, []byte(raw)...)
1746 indexes = append(indexes, res.Index)
1747 k++
1748 }
1749 }
1750 }
1751 }
1752 jsons = append(jsons, ']')
1753 c.value.Type = JSON
1754 c.value.Raw = string(jsons)
1755 c.value.Indexes = indexes
1756 return i + 1, true
1757 }
1758 if rp.alogok {
1759 break
1760 }
1761
1762 c.value.Type = Number
1763 c.value.Num = float64(h - 1)
1764 c.value.Raw = strconv.Itoa(h - 1)
1765 c.calcd = true
1766 return i + 1, true
1767 }
1768 if !c.value.Exists() {
1769 if len(multires) > 0 {
1770 c.value = Result{
1771 Raw: string(append(multires, ']')),
1772 Type: JSON,
1773 Indexes: queryIndexes,
1774 }
1775 } else if rp.query.all {
1776 c.value = Result{
1777 Raw: "[]",
1778 Type: JSON,
1779 }
1780 }
1781 }
1782 return i + 1, false
1783 }
1784 if num {
1785 i, val = parseNumber(c.json, i)
1786 if rp.query.on {
1787 var qval Result
1788 qval.Raw = val
1789 qval.Type = Number
1790 qval.Num, _ = strconv.ParseFloat(val, 64)
1791 if procQuery(qval) {
1792 return i, true
1793 }
1794 } else if hit {
1795 if rp.alogok {
1796 break
1797 }
1798 c.value.Raw = val
1799 c.value.Type = Number
1800 c.value.Num, _ = strconv.ParseFloat(val, 64)
1801 return i, true
1802 }
1803 }
1804 break
1805 }
1806 }
1807 return i, false
1808}
1809
1810func splitPossiblePipe(path string) (left, right string, ok bool) {
1811 // take a quick peek for the pipe character. If found we'll split the piped
1812 // part of the path into the c.pipe field and shorten the rp.
1813 var possible bool
1814 for i := 0; i < len(path); i++ {
1815 if path[i] == '|' {
1816 possible = true
1817 break
1818 }
1819 }
1820 if !possible {
1821 return
1822 }
1823
1824 if len(path) > 0 && path[0] == '{' {
1825 squashed := squash(path[1:])
1826 if len(squashed) < len(path)-1 {
1827 squashed = path[:len(squashed)+1]
1828 remain := path[len(squashed):]
1829 if remain[0] == '|' {
1830 return squashed, remain[1:], true
1831 }
1832 }
1833 return
1834 }
1835
1836 // split the left and right side of the path with the pipe character as
1837 // the delimiter. This is a little tricky because we'll need to basically
1838 // parse the entire path.
1839 for i := 0; i < len(path); i++ {
1840 if path[i] == '\\' {
1841 i++
1842 } else if path[i] == '.' {
1843 if i == len(path)-1 {
1844 return
1845 }
1846 if path[i+1] == '#' {
1847 i += 2
1848 if i == len(path) {
1849 return
1850 }
1851 if path[i] == '[' || path[i] == '(' {
1852 var start, end byte
1853 if path[i] == '[' {
1854 start, end = '[', ']'
1855 } else {
1856 start, end = '(', ')'
1857 }
1858 // inside selector, balance brackets
1859 i++
1860 depth := 1
1861 for ; i < len(path); i++ {
1862 if path[i] == '\\' {
1863 i++
1864 } else if path[i] == start {
1865 depth++
1866 } else if path[i] == end {
1867 depth--
1868 if depth == 0 {
1869 break
1870 }
1871 } else if path[i] == '"' {
1872 // inside selector string, balance quotes
1873 i++
1874 for ; i < len(path); i++ {
1875 if path[i] == '\\' {
1876 i++
1877 } else if path[i] == '"' {
1878 break
1879 }
1880 }
1881 }
1882 }
1883 }
1884 }
1885 } else if path[i] == '|' {
1886 return path[:i], path[i+1:], true
1887 }
1888 }
1889 return
1890}
1891
1892// ForEachLine iterates through lines of JSON as specified by the JSON Lines
1893// format (http://jsonlines.org/).
1894// Each line is returned as a GJSON Result.
1895func ForEachLine(json string, iterator func(line Result) bool) {
1896 var res Result
1897 var i int
1898 for {
1899 i, res, _ = parseAny(json, i, true)
1900 if !res.Exists() {
1901 break
1902 }
1903 if !iterator(res) {
1904 return
1905 }
1906 }
1907}
1908
1909type subSelector struct {
1910 name string
1911 path string
1912}
1913
1914// parseSubSelectors returns the subselectors belonging to a '[path1,path2]' or
1915// '{"field1":path1,"field2":path2}' type subSelection. It's expected that the
1916// first character in path is either '[' or '{', and has already been checked
1917// prior to calling this function.
1918func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) {
1919 modifier := 0
1920 depth := 1
1921 colon := 0
1922 start := 1
1923 i := 1
1924 pushSel := func() {
1925 var sel subSelector
1926 if colon == 0 {
1927 sel.path = path[start:i]
1928 } else {
1929 sel.name = path[start:colon]
1930 sel.path = path[colon+1 : i]
1931 }
1932 sels = append(sels, sel)
1933 colon = 0
1934 modifier = 0
1935 start = i + 1
1936 }
1937 for ; i < len(path); i++ {
1938 switch path[i] {
1939 case '\\':
1940 i++
1941 case '@':
1942 if modifier == 0 && i > 0 && (path[i-1] == '.' || path[i-1] == '|') {
1943 modifier = i
1944 }
1945 case ':':
1946 if modifier == 0 && colon == 0 && depth == 1 {
1947 colon = i
1948 }
1949 case ',':
1950 if depth == 1 {
1951 pushSel()
1952 }
1953 case '"':
1954 i++
1955 loop:
1956 for ; i < len(path); i++ {
1957 switch path[i] {
1958 case '\\':
1959 i++
1960 case '"':
1961 break loop
1962 }
1963 }
1964 case '[', '(', '{':
1965 depth++
1966 case ']', ')', '}':
1967 depth--
1968 if depth == 0 {
1969 pushSel()
1970 path = path[i+1:]
1971 return sels, path, true
1972 }
1973 }
1974 }
1975 return
1976}
1977
1978// nameOfLast returns the name of the last component
1979func nameOfLast(path string) string {
1980 for i := len(path) - 1; i >= 0; i-- {
1981 if path[i] == '|' || path[i] == '.' {
1982 if i > 0 {
1983 if path[i-1] == '\\' {
1984 continue
1985 }
1986 }
1987 return path[i+1:]
1988 }
1989 }
1990 return path
1991}
1992
1993func isSimpleName(component string) bool {
1994 for i := 0; i < len(component); i++ {
1995 if component[i] < ' ' {
1996 return false
1997 }
1998 switch component[i] {
1999 case '[', ']', '{', '}', '(', ')', '#', '|', '!':
2000 return false
2001 }
2002 }
2003 return true
2004}
2005
2006var hexchars = [...]byte{
2007 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
2008 'a', 'b', 'c', 'd', 'e', 'f',
2009}
2010
2011func appendHex16(dst []byte, x uint16) []byte {
2012 return append(dst,
2013 hexchars[x>>12&0xF], hexchars[x>>8&0xF],
2014 hexchars[x>>4&0xF], hexchars[x>>0&0xF],
2015 )
2016}
2017
2018// DisableEscapeHTML will disable the automatic escaping of certain
2019// "problamatic" HTML characters when encoding to JSON.
2020// These character include '>', '<' and '&', which get escaped to \u003e,
2021// \u0026, and \u003c respectively.
2022//
2023// This is a global flag and will affect all further gjson operations.
2024// Ideally, if used, it should be set one time before other gjson functions
2025// are called.
2026var DisableEscapeHTML = false
2027
2028// AppendJSONString is a convenience function that converts the provided string
2029// to a valid JSON string and appends it to dst.
2030func AppendJSONString(dst []byte, s string) []byte {
2031 dst = append(dst, make([]byte, len(s)+2)...)
2032 dst = append(dst[:len(dst)-len(s)-2], '"')
2033 for i := 0; i < len(s); i++ {
2034 if s[i] < ' ' {
2035 dst = append(dst, '\\')
2036 switch s[i] {
2037 case '\b':
2038 dst = append(dst, 'b')
2039 case '\f':
2040 dst = append(dst, 'f')
2041 case '\n':
2042 dst = append(dst, 'n')
2043 case '\r':
2044 dst = append(dst, 'r')
2045 case '\t':
2046 dst = append(dst, 't')
2047 default:
2048 dst = append(dst, 'u')
2049 dst = appendHex16(dst, uint16(s[i]))
2050 }
2051 } else if !DisableEscapeHTML &&
2052 (s[i] == '>' || s[i] == '<' || s[i] == '&') {
2053 dst = append(dst, '\\', 'u')
2054 dst = appendHex16(dst, uint16(s[i]))
2055 } else if s[i] == '\\' {
2056 dst = append(dst, '\\', '\\')
2057 } else if s[i] == '"' {
2058 dst = append(dst, '\\', '"')
2059 } else if s[i] > 127 {
2060 // read utf8 character
2061 r, n := utf8.DecodeRuneInString(s[i:])
2062 if n == 0 {
2063 break
2064 }
2065 if r == utf8.RuneError && n == 1 {
2066 dst = append(dst, `\ufffd`...)
2067 } else if r == '\u2028' || r == '\u2029' {
2068 dst = append(dst, `\u202`...)
2069 dst = append(dst, hexchars[r&0xF])
2070 } else {
2071 dst = append(dst, s[i:i+n]...)
2072 }
2073 i = i + n - 1
2074 } else {
2075 dst = append(dst, s[i])
2076 }
2077 }
2078 return append(dst, '"')
2079}
2080
2081type parseContext struct {
2082 json string
2083 value Result
2084 pipe string
2085 piped bool
2086 calcd bool
2087 lines bool
2088}
2089
2090// Get searches json for the specified path.
2091// A path is in dot syntax, such as "name.last" or "age".
2092// When the value is found it's returned immediately.
2093//
2094// A path is a series of keys separated by a dot.
2095// A key may contain special wildcard characters '*' and '?'.
2096// To access an array value use the index as the key.
2097// To get the number of elements in an array or to access a child path, use
2098// the '#' character.
2099// The dot and wildcard character can be escaped with '\'.
2100//
2101// {
2102// "name": {"first": "Tom", "last": "Anderson"},
2103// "age":37,
2104// "children": ["Sara","Alex","Jack"],
2105// "friends": [
2106// {"first": "James", "last": "Murphy"},
2107// {"first": "Roger", "last": "Craig"}
2108// ]
2109// }
2110// "name.last" >> "Anderson"
2111// "age" >> 37
2112// "children" >> ["Sara","Alex","Jack"]
2113// "children.#" >> 3
2114// "children.1" >> "Alex"
2115// "child*.2" >> "Jack"
2116// "c?ildren.0" >> "Sara"
2117// "friends.#.first" >> ["James","Roger"]
2118//
2119// This function expects that the json is well-formed, and does not validate.
2120// Invalid json will not panic, but it may return back unexpected results.
2121// If you are consuming JSON from an unpredictable source then you may want to
2122// use the Valid function first.
2123func Get(json, path string) Result {
2124 if len(path) > 1 {
2125 if (path[0] == '@' && !DisableModifiers) || path[0] == '!' {
2126 // possible modifier
2127 var ok bool
2128 var npath string
2129 var rjson string
2130 if path[0] == '@' && !DisableModifiers {
2131 npath, rjson, ok = execModifier(json, path)
2132 } else if path[0] == '!' {
2133 npath, rjson, ok = execStatic(json, path)
2134 }
2135 if ok {
2136 path = npath
2137 if len(path) > 0 && (path[0] == '|' || path[0] == '.') {
2138 res := Get(rjson, path[1:])
2139 res.Index = 0
2140 res.Indexes = nil
2141 return res
2142 }
2143 return Parse(rjson)
2144 }
2145 }
2146 if path[0] == '[' || path[0] == '{' {
2147 // using a subselector path
2148 kind := path[0]
2149 var ok bool
2150 var subs []subSelector
2151 subs, path, ok = parseSubSelectors(path)
2152 if ok {
2153 if len(path) == 0 || (path[0] == '|' || path[0] == '.') {
2154 var b []byte
2155 b = append(b, kind)
2156 var i int
2157 for _, sub := range subs {
2158 res := Get(json, sub.path)
2159 if res.Exists() {
2160 if i > 0 {
2161 b = append(b, ',')
2162 }
2163 if kind == '{' {
2164 if len(sub.name) > 0 {
2165 if sub.name[0] == '"' && Valid(sub.name) {
2166 b = append(b, sub.name...)
2167 } else {
2168 b = AppendJSONString(b, sub.name)
2169 }
2170 } else {
2171 last := nameOfLast(sub.path)
2172 if isSimpleName(last) {
2173 b = AppendJSONString(b, last)
2174 } else {
2175 b = AppendJSONString(b, "_")
2176 }
2177 }
2178 b = append(b, ':')
2179 }
2180 var raw string
2181 if len(res.Raw) == 0 {
2182 raw = res.String()
2183 if len(raw) == 0 {
2184 raw = "null"
2185 }
2186 } else {
2187 raw = res.Raw
2188 }
2189 b = append(b, raw...)
2190 i++
2191 }
2192 }
2193 b = append(b, kind+2)
2194 var res Result
2195 res.Raw = string(b)
2196 res.Type = JSON
2197 if len(path) > 0 {
2198 res = res.Get(path[1:])
2199 }
2200 res.Index = 0
2201 return res
2202 }
2203 }
2204 }
2205 }
2206 var i int
2207 var c = &parseContext{json: json}
2208 if len(path) >= 2 && path[0] == '.' && path[1] == '.' {
2209 c.lines = true
2210 parseArray(c, 0, path[2:])
2211 } else {
2212 for ; i < len(c.json); i++ {
2213 if c.json[i] == '{' {
2214 i++
2215 parseObject(c, i, path)
2216 break
2217 }
2218 if c.json[i] == '[' {
2219 i++
2220 parseArray(c, i, path)
2221 break
2222 }
2223 }
2224 }
2225 if c.piped {
2226 res := c.value.Get(c.pipe)
2227 res.Index = 0
2228 return res
2229 }
2230 fillIndex(json, c)
2231 return c.value
2232}
2233
2234// GetBytes searches json for the specified path.
2235// If working with bytes, this method preferred over Get(string(data), path)
2236func GetBytes(json []byte, path string) Result {
2237 return getBytes(json, path)
2238}
2239
2240// runeit returns the rune from the the \uXXXX
2241func runeit(json string) rune {
2242 n, _ := strconv.ParseUint(json[:4], 16, 64)
2243 return rune(n)
2244}
2245
2246// unescape unescapes a string
2247func unescape(json string) string {
2248 var str = make([]byte, 0, len(json))
2249 for i := 0; i < len(json); i++ {
2250 switch {
2251 default:
2252 str = append(str, json[i])
2253 case json[i] < ' ':
2254 return string(str)
2255 case json[i] == '\\':
2256 i++
2257 if i >= len(json) {
2258 return string(str)
2259 }
2260 switch json[i] {
2261 default:
2262 return string(str)
2263 case '\\':
2264 str = append(str, '\\')
2265 case '/':
2266 str = append(str, '/')
2267 case 'b':
2268 str = append(str, '\b')
2269 case 'f':
2270 str = append(str, '\f')
2271 case 'n':
2272 str = append(str, '\n')
2273 case 'r':
2274 str = append(str, '\r')
2275 case 't':
2276 str = append(str, '\t')
2277 case '"':
2278 str = append(str, '"')
2279 case 'u':
2280 if i+5 > len(json) {
2281 return string(str)
2282 }
2283 r := runeit(json[i+1:])
2284 i += 5
2285 if utf16.IsSurrogate(r) {
2286 // need another code
2287 if len(json[i:]) >= 6 && json[i] == '\\' &&
2288 json[i+1] == 'u' {
2289 // we expect it to be correct so just consume it
2290 r = utf16.DecodeRune(r, runeit(json[i+2:]))
2291 i += 6
2292 }
2293 }
2294 // provide enough space to encode the largest utf8 possible
2295 str = append(str, 0, 0, 0, 0, 0, 0, 0, 0)
2296 n := utf8.EncodeRune(str[len(str)-8:], r)
2297 str = str[:len(str)-8+n]
2298 i-- // backtrack index by one
2299 }
2300 }
2301 }
2302 return string(str)
2303}
2304
2305// Less return true if a token is less than another token.
2306// The caseSensitive parameter is used when the tokens are Strings.
2307// The order when comparing two different type is:
2308//
2309// Null < False < Number < String < True < JSON
2310func (t Result) Less(token Result, caseSensitive bool) bool {
2311 if t.Type < token.Type {
2312 return true
2313 }
2314 if t.Type > token.Type {
2315 return false
2316 }
2317 if t.Type == String {
2318 if caseSensitive {
2319 return t.Str < token.Str
2320 }
2321 return stringLessInsensitive(t.Str, token.Str)
2322 }
2323 if t.Type == Number {
2324 return t.Num < token.Num
2325 }
2326 return t.Raw < token.Raw
2327}
2328
2329func stringLessInsensitive(a, b string) bool {
2330 for i := 0; i < len(a) && i < len(b); i++ {
2331 if a[i] >= 'A' && a[i] <= 'Z' {
2332 if b[i] >= 'A' && b[i] <= 'Z' {
2333 // both are uppercase, do nothing
2334 if a[i] < b[i] {
2335 return true
2336 } else if a[i] > b[i] {
2337 return false
2338 }
2339 } else {
2340 // a is uppercase, convert a to lowercase
2341 if a[i]+32 < b[i] {
2342 return true
2343 } else if a[i]+32 > b[i] {
2344 return false
2345 }
2346 }
2347 } else if b[i] >= 'A' && b[i] <= 'Z' {
2348 // b is uppercase, convert b to lowercase
2349 if a[i] < b[i]+32 {
2350 return true
2351 } else if a[i] > b[i]+32 {
2352 return false
2353 }
2354 } else {
2355 // neither are uppercase
2356 if a[i] < b[i] {
2357 return true
2358 } else if a[i] > b[i] {
2359 return false
2360 }
2361 }
2362 }
2363 return len(a) < len(b)
2364}
2365
2366// parseAny parses the next value from a json string.
2367// A Result is returned when the hit param is set.
2368// The return values are (i int, res Result, ok bool)
2369func parseAny(json string, i int, hit bool) (int, Result, bool) {
2370 var res Result
2371 var val string
2372 for ; i < len(json); i++ {
2373 if json[i] == '{' || json[i] == '[' {
2374 i, val = parseSquash(json, i)
2375 if hit {
2376 res.Raw = val
2377 res.Type = JSON
2378 }
2379 var tmp parseContext
2380 tmp.value = res
2381 fillIndex(json, &tmp)
2382 return i, tmp.value, true
2383 }
2384 if json[i] <= ' ' {
2385 continue
2386 }
2387 var num bool
2388 switch json[i] {
2389 case '"':
2390 i++
2391 var vesc bool
2392 var ok bool
2393 i, val, vesc, ok = parseString(json, i)
2394 if !ok {
2395 return i, res, false
2396 }
2397 if hit {
2398 res.Type = String
2399 res.Raw = val
2400 if vesc {
2401 res.Str = unescape(val[1 : len(val)-1])
2402 } else {
2403 res.Str = val[1 : len(val)-1]
2404 }
2405 }
2406 return i, res, true
2407 case 'n':
2408 if i+1 < len(json) && json[i+1] != 'u' {
2409 num = true
2410 break
2411 }
2412 fallthrough
2413 case 't', 'f':
2414 vc := json[i]
2415 i, val = parseLiteral(json, i)
2416 if hit {
2417 res.Raw = val
2418 switch vc {
2419 case 't':
2420 res.Type = True
2421 case 'f':
2422 res.Type = False
2423 }
2424 return i, res, true
2425 }
2426 case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
2427 'i', 'I', 'N':
2428 num = true
2429 }
2430 if num {
2431 i, val = parseNumber(json, i)
2432 if hit {
2433 res.Raw = val
2434 res.Type = Number
2435 res.Num, _ = strconv.ParseFloat(val, 64)
2436 }
2437 return i, res, true
2438 }
2439
2440 }
2441 return i, res, false
2442}
2443
2444// GetMany searches json for the multiple paths.
2445// The return value is a Result array where the number of items
2446// will be equal to the number of input paths.
2447func GetMany(json string, path ...string) []Result {
2448 res := make([]Result, len(path))
2449 for i, path := range path {
2450 res[i] = Get(json, path)
2451 }
2452 return res
2453}
2454
2455// GetManyBytes searches json for the multiple paths.
2456// The return value is a Result array where the number of items
2457// will be equal to the number of input paths.
2458func GetManyBytes(json []byte, path ...string) []Result {
2459 res := make([]Result, len(path))
2460 for i, path := range path {
2461 res[i] = GetBytes(json, path)
2462 }
2463 return res
2464}
2465
2466func validpayload(data []byte, i int) (outi int, ok bool) {
2467 for ; i < len(data); i++ {
2468 switch data[i] {
2469 default:
2470 i, ok = validany(data, i)
2471 if !ok {
2472 return i, false
2473 }
2474 for ; i < len(data); i++ {
2475 switch data[i] {
2476 default:
2477 return i, false
2478 case ' ', '\t', '\n', '\r':
2479 continue
2480 }
2481 }
2482 return i, true
2483 case ' ', '\t', '\n', '\r':
2484 continue
2485 }
2486 }
2487 return i, false
2488}
2489func validany(data []byte, i int) (outi int, ok bool) {
2490 for ; i < len(data); i++ {
2491 switch data[i] {
2492 default:
2493 return i, false
2494 case ' ', '\t', '\n', '\r':
2495 continue
2496 case '{':
2497 return validobject(data, i+1)
2498 case '[':
2499 return validarray(data, i+1)
2500 case '"':
2501 return validstring(data, i+1)
2502 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
2503 return validnumber(data, i+1)
2504 case 't':
2505 return validtrue(data, i+1)
2506 case 'f':
2507 return validfalse(data, i+1)
2508 case 'n':
2509 return validnull(data, i+1)
2510 }
2511 }
2512 return i, false
2513}
2514func validobject(data []byte, i int) (outi int, ok bool) {
2515 for ; i < len(data); i++ {
2516 switch data[i] {
2517 default:
2518 return i, false
2519 case ' ', '\t', '\n', '\r':
2520 continue
2521 case '}':
2522 return i + 1, true
2523 case '"':
2524 key:
2525 if i, ok = validstring(data, i+1); !ok {
2526 return i, false
2527 }
2528 if i, ok = validcolon(data, i); !ok {
2529 return i, false
2530 }
2531 if i, ok = validany(data, i); !ok {
2532 return i, false
2533 }
2534 if i, ok = validcomma(data, i, '}'); !ok {
2535 return i, false
2536 }
2537 if data[i] == '}' {
2538 return i + 1, true
2539 }
2540 i++
2541 for ; i < len(data); i++ {
2542 switch data[i] {
2543 default:
2544 return i, false
2545 case ' ', '\t', '\n', '\r':
2546 continue
2547 case '"':
2548 goto key
2549 }
2550 }
2551 return i, false
2552 }
2553 }
2554 return i, false
2555}
2556func validcolon(data []byte, i int) (outi int, ok bool) {
2557 for ; i < len(data); i++ {
2558 switch data[i] {
2559 default:
2560 return i, false
2561 case ' ', '\t', '\n', '\r':
2562 continue
2563 case ':':
2564 return i + 1, true
2565 }
2566 }
2567 return i, false
2568}
2569func validcomma(data []byte, i int, end byte) (outi int, ok bool) {
2570 for ; i < len(data); i++ {
2571 switch data[i] {
2572 default:
2573 return i, false
2574 case ' ', '\t', '\n', '\r':
2575 continue
2576 case ',':
2577 return i, true
2578 case end:
2579 return i, true
2580 }
2581 }
2582 return i, false
2583}
2584func validarray(data []byte, i int) (outi int, ok bool) {
2585 for ; i < len(data); i++ {
2586 switch data[i] {
2587 default:
2588 for ; i < len(data); i++ {
2589 if i, ok = validany(data, i); !ok {
2590 return i, false
2591 }
2592 if i, ok = validcomma(data, i, ']'); !ok {
2593 return i, false
2594 }
2595 if data[i] == ']' {
2596 return i + 1, true
2597 }
2598 }
2599 case ' ', '\t', '\n', '\r':
2600 continue
2601 case ']':
2602 return i + 1, true
2603 }
2604 }
2605 return i, false
2606}
2607func validstring(data []byte, i int) (outi int, ok bool) {
2608 for ; i < len(data); i++ {
2609 if data[i] < ' ' {
2610 return i, false
2611 } else if data[i] == '\\' {
2612 i++
2613 if i == len(data) {
2614 return i, false
2615 }
2616 switch data[i] {
2617 default:
2618 return i, false
2619 case '"', '\\', '/', 'b', 'f', 'n', 'r', 't':
2620 case 'u':
2621 for j := 0; j < 4; j++ {
2622 i++
2623 if i >= len(data) {
2624 return i, false
2625 }
2626 if !((data[i] >= '0' && data[i] <= '9') ||
2627 (data[i] >= 'a' && data[i] <= 'f') ||
2628 (data[i] >= 'A' && data[i] <= 'F')) {
2629 return i, false
2630 }
2631 }
2632 }
2633 } else if data[i] == '"' {
2634 return i + 1, true
2635 }
2636 }
2637 return i, false
2638}
2639func validnumber(data []byte, i int) (outi int, ok bool) {
2640 i--
2641 // sign
2642 if data[i] == '-' {
2643 i++
2644 if i == len(data) {
2645 return i, false
2646 }
2647 if data[i] < '0' || data[i] > '9' {
2648 return i, false
2649 }
2650 }
2651 // int
2652 if i == len(data) {
2653 return i, false
2654 }
2655 if data[i] == '0' {
2656 i++
2657 } else {
2658 for ; i < len(data); i++ {
2659 if data[i] >= '0' && data[i] <= '9' {
2660 continue
2661 }
2662 break
2663 }
2664 }
2665 // frac
2666 if i == len(data) {
2667 return i, true
2668 }
2669 if data[i] == '.' {
2670 i++
2671 if i == len(data) {
2672 return i, false
2673 }
2674 if data[i] < '0' || data[i] > '9' {
2675 return i, false
2676 }
2677 i++
2678 for ; i < len(data); i++ {
2679 if data[i] >= '0' && data[i] <= '9' {
2680 continue
2681 }
2682 break
2683 }
2684 }
2685 // exp
2686 if i == len(data) {
2687 return i, true
2688 }
2689 if data[i] == 'e' || data[i] == 'E' {
2690 i++
2691 if i == len(data) {
2692 return i, false
2693 }
2694 if data[i] == '+' || data[i] == '-' {
2695 i++
2696 }
2697 if i == len(data) {
2698 return i, false
2699 }
2700 if data[i] < '0' || data[i] > '9' {
2701 return i, false
2702 }
2703 i++
2704 for ; i < len(data); i++ {
2705 if data[i] >= '0' && data[i] <= '9' {
2706 continue
2707 }
2708 break
2709 }
2710 }
2711 return i, true
2712}
2713
2714func validtrue(data []byte, i int) (outi int, ok bool) {
2715 if i+3 <= len(data) && data[i] == 'r' && data[i+1] == 'u' &&
2716 data[i+2] == 'e' {
2717 return i + 3, true
2718 }
2719 return i, false
2720}
2721func validfalse(data []byte, i int) (outi int, ok bool) {
2722 if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' &&
2723 data[i+2] == 's' && data[i+3] == 'e' {
2724 return i + 4, true
2725 }
2726 return i, false
2727}
2728func validnull(data []byte, i int) (outi int, ok bool) {
2729 if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' &&
2730 data[i+2] == 'l' {
2731 return i + 3, true
2732 }
2733 return i, false
2734}
2735
2736// Valid returns true if the input is valid json.
2737//
2738// if !gjson.Valid(json) {
2739// return errors.New("invalid json")
2740// }
2741// value := gjson.Get(json, "name.last")
2742func Valid(json string) bool {
2743 _, ok := validpayload(stringBytes(json), 0)
2744 return ok
2745}
2746
2747// ValidBytes returns true if the input is valid json.
2748//
2749// if !gjson.Valid(json) {
2750// return errors.New("invalid json")
2751// }
2752// value := gjson.Get(json, "name.last")
2753//
2754// If working with bytes, this method preferred over ValidBytes(string(data))
2755func ValidBytes(json []byte) bool {
2756 _, ok := validpayload(json, 0)
2757 return ok
2758}
2759
2760func parseUint(s string) (n uint64, ok bool) {
2761 var i int
2762 if i == len(s) {
2763 return 0, false
2764 }
2765 for ; i < len(s); i++ {
2766 if s[i] >= '0' && s[i] <= '9' {
2767 n = n*10 + uint64(s[i]-'0')
2768 } else {
2769 return 0, false
2770 }
2771 }
2772 return n, true
2773}
2774
2775func parseInt(s string) (n int64, ok bool) {
2776 var i int
2777 var sign bool
2778 if len(s) > 0 && s[0] == '-' {
2779 sign = true
2780 i++
2781 }
2782 if i == len(s) {
2783 return 0, false
2784 }
2785 for ; i < len(s); i++ {
2786 if s[i] >= '0' && s[i] <= '9' {
2787 n = n*10 + int64(s[i]-'0')
2788 } else {
2789 return 0, false
2790 }
2791 }
2792 if sign {
2793 return n * -1, true
2794 }
2795 return n, true
2796}
2797
2798// safeInt validates a given JSON number
2799// ensures it lies within the minimum and maximum representable JSON numbers
2800func safeInt(f float64) (n int64, ok bool) {
2801 // https://tc39.es/ecma262/#sec-number.min_safe_integer
2802 // https://tc39.es/ecma262/#sec-number.max_safe_integer
2803 if f < -9007199254740991 || f > 9007199254740991 {
2804 return 0, false
2805 }
2806 return int64(f), true
2807}
2808
2809// execStatic parses the path to find a static value.
2810// The input expects that the path already starts with a '!'
2811func execStatic(json, path string) (pathOut, res string, ok bool) {
2812 name := path[1:]
2813 if len(name) > 0 {
2814 switch name[0] {
2815 case '{', '[', '"', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7',
2816 '8', '9':
2817 _, res = parseSquash(name, 0)
2818 pathOut = name[len(res):]
2819 return pathOut, res, true
2820 }
2821 }
2822 for i := 1; i < len(path); i++ {
2823 if path[i] == '|' {
2824 pathOut = path[i:]
2825 name = path[1:i]
2826 break
2827 }
2828 if path[i] == '.' {
2829 pathOut = path[i:]
2830 name = path[1:i]
2831 break
2832 }
2833 }
2834 switch strings.ToLower(name) {
2835 case "true", "false", "null", "nan", "inf":
2836 return pathOut, name, true
2837 }
2838 return pathOut, res, false
2839}
2840
2841// execModifier parses the path to find a matching modifier function.
2842// The input expects that the path already starts with a '@'
2843func execModifier(json, path string) (pathOut, res string, ok bool) {
2844 name := path[1:]
2845 var hasArgs bool
2846 for i := 1; i < len(path); i++ {
2847 if path[i] == ':' {
2848 pathOut = path[i+1:]
2849 name = path[1:i]
2850 hasArgs = len(pathOut) > 0
2851 break
2852 }
2853 if path[i] == '|' {
2854 pathOut = path[i:]
2855 name = path[1:i]
2856 break
2857 }
2858 if path[i] == '.' {
2859 pathOut = path[i:]
2860 name = path[1:i]
2861 break
2862 }
2863 }
2864 if fn, ok := modifiers[name]; ok {
2865 var args string
2866 if hasArgs {
2867 var parsedArgs bool
2868 switch pathOut[0] {
2869 case '{', '[', '"':
2870 // json arg
2871 res := Parse(pathOut)
2872 if res.Exists() {
2873 args = squash(pathOut)
2874 pathOut = pathOut[len(args):]
2875 parsedArgs = true
2876 }
2877 }
2878 if !parsedArgs {
2879 // simple arg
2880 i := 0
2881 for ; i < len(pathOut); i++ {
2882 if pathOut[i] == '|' {
2883 break
2884 }
2885 switch pathOut[i] {
2886 case '{', '[', '"', '(':
2887 s := squash(pathOut[i:])
2888 i += len(s) - 1
2889 }
2890 }
2891 args = pathOut[:i]
2892 pathOut = pathOut[i:]
2893 }
2894 }
2895 return pathOut, fn(json, args), true
2896 }
2897 return pathOut, res, false
2898}
2899
2900// unwrap removes the '[]' or '{}' characters around json
2901func unwrap(json string) string {
2902 json = trim(json)
2903 if len(json) >= 2 && (json[0] == '[' || json[0] == '{') {
2904 json = json[1 : len(json)-1]
2905 }
2906 return json
2907}
2908
2909// DisableModifiers will disable the modifier syntax
2910var DisableModifiers = false
2911
2912var modifiers map[string]func(json, arg string) string
2913
2914func init() {
2915 modifiers = map[string]func(json, arg string) string{
2916 "pretty": modPretty,
2917 "ugly": modUgly,
2918 "reverse": modReverse,
2919 "this": modThis,
2920 "flatten": modFlatten,
2921 "join": modJoin,
2922 "valid": modValid,
2923 "keys": modKeys,
2924 "values": modValues,
2925 "tostr": modToStr,
2926 "fromstr": modFromStr,
2927 "group": modGroup,
2928 "dig": modDig,
2929 }
2930}
2931
2932// AddModifier binds a custom modifier command to the GJSON syntax.
2933// This operation is not thread safe and should be executed prior to
2934// using all other gjson function.
2935func AddModifier(name string, fn func(json, arg string) string) {
2936 modifiers[name] = fn
2937}
2938
2939// ModifierExists returns true when the specified modifier exists.
2940func ModifierExists(name string, fn func(json, arg string) string) bool {
2941 _, ok := modifiers[name]
2942 return ok
2943}
2944
2945// cleanWS remove any non-whitespace from string
2946func cleanWS(s string) string {
2947 for i := 0; i < len(s); i++ {
2948 switch s[i] {
2949 case ' ', '\t', '\n', '\r':
2950 continue
2951 default:
2952 var s2 []byte
2953 for i := 0; i < len(s); i++ {
2954 switch s[i] {
2955 case ' ', '\t', '\n', '\r':
2956 s2 = append(s2, s[i])
2957 }
2958 }
2959 return string(s2)
2960 }
2961 }
2962 return s
2963}
2964
2965// @pretty modifier makes the json look nice.
2966func modPretty(json, arg string) string {
2967 if len(arg) > 0 {
2968 opts := *pretty.DefaultOptions
2969 Parse(arg).ForEach(func(key, value Result) bool {
2970 switch key.String() {
2971 case "sortKeys":
2972 opts.SortKeys = value.Bool()
2973 case "indent":
2974 opts.Indent = cleanWS(value.String())
2975 case "prefix":
2976 opts.Prefix = cleanWS(value.String())
2977 case "width":
2978 opts.Width = int(value.Int())
2979 }
2980 return true
2981 })
2982 return bytesString(pretty.PrettyOptions(stringBytes(json), &opts))
2983 }
2984 return bytesString(pretty.Pretty(stringBytes(json)))
2985}
2986
2987// @this returns the current element. Can be used to retrieve the root element.
2988func modThis(json, arg string) string {
2989 return json
2990}
2991
2992// @ugly modifier removes all whitespace.
2993func modUgly(json, arg string) string {
2994 return bytesString(pretty.Ugly(stringBytes(json)))
2995}
2996
2997// @reverse reverses array elements or root object members.
2998func modReverse(json, arg string) string {
2999 res := Parse(json)
3000 if res.IsArray() {
3001 var values []Result
3002 res.ForEach(func(_, value Result) bool {
3003 values = append(values, value)
3004 return true
3005 })
3006 out := make([]byte, 0, len(json))
3007 out = append(out, '[')
3008 for i, j := len(values)-1, 0; i >= 0; i, j = i-1, j+1 {
3009 if j > 0 {
3010 out = append(out, ',')
3011 }
3012 out = append(out, values[i].Raw...)
3013 }
3014 out = append(out, ']')
3015 return bytesString(out)
3016 }
3017 if res.IsObject() {
3018 var keyValues []Result
3019 res.ForEach(func(key, value Result) bool {
3020 keyValues = append(keyValues, key, value)
3021 return true
3022 })
3023 out := make([]byte, 0, len(json))
3024 out = append(out, '{')
3025 for i, j := len(keyValues)-2, 0; i >= 0; i, j = i-2, j+1 {
3026 if j > 0 {
3027 out = append(out, ',')
3028 }
3029 out = append(out, keyValues[i+0].Raw...)
3030 out = append(out, ':')
3031 out = append(out, keyValues[i+1].Raw...)
3032 }
3033 out = append(out, '}')
3034 return bytesString(out)
3035 }
3036 return json
3037}
3038
3039// @flatten an array with child arrays.
3040//
3041// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,[6,7]]
3042//
3043// The {"deep":true} arg can be provide for deep flattening.
3044//
3045// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,6,7]
3046//
3047// The original json is returned when the json is not an array.
3048func modFlatten(json, arg string) string {
3049 res := Parse(json)
3050 if !res.IsArray() {
3051 return json
3052 }
3053 var deep bool
3054 if arg != "" {
3055 Parse(arg).ForEach(func(key, value Result) bool {
3056 if key.String() == "deep" {
3057 deep = value.Bool()
3058 }
3059 return true
3060 })
3061 }
3062 var out []byte
3063 out = append(out, '[')
3064 var idx int
3065 res.ForEach(func(_, value Result) bool {
3066 var raw string
3067 if value.IsArray() {
3068 if deep {
3069 raw = unwrap(modFlatten(value.Raw, arg))
3070 } else {
3071 raw = unwrap(value.Raw)
3072 }
3073 } else {
3074 raw = value.Raw
3075 }
3076 raw = strings.TrimSpace(raw)
3077 if len(raw) > 0 {
3078 if idx > 0 {
3079 out = append(out, ',')
3080 }
3081 out = append(out, raw...)
3082 idx++
3083 }
3084 return true
3085 })
3086 out = append(out, ']')
3087 return bytesString(out)
3088}
3089
3090// @keys extracts the keys from an object.
3091//
3092// {"first":"Tom","last":"Smith"} -> ["first","last"]
3093func modKeys(json, arg string) string {
3094 v := Parse(json)
3095 if !v.Exists() {
3096 return "[]"
3097 }
3098 obj := v.IsObject()
3099 var out strings.Builder
3100 out.WriteByte('[')
3101 var i int
3102 v.ForEach(func(key, _ Result) bool {
3103 if i > 0 {
3104 out.WriteByte(',')
3105 }
3106 if obj {
3107 out.WriteString(key.Raw)
3108 } else {
3109 out.WriteString("null")
3110 }
3111 i++
3112 return true
3113 })
3114 out.WriteByte(']')
3115 return out.String()
3116}
3117
3118// @values extracts the values from an object.
3119//
3120// {"first":"Tom","last":"Smith"} -> ["Tom","Smith"]
3121func modValues(json, arg string) string {
3122 v := Parse(json)
3123 if !v.Exists() {
3124 return "[]"
3125 }
3126 if v.IsArray() {
3127 return json
3128 }
3129 var out strings.Builder
3130 out.WriteByte('[')
3131 var i int
3132 v.ForEach(func(_, value Result) bool {
3133 if i > 0 {
3134 out.WriteByte(',')
3135 }
3136 out.WriteString(value.Raw)
3137 i++
3138 return true
3139 })
3140 out.WriteByte(']')
3141 return out.String()
3142}
3143
3144// @join multiple objects into a single object.
3145//
3146// [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"}
3147//
3148// The arg can be "true" to specify that duplicate keys should be preserved.
3149//
3150// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":37,"age":41}
3151//
3152// Without preserved keys:
3153//
3154// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":41}
3155//
3156// The original json is returned when the json is not an object.
3157func modJoin(json, arg string) string {
3158 res := Parse(json)
3159 if !res.IsArray() {
3160 return json
3161 }
3162 var preserve bool
3163 if arg != "" {
3164 Parse(arg).ForEach(func(key, value Result) bool {
3165 if key.String() == "preserve" {
3166 preserve = value.Bool()
3167 }
3168 return true
3169 })
3170 }
3171 var out []byte
3172 out = append(out, '{')
3173 if preserve {
3174 // Preserve duplicate keys.
3175 var idx int
3176 res.ForEach(func(_, value Result) bool {
3177 if !value.IsObject() {
3178 return true
3179 }
3180 if idx > 0 {
3181 out = append(out, ',')
3182 }
3183 out = append(out, unwrap(value.Raw)...)
3184 idx++
3185 return true
3186 })
3187 } else {
3188 // Deduplicate keys and generate an object with stable ordering.
3189 var keys []Result
3190 kvals := make(map[string]Result)
3191 res.ForEach(func(_, value Result) bool {
3192 if !value.IsObject() {
3193 return true
3194 }
3195 value.ForEach(func(key, value Result) bool {
3196 k := key.String()
3197 if _, ok := kvals[k]; !ok {
3198 keys = append(keys, key)
3199 }
3200 kvals[k] = value
3201 return true
3202 })
3203 return true
3204 })
3205 for i := 0; i < len(keys); i++ {
3206 if i > 0 {
3207 out = append(out, ',')
3208 }
3209 out = append(out, keys[i].Raw...)
3210 out = append(out, ':')
3211 out = append(out, kvals[keys[i].String()].Raw...)
3212 }
3213 }
3214 out = append(out, '}')
3215 return bytesString(out)
3216}
3217
3218// @valid ensures that the json is valid before moving on. An empty string is
3219// returned when the json is not valid, otherwise it returns the original json.
3220func modValid(json, arg string) string {
3221 if !Valid(json) {
3222 return ""
3223 }
3224 return json
3225}
3226
3227// @fromstr converts a string to json
3228//
3229// "{\"id\":1023,\"name\":\"alert\"}" -> {"id":1023,"name":"alert"}
3230func modFromStr(json, arg string) string {
3231 if !Valid(json) {
3232 return ""
3233 }
3234 return Parse(json).String()
3235}
3236
3237// @tostr converts a string to json
3238//
3239// {"id":1023,"name":"alert"} -> "{\"id\":1023,\"name\":\"alert\"}"
3240func modToStr(str, arg string) string {
3241 return string(AppendJSONString(nil, str))
3242}
3243
3244func modGroup(json, arg string) string {
3245 res := Parse(json)
3246 if !res.IsObject() {
3247 return ""
3248 }
3249 var all [][]byte
3250 res.ForEach(func(key, value Result) bool {
3251 if !value.IsArray() {
3252 return true
3253 }
3254 var idx int
3255 value.ForEach(func(_, value Result) bool {
3256 if idx == len(all) {
3257 all = append(all, []byte{})
3258 }
3259 all[idx] = append(all[idx], ("," + key.Raw + ":" + value.Raw)...)
3260 idx++
3261 return true
3262 })
3263 return true
3264 })
3265 var data []byte
3266 data = append(data, '[')
3267 for i, item := range all {
3268 if i > 0 {
3269 data = append(data, ',')
3270 }
3271 data = append(data, '{')
3272 data = append(data, item[1:]...)
3273 data = append(data, '}')
3274 }
3275 data = append(data, ']')
3276 return string(data)
3277}
3278
3279// stringHeader instead of reflect.StringHeader
3280type stringHeader struct {
3281 data unsafe.Pointer
3282 len int
3283}
3284
3285// sliceHeader instead of reflect.SliceHeader
3286type sliceHeader struct {
3287 data unsafe.Pointer
3288 len int
3289 cap int
3290}
3291
3292// getBytes casts the input json bytes to a string and safely returns the
3293// results as uniquely allocated data. This operation is intended to minimize
3294// copies and allocations for the large json string->[]byte.
3295func getBytes(json []byte, path string) Result {
3296 var result Result
3297 if json != nil {
3298 // unsafe cast to string
3299 result = Get(*(*string)(unsafe.Pointer(&json)), path)
3300 // safely get the string headers
3301 rawhi := *(*stringHeader)(unsafe.Pointer(&result.Raw))
3302 strhi := *(*stringHeader)(unsafe.Pointer(&result.Str))
3303 // create byte slice headers
3304 rawh := sliceHeader{data: rawhi.data, len: rawhi.len, cap: rawhi.len}
3305 strh := sliceHeader{data: strhi.data, len: strhi.len, cap: rawhi.len}
3306 if strh.data == nil {
3307 // str is nil
3308 if rawh.data == nil {
3309 // raw is nil
3310 result.Raw = ""
3311 } else {
3312 // raw has data, safely copy the slice header to a string
3313 result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
3314 }
3315 result.Str = ""
3316 } else if rawh.data == nil {
3317 // raw is nil
3318 result.Raw = ""
3319 // str has data, safely copy the slice header to a string
3320 result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
3321 } else if uintptr(strh.data) >= uintptr(rawh.data) &&
3322 uintptr(strh.data)+uintptr(strh.len) <=
3323 uintptr(rawh.data)+uintptr(rawh.len) {
3324 // Str is a substring of Raw.
3325 start := uintptr(strh.data) - uintptr(rawh.data)
3326 // safely copy the raw slice header
3327 result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
3328 // substring the raw
3329 result.Str = result.Raw[start : start+uintptr(strh.len)]
3330 } else {
3331 // safely copy both the raw and str slice headers to strings
3332 result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
3333 result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
3334 }
3335 }
3336 return result
3337}
3338
3339// fillIndex finds the position of Raw data and assigns it to the Index field
3340// of the resulting value. If the position cannot be found then Index zero is
3341// used instead.
3342func fillIndex(json string, c *parseContext) {
3343 if len(c.value.Raw) > 0 && !c.calcd {
3344 jhdr := *(*stringHeader)(unsafe.Pointer(&json))
3345 rhdr := *(*stringHeader)(unsafe.Pointer(&(c.value.Raw)))
3346 c.value.Index = int(uintptr(rhdr.data) - uintptr(jhdr.data))
3347 if c.value.Index < 0 || c.value.Index >= len(json) {
3348 c.value.Index = 0
3349 }
3350 }
3351}
3352
3353func stringBytes(s string) []byte {
3354 return *(*[]byte)(unsafe.Pointer(&sliceHeader{
3355 data: (*stringHeader)(unsafe.Pointer(&s)).data,
3356 len: len(s),
3357 cap: len(s),
3358 }))
3359}
3360
3361func bytesString(b []byte) string {
3362 return *(*string)(unsafe.Pointer(&b))
3363}
3364
3365func revSquash(json string) string {
3366 // reverse squash
3367 // expects that the tail character is a ']' or '}' or ')' or '"'
3368 // squash the value, ignoring all nested arrays and objects.
3369 i := len(json) - 1
3370 var depth int
3371 if json[i] != '"' {
3372 depth++
3373 }
3374 if json[i] == '}' || json[i] == ']' || json[i] == ')' {
3375 i--
3376 }
3377 for ; i >= 0; i-- {
3378 switch json[i] {
3379 case '"':
3380 i--
3381 for ; i >= 0; i-- {
3382 if json[i] == '"' {
3383 esc := 0
3384 for i > 0 && json[i-1] == '\\' {
3385 i--
3386 esc++
3387 }
3388 if esc%2 == 1 {
3389 continue
3390 }
3391 i += esc
3392 break
3393 }
3394 }
3395 if depth == 0 {
3396 if i < 0 {
3397 i = 0
3398 }
3399 return json[i:]
3400 }
3401 case '}', ']', ')':
3402 depth++
3403 case '{', '[', '(':
3404 depth--
3405 if depth == 0 {
3406 return json[i:]
3407 }
3408 }
3409 }
3410 return json
3411}
3412
3413// Paths returns the original GJSON paths for a Result where the Result came
3414// from a simple query path that returns an array, like:
3415//
3416// gjson.Get(json, "friends.#.first")
3417//
3418// The returned value will be in the form of a JSON array:
3419//
3420// ["friends.0.first","friends.1.first","friends.2.first"]
3421//
3422// The param 'json' must be the original JSON used when calling Get.
3423//
3424// Returns an empty string if the paths cannot be determined, which can happen
3425// when the Result came from a path that contained a multipath, modifier,
3426// or a nested query.
3427func (t Result) Paths(json string) []string {
3428 if t.Indexes == nil {
3429 return nil
3430 }
3431 paths := make([]string, 0, len(t.Indexes))
3432 t.ForEach(func(_, value Result) bool {
3433 paths = append(paths, value.Path(json))
3434 return true
3435 })
3436 if len(paths) != len(t.Indexes) {
3437 return nil
3438 }
3439 return paths
3440}
3441
3442// Path returns the original GJSON path for a Result where the Result came
3443// from a simple path that returns a single value, like:
3444//
3445// gjson.Get(json, "friends.#(last=Murphy)")
3446//
3447// The returned value will be in the form of a JSON string:
3448//
3449// "friends.0"
3450//
3451// The param 'json' must be the original JSON used when calling Get.
3452//
3453// Returns an empty string if the paths cannot be determined, which can happen
3454// when the Result came from a path that contained a multipath, modifier,
3455// or a nested query.
3456func (t Result) Path(json string) string {
3457 var path []byte
3458 var comps []string // raw components
3459 i := t.Index - 1
3460 if t.Index+len(t.Raw) > len(json) {
3461 // JSON cannot safely contain Result.
3462 goto fail
3463 }
3464 if !strings.HasPrefix(json[t.Index:], t.Raw) {
3465 // Result is not at the JSON index as expected.
3466 goto fail
3467 }
3468 for ; i >= 0; i-- {
3469 if json[i] <= ' ' {
3470 continue
3471 }
3472 if json[i] == ':' {
3473 // inside of object, get the key
3474 for ; i >= 0; i-- {
3475 if json[i] != '"' {
3476 continue
3477 }
3478 break
3479 }
3480 raw := revSquash(json[:i+1])
3481 i = i - len(raw)
3482 comps = append(comps, raw)
3483 // key gotten, now squash the rest
3484 raw = revSquash(json[:i+1])
3485 i = i - len(raw)
3486 i++ // increment the index for next loop step
3487 } else if json[i] == '{' {
3488 // Encountered an open object. The original result was probably an
3489 // object key.
3490 goto fail
3491 } else if json[i] == ',' || json[i] == '[' {
3492 // inside of an array, count the position
3493 var arrIdx int
3494 if json[i] == ',' {
3495 arrIdx++
3496 i--
3497 }
3498 for ; i >= 0; i-- {
3499 if json[i] == ':' {
3500 // Encountered an unexpected colon. The original result was
3501 // probably an object key.
3502 goto fail
3503 } else if json[i] == ',' {
3504 arrIdx++
3505 } else if json[i] == '[' {
3506 comps = append(comps, strconv.Itoa(arrIdx))
3507 break
3508 } else if json[i] == ']' || json[i] == '}' || json[i] == '"' {
3509 raw := revSquash(json[:i+1])
3510 i = i - len(raw) + 1
3511 }
3512 }
3513 }
3514 }
3515 if len(comps) == 0 {
3516 if DisableModifiers {
3517 goto fail
3518 }
3519 return "@this"
3520 }
3521 for i := len(comps) - 1; i >= 0; i-- {
3522 rcomp := Parse(comps[i])
3523 if !rcomp.Exists() {
3524 goto fail
3525 }
3526 comp := Escape(rcomp.String())
3527 path = append(path, '.')
3528 path = append(path, comp...)
3529 }
3530 if len(path) > 0 {
3531 path = path[1:]
3532 }
3533 return string(path)
3534fail:
3535 return ""
3536}
3537
3538// isSafePathKeyChar returns true if the input character is safe for not
3539// needing escaping.
3540func isSafePathKeyChar(c byte) bool {
3541 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
3542 (c >= '0' && c <= '9') || c <= ' ' || c > '~' || c == '_' ||
3543 c == '-' || c == ':'
3544}
3545
3546// Escape returns an escaped path component.
3547//
3548// json := `{
3549// "user":{
3550// "first.name": "Janet",
3551// "last.name": "Prichard"
3552// }
3553// }`
3554// user := gjson.Get(json, "user")
3555// println(user.Get(gjson.Escape("first.name"))
3556// println(user.Get(gjson.Escape("last.name"))
3557// // Output:
3558// // Janet
3559// // Prichard
3560func Escape(comp string) string {
3561 for i := 0; i < len(comp); i++ {
3562 if !isSafePathKeyChar(comp[i]) {
3563 ncomp := make([]byte, len(comp)+1)
3564 copy(ncomp, comp[:i])
3565 ncomp = ncomp[:i]
3566 for ; i < len(comp); i++ {
3567 if !isSafePathKeyChar(comp[i]) {
3568 ncomp = append(ncomp, '\\')
3569 }
3570 ncomp = append(ncomp, comp[i])
3571 }
3572 return string(ncomp)
3573 }
3574 }
3575 return comp
3576}
3577
3578func parseRecursiveDescent(all []Result, parent Result, path string) []Result {
3579 if res := parent.Get(path); res.Exists() {
3580 all = append(all, res)
3581 }
3582 if parent.IsArray() || parent.IsObject() {
3583 parent.ForEach(func(_, val Result) bool {
3584 all = parseRecursiveDescent(all, val, path)
3585 return true
3586 })
3587 }
3588 return all
3589}
3590
3591func modDig(json, arg string) string {
3592 all := parseRecursiveDescent(nil, Parse(json), arg)
3593 var out []byte
3594 out = append(out, '[')
3595 for i, res := range all {
3596 if i > 0 {
3597 out = append(out, ',')
3598 }
3599 out = append(out, res.Raw...)
3600 }
3601 out = append(out, ']')
3602 return string(out)
3603}