github.com/fufuok/utils@v1.0.10/xjson/gjson/gjson.go (about) 1 // Package gjson provides searching for json strings. 2 package gjson 3 4 import ( 5 "strconv" 6 "strings" 7 "time" 8 "unicode/utf16" 9 "unicode/utf8" 10 "unsafe" 11 12 "github.com/fufuok/utils/xjson/match" 13 "github.com/fufuok/utils/xjson/pretty" 14 ) 15 16 // Type is Result type 17 type Type int 18 19 const ( 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. 35 func (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(). 55 type 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. 72 func (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. 103 func (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. 118 func (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. 144 func (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. 170 func (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. 185 func (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. 195 func (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. 207 func (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. 212 func (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. 217 func (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. 227 func (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. 306 func (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. 316 func (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 328 type arrayOrMapResult struct { 329 a []Result 330 ai []interface{} 331 o map[string]Result 332 oi map[string]interface{} 333 vc byte 334 } 335 336 func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) { 337 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 } 443 end: 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. 464 func 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)) 513 func ParseBytes(json []byte) Result { 514 return Parse(string(json)) 515 } 516 517 func 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 570 func 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 593 func 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 602 func 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 // } 651 func (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 664 func (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 688 func parseString(json string, i int) (int, string, bool, bool) { 689 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 726 func parseNumber(json string, i int) (int, string) { 727 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 738 func parseLiteral(json string, i int) (int, string) { 739 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 749 type 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 767 func 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 := parseQuery(path[i:]) 797 if !ok { 798 // bad query, end now 799 break 800 } 801 if len(value) >= 2 && value[0] == '"' && 802 value[len(value)-1] == '"' { 803 value = value[1 : len(value)-1] 804 if vesc { 805 value = unescape(value) 806 } 807 } 808 r.query.path = qpath 809 r.query.op = op 810 r.query.value = value 811 812 i = fi - 1 813 if i+1 < len(path) && path[i+1] == '#' { 814 r.query.all = true 815 } 816 } 817 } 818 continue 819 } 820 } 821 r.part = path 822 r.path = "" 823 return 824 } 825 826 // splitQuery takes a query and splits it into three parts: 827 // 828 // path, op, middle, and right. 829 // 830 // So for this query: 831 // 832 // #(first_name=="Murphy").last 833 // 834 // Becomes 835 // 836 // first_name # path 837 // =="Murphy" # middle 838 // .last # right 839 // 840 // Or, 841 // 842 // #(service_roles.#(=="one")).cap 843 // 844 // Becomes 845 // 846 // service_roles.#(=="one") # path 847 // # middle 848 // .cap # right 849 func parseQuery(query string) ( 850 path, op, value, remain string, i int, vesc, ok bool, 851 ) { 852 if len(query) < 2 || query[0] != '#' || 853 (query[1] != '(' && query[1] != '[') { 854 return "", "", "", "", i, false, false 855 } 856 i = 2 857 j := 0 // start of value part 858 depth := 1 859 for ; i < len(query); i++ { 860 if depth == 1 && j == 0 { 861 switch query[i] { 862 case '!', '=', '<', '>', '%': 863 // start of the value part 864 j = i 865 continue 866 } 867 } 868 if query[i] == '\\' { 869 i++ 870 } else if query[i] == '[' || query[i] == '(' { 871 depth++ 872 } else if query[i] == ']' || query[i] == ')' { 873 depth-- 874 if depth == 0 { 875 break 876 } 877 } else if query[i] == '"' { 878 // inside selector string, balance quotes 879 i++ 880 for ; i < len(query); i++ { 881 if query[i] == '\\' { 882 vesc = true 883 i++ 884 } else if query[i] == '"' { 885 break 886 } 887 } 888 } 889 } 890 if depth > 0 { 891 return "", "", "", "", i, false, false 892 } 893 if j > 0 { 894 path = trim(query[2:j]) 895 value = trim(query[j:i]) 896 remain = query[i+1:] 897 // parse the compare op from the value 898 var opsz int 899 switch { 900 case len(value) == 1: 901 opsz = 1 902 case value[0] == '!' && value[1] == '=': 903 opsz = 2 904 case value[0] == '!' && value[1] == '%': 905 opsz = 2 906 case value[0] == '<' && value[1] == '=': 907 opsz = 2 908 case value[0] == '>' && value[1] == '=': 909 opsz = 2 910 case value[0] == '=' && value[1] == '=': 911 value = value[1:] 912 opsz = 1 913 case value[0] == '<': 914 opsz = 1 915 case value[0] == '>': 916 opsz = 1 917 case value[0] == '=': 918 opsz = 1 919 case value[0] == '%': 920 opsz = 1 921 } 922 op = value[:opsz] 923 value = trim(value[opsz:]) 924 } else { 925 path = trim(query[2:i]) 926 remain = query[i+1:] 927 } 928 return path, op, value, remain, i + 1, vesc, true 929 } 930 931 func trim(s string) string { 932 left: 933 if len(s) > 0 && s[0] <= ' ' { 934 s = s[1:] 935 goto left 936 } 937 right: 938 if len(s) > 0 && s[len(s)-1] <= ' ' { 939 s = s[:len(s)-1] 940 goto right 941 } 942 return s 943 } 944 945 // peek at the next byte and see if it's a '@', '[', or '{'. 946 func isDotPiperChar(s string) bool { 947 if DisableModifiers { 948 return false 949 } 950 c := s[0] 951 if c == '@' { 952 // check that the next component is *not* a modifier. 953 i := 1 954 for ; i < len(s); i++ { 955 if s[i] == '.' || s[i] == '|' || s[i] == ':' { 956 break 957 } 958 } 959 _, ok := modifiers[s[1:i]] 960 return ok 961 } 962 return c == '[' || c == '{' 963 } 964 965 type objectPathResult struct { 966 part string 967 path string 968 pipe string 969 piped bool 970 wild bool 971 more bool 972 } 973 974 func parseObjectPath(path string) (r objectPathResult) { 975 for i := 0; i < len(path); i++ { 976 if path[i] == '|' { 977 r.part = path[:i] 978 r.pipe = path[i+1:] 979 r.piped = true 980 return 981 } 982 if path[i] == '.' { 983 r.part = path[:i] 984 if i < len(path)-1 && isDotPiperChar(path[i+1:]) { 985 r.pipe = path[i+1:] 986 r.piped = true 987 } else { 988 r.path = path[i+1:] 989 r.more = true 990 } 991 return 992 } 993 if path[i] == '*' || path[i] == '?' { 994 r.wild = true 995 continue 996 } 997 if path[i] == '\\' { 998 // go into escape mode. this is a slower path that 999 // strips off the escape character from the part. 1000 epart := []byte(path[:i]) 1001 i++ 1002 if i < len(path) { 1003 epart = append(epart, path[i]) 1004 i++ 1005 for ; i < len(path); i++ { 1006 if path[i] == '\\' { 1007 i++ 1008 if i < len(path) { 1009 epart = append(epart, path[i]) 1010 } 1011 continue 1012 } else if path[i] == '.' { 1013 r.part = string(epart) 1014 if i < len(path)-1 && isDotPiperChar(path[i+1:]) { 1015 r.pipe = path[i+1:] 1016 r.piped = true 1017 } else { 1018 r.path = path[i+1:] 1019 r.more = true 1020 } 1021 return 1022 } else if path[i] == '|' { 1023 r.part = string(epart) 1024 r.pipe = path[i+1:] 1025 r.piped = true 1026 return 1027 } else if path[i] == '*' || path[i] == '?' { 1028 r.wild = true 1029 } 1030 epart = append(epart, path[i]) 1031 } 1032 } 1033 // append the last part 1034 r.part = string(epart) 1035 return 1036 } 1037 } 1038 r.part = path 1039 return 1040 } 1041 1042 func parseSquash(json string, i int) (int, string) { 1043 // expects that the lead character is a '[' or '{' or '(' 1044 // squash the value, ignoring all nested arrays and objects. 1045 // the first '[' or '{' or '(' has already been read 1046 s := i 1047 i++ 1048 depth := 1 1049 for ; i < len(json); i++ { 1050 if json[i] >= '"' && json[i] <= '}' { 1051 switch json[i] { 1052 case '"': 1053 i++ 1054 s2 := i 1055 for ; i < len(json); i++ { 1056 if json[i] > '\\' { 1057 continue 1058 } 1059 if json[i] == '"' { 1060 // look for an escaped slash 1061 if json[i-1] == '\\' { 1062 n := 0 1063 for j := i - 2; j > s2-1; j-- { 1064 if json[j] != '\\' { 1065 break 1066 } 1067 n++ 1068 } 1069 if n%2 == 0 { 1070 continue 1071 } 1072 } 1073 break 1074 } 1075 } 1076 case '{', '[', '(': 1077 depth++ 1078 case '}', ']', ')': 1079 depth-- 1080 if depth == 0 { 1081 i++ 1082 return i, json[s:i] 1083 } 1084 } 1085 } 1086 } 1087 return i, json[s:] 1088 } 1089 1090 func parseObject(c *parseContext, i int, path string) (int, bool) { 1091 var pmatch, kesc, vesc, ok, hit bool 1092 var key, val string 1093 rp := parseObjectPath(path) 1094 if !rp.more && rp.piped { 1095 c.pipe = rp.pipe 1096 c.piped = true 1097 } 1098 for i < len(c.json) { 1099 for ; i < len(c.json); i++ { 1100 if c.json[i] == '"' { 1101 // parse_key_string 1102 // this is slightly different from getting s string value 1103 // because we don't need the outer quotes. 1104 i++ 1105 s := i 1106 for ; i < len(c.json); i++ { 1107 if c.json[i] > '\\' { 1108 continue 1109 } 1110 if c.json[i] == '"' { 1111 i, key, kesc, ok = i+1, c.json[s:i], false, true 1112 goto parse_key_string_done 1113 } 1114 if c.json[i] == '\\' { 1115 i++ 1116 for ; i < len(c.json); i++ { 1117 if c.json[i] > '\\' { 1118 continue 1119 } 1120 if c.json[i] == '"' { 1121 // look for an escaped slash 1122 if c.json[i-1] == '\\' { 1123 n := 0 1124 for j := i - 2; j > 0; j-- { 1125 if c.json[j] != '\\' { 1126 break 1127 } 1128 n++ 1129 } 1130 if n%2 == 0 { 1131 continue 1132 } 1133 } 1134 i, key, kesc, ok = i+1, c.json[s:i], true, true 1135 goto parse_key_string_done 1136 } 1137 } 1138 break 1139 } 1140 } 1141 key, kesc, ok = c.json[s:], false, false 1142 parse_key_string_done: 1143 break 1144 } 1145 if c.json[i] == '}' { 1146 return i + 1, false 1147 } 1148 } 1149 if !ok { 1150 return i, false 1151 } 1152 if rp.wild { 1153 if kesc { 1154 pmatch = matchLimit(unescape(key), rp.part) 1155 } else { 1156 pmatch = matchLimit(key, rp.part) 1157 } 1158 } else { 1159 if kesc { 1160 pmatch = rp.part == unescape(key) 1161 } else { 1162 pmatch = rp.part == key 1163 } 1164 } 1165 hit = pmatch && !rp.more 1166 for ; i < len(c.json); i++ { 1167 var num bool 1168 switch c.json[i] { 1169 default: 1170 continue 1171 case '"': 1172 i++ 1173 i, val, vesc, ok = parseString(c.json, i) 1174 if !ok { 1175 return i, false 1176 } 1177 if hit { 1178 if vesc { 1179 c.value.Str = unescape(val[1 : len(val)-1]) 1180 } else { 1181 c.value.Str = val[1 : len(val)-1] 1182 } 1183 c.value.Raw = val 1184 c.value.Type = String 1185 return i, true 1186 } 1187 case '{': 1188 if pmatch && !hit { 1189 i, hit = parseObject(c, i+1, rp.path) 1190 if hit { 1191 return i, true 1192 } 1193 } else { 1194 i, val = parseSquash(c.json, i) 1195 if hit { 1196 c.value.Raw = val 1197 c.value.Type = JSON 1198 return i, true 1199 } 1200 } 1201 case '[': 1202 if pmatch && !hit { 1203 i, hit = parseArray(c, i+1, rp.path) 1204 if hit { 1205 return i, true 1206 } 1207 } else { 1208 i, val = parseSquash(c.json, i) 1209 if hit { 1210 c.value.Raw = val 1211 c.value.Type = JSON 1212 return i, true 1213 } 1214 } 1215 case 'n': 1216 if i+1 < len(c.json) && c.json[i+1] != 'u' { 1217 num = true 1218 break 1219 } 1220 fallthrough 1221 case 't', 'f': 1222 vc := c.json[i] 1223 i, val = parseLiteral(c.json, i) 1224 if hit { 1225 c.value.Raw = val 1226 switch vc { 1227 case 't': 1228 c.value.Type = True 1229 case 'f': 1230 c.value.Type = False 1231 } 1232 return i, true 1233 } 1234 case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 1235 'i', 'I', 'N': 1236 num = true 1237 } 1238 if num { 1239 i, val = parseNumber(c.json, i) 1240 if hit { 1241 c.value.Raw = val 1242 c.value.Type = Number 1243 c.value.Num, _ = strconv.ParseFloat(val, 64) 1244 return i, true 1245 } 1246 } 1247 break 1248 } 1249 } 1250 return i, false 1251 } 1252 1253 // matchLimit will limit the complexity of the match operation to avoid ReDos 1254 // attacks from arbritary inputs. 1255 // See the github.com/tidwall/match.MatchLimit function for more information. 1256 func matchLimit(str, pattern string) bool { 1257 matched, _ := match.MatchLimit(str, pattern, 10000) 1258 return matched 1259 } 1260 1261 func falseish(t Result) bool { 1262 switch t.Type { 1263 case Null: 1264 return true 1265 case False: 1266 return true 1267 case String: 1268 b, err := strconv.ParseBool(strings.ToLower(t.Str)) 1269 if err != nil { 1270 return false 1271 } 1272 return !b 1273 case Number: 1274 return t.Num == 0 1275 default: 1276 return false 1277 } 1278 } 1279 1280 func trueish(t Result) bool { 1281 switch t.Type { 1282 case True: 1283 return true 1284 case String: 1285 b, err := strconv.ParseBool(strings.ToLower(t.Str)) 1286 if err != nil { 1287 return false 1288 } 1289 return b 1290 case Number: 1291 return t.Num != 0 1292 default: 1293 return false 1294 } 1295 } 1296 1297 func nullish(t Result) bool { 1298 return t.Type == Null 1299 } 1300 1301 func queryMatches(rp *arrayPathResult, value Result) bool { 1302 rpv := rp.query.value 1303 if len(rpv) > 0 { 1304 if rpv[0] == '~' { 1305 // convert to bool 1306 rpv = rpv[1:] 1307 var ish, ok bool 1308 switch rpv { 1309 case "*": 1310 ish, ok = value.Exists(), true 1311 case "null": 1312 ish, ok = nullish(value), true 1313 case "true": 1314 ish, ok = trueish(value), true 1315 case "false": 1316 ish, ok = falseish(value), true 1317 } 1318 if ok { 1319 rpv = "true" 1320 if ish { 1321 value = Result{Type: True} 1322 } else { 1323 value = Result{Type: False} 1324 } 1325 } else { 1326 rpv = "" 1327 value = Result{} 1328 } 1329 } 1330 } 1331 if !value.Exists() { 1332 return false 1333 } 1334 if rp.query.op == "" { 1335 // the query is only looking for existence, such as: 1336 // friends.#(name) 1337 // which makes sure that the array "friends" has an element of 1338 // "name" that exists 1339 return true 1340 } 1341 switch value.Type { 1342 case String: 1343 switch rp.query.op { 1344 case "=": 1345 return value.Str == rpv 1346 case "!=": 1347 return value.Str != rpv 1348 case "<": 1349 return value.Str < rpv 1350 case "<=": 1351 return value.Str <= rpv 1352 case ">": 1353 return value.Str > rpv 1354 case ">=": 1355 return value.Str >= rpv 1356 case "%": 1357 return matchLimit(value.Str, rpv) 1358 case "!%": 1359 return !matchLimit(value.Str, rpv) 1360 } 1361 case Number: 1362 rpvn, _ := strconv.ParseFloat(rpv, 64) 1363 switch rp.query.op { 1364 case "=": 1365 return value.Num == rpvn 1366 case "!=": 1367 return value.Num != rpvn 1368 case "<": 1369 return value.Num < rpvn 1370 case "<=": 1371 return value.Num <= rpvn 1372 case ">": 1373 return value.Num > rpvn 1374 case ">=": 1375 return value.Num >= rpvn 1376 } 1377 case True: 1378 switch rp.query.op { 1379 case "=": 1380 return rpv == "true" 1381 case "!=": 1382 return rpv != "true" 1383 case ">": 1384 return rpv == "false" 1385 case ">=": 1386 return true 1387 } 1388 case False: 1389 switch rp.query.op { 1390 case "=": 1391 return rpv == "false" 1392 case "!=": 1393 return rpv != "false" 1394 case "<": 1395 return rpv == "true" 1396 case "<=": 1397 return true 1398 } 1399 } 1400 return false 1401 } 1402 1403 func parseArray(c *parseContext, i int, path string) (int, bool) { 1404 var pmatch, vesc, ok, hit bool 1405 var val string 1406 var h int 1407 var alog []int 1408 var partidx int 1409 var multires []byte 1410 var queryIndexes []int 1411 rp := parseArrayPath(path) 1412 if !rp.arrch { 1413 n, ok := parseUint(rp.part) 1414 if !ok { 1415 partidx = -1 1416 } else { 1417 partidx = int(n) 1418 } 1419 } 1420 if !rp.more && rp.piped { 1421 c.pipe = rp.pipe 1422 c.piped = true 1423 } 1424 1425 procQuery := func(qval Result) bool { 1426 if rp.query.all { 1427 if len(multires) == 0 { 1428 multires = append(multires, '[') 1429 } 1430 } 1431 var tmp parseContext 1432 tmp.value = qval 1433 fillIndex(c.json, &tmp) 1434 parentIndex := tmp.value.Index 1435 var res Result 1436 if qval.Type == JSON { 1437 res = qval.Get(rp.query.path) 1438 } else { 1439 if rp.query.path != "" { 1440 return false 1441 } 1442 res = qval 1443 } 1444 if queryMatches(&rp, res) { 1445 if rp.more { 1446 left, right, ok := splitPossiblePipe(rp.path) 1447 if ok { 1448 rp.path = left 1449 c.pipe = right 1450 c.piped = true 1451 } 1452 res = qval.Get(rp.path) 1453 } else { 1454 res = qval 1455 } 1456 if rp.query.all { 1457 raw := res.Raw 1458 if len(raw) == 0 { 1459 raw = res.String() 1460 } 1461 if raw != "" { 1462 if len(multires) > 1 { 1463 multires = append(multires, ',') 1464 } 1465 multires = append(multires, raw...) 1466 queryIndexes = append(queryIndexes, res.Index+parentIndex) 1467 } 1468 } else { 1469 c.value = res 1470 return true 1471 } 1472 } 1473 return false 1474 } 1475 for i < len(c.json)+1 { 1476 if !rp.arrch { 1477 pmatch = partidx == h 1478 hit = pmatch && !rp.more 1479 } 1480 h++ 1481 if rp.alogok { 1482 alog = append(alog, i) 1483 } 1484 for ; ; i++ { 1485 var ch byte 1486 if i > len(c.json) { 1487 break 1488 } else if i == len(c.json) { 1489 ch = ']' 1490 } else { 1491 ch = c.json[i] 1492 } 1493 var num bool 1494 switch ch { 1495 default: 1496 continue 1497 case '"': 1498 i++ 1499 i, val, vesc, ok = parseString(c.json, i) 1500 if !ok { 1501 return i, false 1502 } 1503 if rp.query.on { 1504 var qval Result 1505 if vesc { 1506 qval.Str = unescape(val[1 : len(val)-1]) 1507 } else { 1508 qval.Str = val[1 : len(val)-1] 1509 } 1510 qval.Raw = val 1511 qval.Type = String 1512 if procQuery(qval) { 1513 return i, true 1514 } 1515 } else if hit { 1516 if rp.alogok { 1517 break 1518 } 1519 if vesc { 1520 c.value.Str = unescape(val[1 : len(val)-1]) 1521 } else { 1522 c.value.Str = val[1 : len(val)-1] 1523 } 1524 c.value.Raw = val 1525 c.value.Type = String 1526 return i, true 1527 } 1528 case '{': 1529 if pmatch && !hit { 1530 i, hit = parseObject(c, i+1, rp.path) 1531 if hit { 1532 if rp.alogok { 1533 break 1534 } 1535 return i, true 1536 } 1537 } else { 1538 i, val = parseSquash(c.json, i) 1539 if rp.query.on { 1540 if procQuery(Result{Raw: val, Type: JSON}) { 1541 return i, true 1542 } 1543 } else if hit { 1544 if rp.alogok { 1545 break 1546 } 1547 c.value.Raw = val 1548 c.value.Type = JSON 1549 return i, true 1550 } 1551 } 1552 case '[': 1553 if pmatch && !hit { 1554 i, hit = parseArray(c, i+1, rp.path) 1555 if hit { 1556 if rp.alogok { 1557 break 1558 } 1559 return i, true 1560 } 1561 } else { 1562 i, val = parseSquash(c.json, i) 1563 if rp.query.on { 1564 if procQuery(Result{Raw: val, Type: JSON}) { 1565 return i, true 1566 } 1567 } else if hit { 1568 if rp.alogok { 1569 break 1570 } 1571 c.value.Raw = val 1572 c.value.Type = JSON 1573 return i, true 1574 } 1575 } 1576 case 'n': 1577 if i+1 < len(c.json) && c.json[i+1] != 'u' { 1578 num = true 1579 break 1580 } 1581 fallthrough 1582 case 't', 'f': 1583 vc := c.json[i] 1584 i, val = parseLiteral(c.json, i) 1585 if rp.query.on { 1586 var qval Result 1587 qval.Raw = val 1588 switch vc { 1589 case 't': 1590 qval.Type = True 1591 case 'f': 1592 qval.Type = False 1593 } 1594 if procQuery(qval) { 1595 return i, true 1596 } 1597 } else if hit { 1598 if rp.alogok { 1599 break 1600 } 1601 c.value.Raw = val 1602 switch vc { 1603 case 't': 1604 c.value.Type = True 1605 case 'f': 1606 c.value.Type = False 1607 } 1608 return i, true 1609 } 1610 case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 1611 'i', 'I', 'N': 1612 num = true 1613 case ']': 1614 if rp.arrch && rp.part == "#" { 1615 if rp.alogok { 1616 left, right, ok := splitPossiblePipe(rp.alogkey) 1617 if ok { 1618 rp.alogkey = left 1619 c.pipe = right 1620 c.piped = true 1621 } 1622 indexes := make([]int, 0, 64) 1623 jsons := make([]byte, 0, 64) 1624 jsons = append(jsons, '[') 1625 for j, k := 0, 0; j < len(alog); j++ { 1626 idx := alog[j] 1627 for idx < len(c.json) { 1628 switch c.json[idx] { 1629 case ' ', '\t', '\r', '\n': 1630 idx++ 1631 continue 1632 } 1633 break 1634 } 1635 if idx < len(c.json) && c.json[idx] != ']' { 1636 _, res, ok := parseAny(c.json, idx, true) 1637 if ok { 1638 res := res.Get(rp.alogkey) 1639 if res.Exists() { 1640 if k > 0 { 1641 jsons = append(jsons, ',') 1642 } 1643 raw := res.Raw 1644 if len(raw) == 0 { 1645 raw = res.String() 1646 } 1647 jsons = append(jsons, []byte(raw)...) 1648 indexes = append(indexes, res.Index) 1649 k++ 1650 } 1651 } 1652 } 1653 } 1654 jsons = append(jsons, ']') 1655 c.value.Type = JSON 1656 c.value.Raw = string(jsons) 1657 c.value.Indexes = indexes 1658 return i + 1, true 1659 } 1660 if rp.alogok { 1661 break 1662 } 1663 1664 c.value.Type = Number 1665 c.value.Num = float64(h - 1) 1666 c.value.Raw = strconv.Itoa(h - 1) 1667 c.calcd = true 1668 return i + 1, true 1669 } 1670 if !c.value.Exists() { 1671 if len(multires) > 0 { 1672 c.value = Result{ 1673 Raw: string(append(multires, ']')), 1674 Type: JSON, 1675 Indexes: queryIndexes, 1676 } 1677 } else if rp.query.all { 1678 c.value = Result{ 1679 Raw: "[]", 1680 Type: JSON, 1681 } 1682 } 1683 } 1684 return i + 1, false 1685 } 1686 if num { 1687 i, val = parseNumber(c.json, i) 1688 if rp.query.on { 1689 var qval Result 1690 qval.Raw = val 1691 qval.Type = Number 1692 qval.Num, _ = strconv.ParseFloat(val, 64) 1693 if procQuery(qval) { 1694 return i, true 1695 } 1696 } else if hit { 1697 if rp.alogok { 1698 break 1699 } 1700 c.value.Raw = val 1701 c.value.Type = Number 1702 c.value.Num, _ = strconv.ParseFloat(val, 64) 1703 return i, true 1704 } 1705 } 1706 break 1707 } 1708 } 1709 return i, false 1710 } 1711 1712 func splitPossiblePipe(path string) (left, right string, ok bool) { 1713 // take a quick peek for the pipe character. If found we'll split the piped 1714 // part of the path into the c.pipe field and shorten the rp. 1715 var possible bool 1716 for i := 0; i < len(path); i++ { 1717 if path[i] == '|' { 1718 possible = true 1719 break 1720 } 1721 } 1722 if !possible { 1723 return 1724 } 1725 1726 if len(path) > 0 && path[0] == '{' { 1727 squashed := squash(path[1:]) 1728 if len(squashed) < len(path)-1 { 1729 squashed = path[:len(squashed)+1] 1730 remain := path[len(squashed):] 1731 if remain[0] == '|' { 1732 return squashed, remain[1:], true 1733 } 1734 } 1735 return 1736 } 1737 1738 // split the left and right side of the path with the pipe character as 1739 // the delimiter. This is a little tricky because we'll need to basically 1740 // parse the entire path. 1741 for i := 0; i < len(path); i++ { 1742 if path[i] == '\\' { 1743 i++ 1744 } else if path[i] == '.' { 1745 if i == len(path)-1 { 1746 return 1747 } 1748 if path[i+1] == '#' { 1749 i += 2 1750 if i == len(path) { 1751 return 1752 } 1753 if path[i] == '[' || path[i] == '(' { 1754 var start, end byte 1755 if path[i] == '[' { 1756 start, end = '[', ']' 1757 } else { 1758 start, end = '(', ')' 1759 } 1760 // inside selector, balance brackets 1761 i++ 1762 depth := 1 1763 for ; i < len(path); i++ { 1764 if path[i] == '\\' { 1765 i++ 1766 } else if path[i] == start { 1767 depth++ 1768 } else if path[i] == end { 1769 depth-- 1770 if depth == 0 { 1771 break 1772 } 1773 } else if path[i] == '"' { 1774 // inside selector string, balance quotes 1775 i++ 1776 for ; i < len(path); i++ { 1777 if path[i] == '\\' { 1778 i++ 1779 } else if path[i] == '"' { 1780 break 1781 } 1782 } 1783 } 1784 } 1785 } 1786 } 1787 } else if path[i] == '|' { 1788 return path[:i], path[i+1:], true 1789 } 1790 } 1791 return 1792 } 1793 1794 // ForEachLine iterates through lines of JSON as specified by the JSON Lines 1795 // format (http://jsonlines.org/). 1796 // Each line is returned as a GJSON Result. 1797 func ForEachLine(json string, iterator func(line Result) bool) { 1798 var res Result 1799 var i int 1800 for { 1801 i, res, _ = parseAny(json, i, true) 1802 if !res.Exists() { 1803 break 1804 } 1805 if !iterator(res) { 1806 return 1807 } 1808 } 1809 } 1810 1811 type subSelector struct { 1812 name string 1813 path string 1814 } 1815 1816 // parseSubSelectors returns the subselectors belonging to a '[path1,path2]' or 1817 // '{"field1":path1,"field2":path2}' type subSelection. It's expected that the 1818 // first character in path is either '[' or '{', and has already been checked 1819 // prior to calling this function. 1820 func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) { 1821 modifier := 0 1822 depth := 1 1823 colon := 0 1824 start := 1 1825 i := 1 1826 pushSel := func() { 1827 var sel subSelector 1828 if colon == 0 { 1829 sel.path = path[start:i] 1830 } else { 1831 sel.name = path[start:colon] 1832 sel.path = path[colon+1 : i] 1833 } 1834 sels = append(sels, sel) 1835 colon = 0 1836 modifier = 0 1837 start = i + 1 1838 } 1839 for ; i < len(path); i++ { 1840 switch path[i] { 1841 case '\\': 1842 i++ 1843 case '@': 1844 if modifier == 0 && i > 0 && (path[i-1] == '.' || path[i-1] == '|') { 1845 modifier = i 1846 } 1847 case ':': 1848 if modifier == 0 && colon == 0 && depth == 1 { 1849 colon = i 1850 } 1851 case ',': 1852 if depth == 1 { 1853 pushSel() 1854 } 1855 case '"': 1856 i++ 1857 loop: 1858 for ; i < len(path); i++ { 1859 switch path[i] { 1860 case '\\': 1861 i++ 1862 case '"': 1863 break loop 1864 } 1865 } 1866 case '[', '(', '{': 1867 depth++ 1868 case ']', ')', '}': 1869 depth-- 1870 if depth == 0 { 1871 pushSel() 1872 path = path[i+1:] 1873 return sels, path, true 1874 } 1875 } 1876 } 1877 return 1878 } 1879 1880 // nameOfLast returns the name of the last component 1881 func nameOfLast(path string) string { 1882 for i := len(path) - 1; i >= 0; i-- { 1883 if path[i] == '|' || path[i] == '.' { 1884 if i > 0 { 1885 if path[i-1] == '\\' { 1886 continue 1887 } 1888 } 1889 return path[i+1:] 1890 } 1891 } 1892 return path 1893 } 1894 1895 func isSimpleName(component string) bool { 1896 for i := 0; i < len(component); i++ { 1897 if component[i] < ' ' { 1898 return false 1899 } 1900 switch component[i] { 1901 case '[', ']', '{', '}', '(', ')', '#', '|', '!': 1902 return false 1903 } 1904 } 1905 return true 1906 } 1907 1908 var hexchars = [...]byte{ 1909 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 1910 'a', 'b', 'c', 'd', 'e', 'f', 1911 } 1912 1913 func appendHex16(dst []byte, x uint16) []byte { 1914 return append(dst, 1915 hexchars[x>>12&0xF], hexchars[x>>8&0xF], 1916 hexchars[x>>4&0xF], hexchars[x>>0&0xF], 1917 ) 1918 } 1919 1920 // AppendJSONString is a convenience function that converts the provided string 1921 // to a valid JSON string and appends it to dst. 1922 func AppendJSONString(dst []byte, s string) []byte { 1923 dst = append(dst, make([]byte, len(s)+2)...) 1924 dst = append(dst[:len(dst)-len(s)-2], '"') 1925 for i := 0; i < len(s); i++ { 1926 if s[i] < ' ' { 1927 dst = append(dst, '\\') 1928 switch s[i] { 1929 case '\b': 1930 dst = append(dst, 'b') 1931 case '\f': 1932 dst = append(dst, 'f') 1933 case '\n': 1934 dst = append(dst, 'n') 1935 case '\r': 1936 dst = append(dst, 'r') 1937 case '\t': 1938 dst = append(dst, 't') 1939 default: 1940 dst = append(dst, 'u') 1941 dst = appendHex16(dst, uint16(s[i])) 1942 } 1943 } else if s[i] == '>' || s[i] == '<' || s[i] == '&' { 1944 dst = append(dst, '\\', 'u') 1945 dst = appendHex16(dst, uint16(s[i])) 1946 } else if s[i] == '\\' { 1947 dst = append(dst, '\\', '\\') 1948 } else if s[i] == '"' { 1949 dst = append(dst, '\\', '"') 1950 } else if s[i] > 127 { 1951 // read utf8 character 1952 r, n := utf8.DecodeRuneInString(s[i:]) 1953 if n == 0 { 1954 break 1955 } 1956 if r == utf8.RuneError && n == 1 { 1957 dst = append(dst, `\ufffd`...) 1958 } else if r == '\u2028' || r == '\u2029' { 1959 dst = append(dst, `\u202`...) 1960 dst = append(dst, hexchars[r&0xF]) 1961 } else { 1962 dst = append(dst, s[i:i+n]...) 1963 } 1964 i = i + n - 1 1965 } else { 1966 dst = append(dst, s[i]) 1967 } 1968 } 1969 return append(dst, '"') 1970 } 1971 1972 type parseContext struct { 1973 json string 1974 value Result 1975 pipe string 1976 piped bool 1977 calcd bool 1978 lines bool 1979 } 1980 1981 // Get searches json for the specified path. 1982 // A path is in dot syntax, such as "name.last" or "age". 1983 // When the value is found it's returned immediately. 1984 // 1985 // A path is a series of keys separated by a dot. 1986 // A key may contain special wildcard characters '*' and '?'. 1987 // To access an array value use the index as the key. 1988 // To get the number of elements in an array or to access a child path, use 1989 // the '#' character. 1990 // The dot and wildcard character can be escaped with '\'. 1991 // 1992 // { 1993 // "name": {"first": "Tom", "last": "Anderson"}, 1994 // "age":37, 1995 // "children": ["Sara","Alex","Jack"], 1996 // "friends": [ 1997 // {"first": "James", "last": "Murphy"}, 1998 // {"first": "Roger", "last": "Craig"} 1999 // ] 2000 // } 2001 // "name.last" >> "Anderson" 2002 // "age" >> 37 2003 // "children" >> ["Sara","Alex","Jack"] 2004 // "children.#" >> 3 2005 // "children.1" >> "Alex" 2006 // "child*.2" >> "Jack" 2007 // "c?ildren.0" >> "Sara" 2008 // "friends.#.first" >> ["James","Roger"] 2009 // 2010 // This function expects that the json is well-formed, and does not validate. 2011 // Invalid json will not panic, but it may return back unexpected results. 2012 // If you are consuming JSON from an unpredictable source then you may want to 2013 // use the Valid function first. 2014 func Get(json, path string) Result { 2015 if len(path) > 1 { 2016 if (path[0] == '@' && !DisableModifiers) || path[0] == '!' { 2017 // possible modifier 2018 var ok bool 2019 var npath string 2020 var rjson string 2021 if path[0] == '@' && !DisableModifiers { 2022 npath, rjson, ok = execModifier(json, path) 2023 } else if path[0] == '!' { 2024 npath, rjson, ok = execStatic(json, path) 2025 } 2026 if ok { 2027 path = npath 2028 if len(path) > 0 && (path[0] == '|' || path[0] == '.') { 2029 res := Get(rjson, path[1:]) 2030 res.Index = 0 2031 res.Indexes = nil 2032 return res 2033 } 2034 return Parse(rjson) 2035 } 2036 } 2037 if path[0] == '[' || path[0] == '{' { 2038 // using a subselector path 2039 kind := path[0] 2040 var ok bool 2041 var subs []subSelector 2042 subs, path, ok = parseSubSelectors(path) 2043 if ok { 2044 if len(path) == 0 || (path[0] == '|' || path[0] == '.') { 2045 var b []byte 2046 b = append(b, kind) 2047 var i int 2048 for _, sub := range subs { 2049 res := Get(json, sub.path) 2050 if res.Exists() { 2051 if i > 0 { 2052 b = append(b, ',') 2053 } 2054 if kind == '{' { 2055 if len(sub.name) > 0 { 2056 if sub.name[0] == '"' && Valid(sub.name) { 2057 b = append(b, sub.name...) 2058 } else { 2059 b = AppendJSONString(b, sub.name) 2060 } 2061 } else { 2062 last := nameOfLast(sub.path) 2063 if isSimpleName(last) { 2064 b = AppendJSONString(b, last) 2065 } else { 2066 b = AppendJSONString(b, "_") 2067 } 2068 } 2069 b = append(b, ':') 2070 } 2071 var raw string 2072 if len(res.Raw) == 0 { 2073 raw = res.String() 2074 if len(raw) == 0 { 2075 raw = "null" 2076 } 2077 } else { 2078 raw = res.Raw 2079 } 2080 b = append(b, raw...) 2081 i++ 2082 } 2083 } 2084 b = append(b, kind+2) 2085 var res Result 2086 res.Raw = string(b) 2087 res.Type = JSON 2088 if len(path) > 0 { 2089 res = res.Get(path[1:]) 2090 } 2091 res.Index = 0 2092 return res 2093 } 2094 } 2095 } 2096 } 2097 var i int 2098 c := &parseContext{json: json} 2099 if len(path) >= 2 && path[0] == '.' && path[1] == '.' { 2100 c.lines = true 2101 parseArray(c, 0, path[2:]) 2102 } else { 2103 for ; i < len(c.json); i++ { 2104 if c.json[i] == '{' { 2105 i++ 2106 parseObject(c, i, path) 2107 break 2108 } 2109 if c.json[i] == '[' { 2110 i++ 2111 parseArray(c, i, path) 2112 break 2113 } 2114 } 2115 } 2116 if c.piped { 2117 res := c.value.Get(c.pipe) 2118 res.Index = 0 2119 return res 2120 } 2121 fillIndex(json, c) 2122 return c.value 2123 } 2124 2125 // GetBytes searches json for the specified path. 2126 // If working with bytes, this method preferred over Get(string(data), path) 2127 func GetBytes(json []byte, path string) Result { 2128 return getBytes(json, path) 2129 } 2130 2131 // runeit returns the rune from the the \uXXXX 2132 func runeit(json string) rune { 2133 n, _ := strconv.ParseUint(json[:4], 16, 64) 2134 return rune(n) 2135 } 2136 2137 // unescape unescapes a string 2138 func unescape(json string) string { 2139 str := make([]byte, 0, len(json)) 2140 for i := 0; i < len(json); i++ { 2141 switch { 2142 default: 2143 str = append(str, json[i]) 2144 case json[i] < ' ': 2145 return string(str) 2146 case json[i] == '\\': 2147 i++ 2148 if i >= len(json) { 2149 return string(str) 2150 } 2151 switch json[i] { 2152 default: 2153 return string(str) 2154 case '\\': 2155 str = append(str, '\\') 2156 case '/': 2157 str = append(str, '/') 2158 case 'b': 2159 str = append(str, '\b') 2160 case 'f': 2161 str = append(str, '\f') 2162 case 'n': 2163 str = append(str, '\n') 2164 case 'r': 2165 str = append(str, '\r') 2166 case 't': 2167 str = append(str, '\t') 2168 case '"': 2169 str = append(str, '"') 2170 case 'u': 2171 if i+5 > len(json) { 2172 return string(str) 2173 } 2174 r := runeit(json[i+1:]) 2175 i += 5 2176 if utf16.IsSurrogate(r) { 2177 // need another code 2178 if len(json[i:]) >= 6 && json[i] == '\\' && 2179 json[i+1] == 'u' { 2180 // we expect it to be correct so just consume it 2181 r = utf16.DecodeRune(r, runeit(json[i+2:])) 2182 i += 6 2183 } 2184 } 2185 // provide enough space to encode the largest utf8 possible 2186 str = append(str, 0, 0, 0, 0, 0, 0, 0, 0) 2187 n := utf8.EncodeRune(str[len(str)-8:], r) 2188 str = str[:len(str)-8+n] 2189 i-- // backtrack index by one 2190 } 2191 } 2192 } 2193 return string(str) 2194 } 2195 2196 // Less return true if a token is less than another token. 2197 // The caseSensitive paramater is used when the tokens are Strings. 2198 // The order when comparing two different type is: 2199 // 2200 // Null < False < Number < String < True < JSON 2201 func (t Result) Less(token Result, caseSensitive bool) bool { 2202 if t.Type < token.Type { 2203 return true 2204 } 2205 if t.Type > token.Type { 2206 return false 2207 } 2208 if t.Type == String { 2209 if caseSensitive { 2210 return t.Str < token.Str 2211 } 2212 return stringLessInsensitive(t.Str, token.Str) 2213 } 2214 if t.Type == Number { 2215 return t.Num < token.Num 2216 } 2217 return t.Raw < token.Raw 2218 } 2219 2220 func stringLessInsensitive(a, b string) bool { 2221 for i := 0; i < len(a) && i < len(b); i++ { 2222 if a[i] >= 'A' && a[i] <= 'Z' { 2223 if b[i] >= 'A' && b[i] <= 'Z' { 2224 // both are uppercase, do nothing 2225 if a[i] < b[i] { 2226 return true 2227 } else if a[i] > b[i] { 2228 return false 2229 } 2230 } else { 2231 // a is uppercase, convert a to lowercase 2232 if a[i]+32 < b[i] { 2233 return true 2234 } else if a[i]+32 > b[i] { 2235 return false 2236 } 2237 } 2238 } else if b[i] >= 'A' && b[i] <= 'Z' { 2239 // b is uppercase, convert b to lowercase 2240 if a[i] < b[i]+32 { 2241 return true 2242 } else if a[i] > b[i]+32 { 2243 return false 2244 } 2245 } else { 2246 // neither are uppercase 2247 if a[i] < b[i] { 2248 return true 2249 } else if a[i] > b[i] { 2250 return false 2251 } 2252 } 2253 } 2254 return len(a) < len(b) 2255 } 2256 2257 // parseAny parses the next value from a json string. 2258 // A Result is returned when the hit param is set. 2259 // The return values are (i int, res Result, ok bool) 2260 func parseAny(json string, i int, hit bool) (int, Result, bool) { 2261 var res Result 2262 var val string 2263 for ; i < len(json); i++ { 2264 if json[i] == '{' || json[i] == '[' { 2265 i, val = parseSquash(json, i) 2266 if hit { 2267 res.Raw = val 2268 res.Type = JSON 2269 } 2270 var tmp parseContext 2271 tmp.value = res 2272 fillIndex(json, &tmp) 2273 return i, tmp.value, true 2274 } 2275 if json[i] <= ' ' { 2276 continue 2277 } 2278 var num bool 2279 switch json[i] { 2280 case '"': 2281 i++ 2282 var vesc bool 2283 var ok bool 2284 i, val, vesc, ok = parseString(json, i) 2285 if !ok { 2286 return i, res, false 2287 } 2288 if hit { 2289 res.Type = String 2290 res.Raw = val 2291 if vesc { 2292 res.Str = unescape(val[1 : len(val)-1]) 2293 } else { 2294 res.Str = val[1 : len(val)-1] 2295 } 2296 } 2297 return i, res, true 2298 case 'n': 2299 if i+1 < len(json) && json[i+1] != 'u' { 2300 num = true 2301 break 2302 } 2303 fallthrough 2304 case 't', 'f': 2305 vc := json[i] 2306 i, val = parseLiteral(json, i) 2307 if hit { 2308 res.Raw = val 2309 switch vc { 2310 case 't': 2311 res.Type = True 2312 case 'f': 2313 res.Type = False 2314 } 2315 return i, res, true 2316 } 2317 case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 2318 'i', 'I', 'N': 2319 num = true 2320 } 2321 if num { 2322 i, val = parseNumber(json, i) 2323 if hit { 2324 res.Raw = val 2325 res.Type = Number 2326 res.Num, _ = strconv.ParseFloat(val, 64) 2327 } 2328 return i, res, true 2329 } 2330 2331 } 2332 return i, res, false 2333 } 2334 2335 // GetMany searches json for the multiple paths. 2336 // The return value is a Result array where the number of items 2337 // will be equal to the number of input paths. 2338 func GetMany(json string, path ...string) []Result { 2339 res := make([]Result, len(path)) 2340 for i, path := range path { 2341 res[i] = Get(json, path) 2342 } 2343 return res 2344 } 2345 2346 // GetManyBytes searches json for the multiple paths. 2347 // The return value is a Result array where the number of items 2348 // will be equal to the number of input paths. 2349 func GetManyBytes(json []byte, path ...string) []Result { 2350 res := make([]Result, len(path)) 2351 for i, path := range path { 2352 res[i] = GetBytes(json, path) 2353 } 2354 return res 2355 } 2356 2357 func validpayload(data []byte, i int) (outi int, ok bool) { 2358 for ; i < len(data); i++ { 2359 switch data[i] { 2360 default: 2361 i, ok = validany(data, i) 2362 if !ok { 2363 return i, false 2364 } 2365 for ; i < len(data); i++ { 2366 switch data[i] { 2367 default: 2368 return i, false 2369 case ' ', '\t', '\n', '\r': 2370 continue 2371 } 2372 } 2373 return i, true 2374 case ' ', '\t', '\n', '\r': 2375 continue 2376 } 2377 } 2378 return i, false 2379 } 2380 2381 func validany(data []byte, i int) (outi int, ok bool) { 2382 for ; i < len(data); i++ { 2383 switch data[i] { 2384 default: 2385 return i, false 2386 case ' ', '\t', '\n', '\r': 2387 continue 2388 case '{': 2389 return validobject(data, i+1) 2390 case '[': 2391 return validarray(data, i+1) 2392 case '"': 2393 return validstring(data, i+1) 2394 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 2395 return validnumber(data, i+1) 2396 case 't': 2397 return validtrue(data, i+1) 2398 case 'f': 2399 return validfalse(data, i+1) 2400 case 'n': 2401 return validnull(data, i+1) 2402 } 2403 } 2404 return i, false 2405 } 2406 2407 func validobject(data []byte, i int) (outi int, ok bool) { 2408 for ; i < len(data); i++ { 2409 switch data[i] { 2410 default: 2411 return i, false 2412 case ' ', '\t', '\n', '\r': 2413 continue 2414 case '}': 2415 return i + 1, true 2416 case '"': 2417 key: 2418 if i, ok = validstring(data, i+1); !ok { 2419 return i, false 2420 } 2421 if i, ok = validcolon(data, i); !ok { 2422 return i, false 2423 } 2424 if i, ok = validany(data, i); !ok { 2425 return i, false 2426 } 2427 if i, ok = validcomma(data, i, '}'); !ok { 2428 return i, false 2429 } 2430 if data[i] == '}' { 2431 return i + 1, true 2432 } 2433 i++ 2434 for ; i < len(data); i++ { 2435 switch data[i] { 2436 default: 2437 return i, false 2438 case ' ', '\t', '\n', '\r': 2439 continue 2440 case '"': 2441 goto key 2442 } 2443 } 2444 return i, false 2445 } 2446 } 2447 return i, false 2448 } 2449 2450 func validcolon(data []byte, i int) (outi int, ok bool) { 2451 for ; i < len(data); i++ { 2452 switch data[i] { 2453 default: 2454 return i, false 2455 case ' ', '\t', '\n', '\r': 2456 continue 2457 case ':': 2458 return i + 1, true 2459 } 2460 } 2461 return i, false 2462 } 2463 2464 func validcomma(data []byte, i int, end byte) (outi int, ok bool) { 2465 for ; i < len(data); i++ { 2466 switch data[i] { 2467 default: 2468 return i, false 2469 case ' ', '\t', '\n', '\r': 2470 continue 2471 case ',': 2472 return i, true 2473 case end: 2474 return i, true 2475 } 2476 } 2477 return i, false 2478 } 2479 2480 func validarray(data []byte, i int) (outi int, ok bool) { 2481 for ; i < len(data); i++ { 2482 switch data[i] { 2483 default: 2484 for ; i < len(data); i++ { 2485 if i, ok = validany(data, i); !ok { 2486 return i, false 2487 } 2488 if i, ok = validcomma(data, i, ']'); !ok { 2489 return i, false 2490 } 2491 if data[i] == ']' { 2492 return i + 1, true 2493 } 2494 } 2495 case ' ', '\t', '\n', '\r': 2496 continue 2497 case ']': 2498 return i + 1, true 2499 } 2500 } 2501 return i, false 2502 } 2503 2504 func validstring(data []byte, i int) (outi int, ok bool) { 2505 for ; i < len(data); i++ { 2506 if data[i] < ' ' { 2507 return i, false 2508 } else if data[i] == '\\' { 2509 i++ 2510 if i == len(data) { 2511 return i, false 2512 } 2513 switch data[i] { 2514 default: 2515 return i, false 2516 case '"', '\\', '/', 'b', 'f', 'n', 'r', 't': 2517 case 'u': 2518 for j := 0; j < 4; j++ { 2519 i++ 2520 if i >= len(data) { 2521 return i, false 2522 } 2523 if !((data[i] >= '0' && data[i] <= '9') || 2524 (data[i] >= 'a' && data[i] <= 'f') || 2525 (data[i] >= 'A' && data[i] <= 'F')) { 2526 return i, false 2527 } 2528 } 2529 } 2530 } else if data[i] == '"' { 2531 return i + 1, true 2532 } 2533 } 2534 return i, false 2535 } 2536 2537 func validnumber(data []byte, i int) (outi int, ok bool) { 2538 i-- 2539 // sign 2540 if data[i] == '-' { 2541 i++ 2542 if i == len(data) { 2543 return i, false 2544 } 2545 if data[i] < '0' || data[i] > '9' { 2546 return i, false 2547 } 2548 } 2549 // int 2550 if i == len(data) { 2551 return i, false 2552 } 2553 if data[i] == '0' { 2554 i++ 2555 } else { 2556 for ; i < len(data); i++ { 2557 if data[i] >= '0' && data[i] <= '9' { 2558 continue 2559 } 2560 break 2561 } 2562 } 2563 // frac 2564 if i == len(data) { 2565 return i, true 2566 } 2567 if data[i] == '.' { 2568 i++ 2569 if i == len(data) { 2570 return i, false 2571 } 2572 if data[i] < '0' || data[i] > '9' { 2573 return i, false 2574 } 2575 i++ 2576 for ; i < len(data); i++ { 2577 if data[i] >= '0' && data[i] <= '9' { 2578 continue 2579 } 2580 break 2581 } 2582 } 2583 // exp 2584 if i == len(data) { 2585 return i, true 2586 } 2587 if data[i] == 'e' || data[i] == 'E' { 2588 i++ 2589 if i == len(data) { 2590 return i, false 2591 } 2592 if data[i] == '+' || data[i] == '-' { 2593 i++ 2594 } 2595 if i == len(data) { 2596 return i, false 2597 } 2598 if data[i] < '0' || data[i] > '9' { 2599 return i, false 2600 } 2601 i++ 2602 for ; i < len(data); i++ { 2603 if data[i] >= '0' && data[i] <= '9' { 2604 continue 2605 } 2606 break 2607 } 2608 } 2609 return i, true 2610 } 2611 2612 func validtrue(data []byte, i int) (outi int, ok bool) { 2613 if i+3 <= len(data) && data[i] == 'r' && data[i+1] == 'u' && 2614 data[i+2] == 'e' { 2615 return i + 3, true 2616 } 2617 return i, false 2618 } 2619 2620 func validfalse(data []byte, i int) (outi int, ok bool) { 2621 if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' && 2622 data[i+2] == 's' && data[i+3] == 'e' { 2623 return i + 4, true 2624 } 2625 return i, false 2626 } 2627 2628 func validnull(data []byte, i int) (outi int, ok bool) { 2629 if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' && 2630 data[i+2] == 'l' { 2631 return i + 3, true 2632 } 2633 return i, false 2634 } 2635 2636 // Valid returns true if the input is valid json. 2637 // 2638 // if !gjson.Valid(json) { 2639 // return errors.New("invalid json") 2640 // } 2641 // value := gjson.Get(json, "name.last") 2642 func Valid(json string) bool { 2643 _, ok := validpayload(stringBytes(json), 0) 2644 return ok 2645 } 2646 2647 // ValidBytes returns true if the input is valid json. 2648 // 2649 // if !gjson.Valid(json) { 2650 // return errors.New("invalid json") 2651 // } 2652 // value := gjson.Get(json, "name.last") 2653 // 2654 // If working with bytes, this method preferred over ValidBytes(string(data)) 2655 func ValidBytes(json []byte) bool { 2656 _, ok := validpayload(json, 0) 2657 return ok 2658 } 2659 2660 func parseUint(s string) (n uint64, ok bool) { 2661 var i int 2662 if i == len(s) { 2663 return 0, false 2664 } 2665 for ; i < len(s); i++ { 2666 if s[i] >= '0' && s[i] <= '9' { 2667 n = n*10 + uint64(s[i]-'0') 2668 } else { 2669 return 0, false 2670 } 2671 } 2672 return n, true 2673 } 2674 2675 func parseInt(s string) (n int64, ok bool) { 2676 var i int 2677 var sign bool 2678 if len(s) > 0 && s[0] == '-' { 2679 sign = true 2680 i++ 2681 } 2682 if i == len(s) { 2683 return 0, false 2684 } 2685 for ; i < len(s); i++ { 2686 if s[i] >= '0' && s[i] <= '9' { 2687 n = n*10 + int64(s[i]-'0') 2688 } else { 2689 return 0, false 2690 } 2691 } 2692 if sign { 2693 return n * -1, true 2694 } 2695 return n, true 2696 } 2697 2698 // safeInt validates a given JSON number 2699 // ensures it lies within the minimum and maximum representable JSON numbers 2700 func safeInt(f float64) (n int64, ok bool) { 2701 // https://tc39.es/ecma262/#sec-number.min_safe_integer 2702 // https://tc39.es/ecma262/#sec-number.max_safe_integer 2703 if f < -9007199254740991 || f > 9007199254740991 { 2704 return 0, false 2705 } 2706 return int64(f), true 2707 } 2708 2709 // execStatic parses the path to find a static value. 2710 // The input expects that the path already starts with a '!' 2711 func execStatic(json, path string) (pathOut, res string, ok bool) { 2712 name := path[1:] 2713 if len(name) > 0 { 2714 switch name[0] { 2715 case '{', '[', '"', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', 2716 '8', '9': 2717 _, res = parseSquash(name, 0) 2718 pathOut = name[len(res):] 2719 return pathOut, res, true 2720 } 2721 } 2722 for i := 1; i < len(path); i++ { 2723 if path[i] == '|' { 2724 pathOut = path[i:] 2725 name = path[1:i] 2726 break 2727 } 2728 if path[i] == '.' { 2729 pathOut = path[i:] 2730 name = path[1:i] 2731 break 2732 } 2733 } 2734 switch strings.ToLower(name) { 2735 case "true", "false", "null", "nan", "inf": 2736 return pathOut, name, true 2737 } 2738 return pathOut, res, false 2739 } 2740 2741 // execModifier parses the path to find a matching modifier function. 2742 // The input expects that the path already starts with a '@' 2743 func execModifier(json, path string) (pathOut, res string, ok bool) { 2744 name := path[1:] 2745 var hasArgs bool 2746 for i := 1; i < len(path); i++ { 2747 if path[i] == ':' { 2748 pathOut = path[i+1:] 2749 name = path[1:i] 2750 hasArgs = len(pathOut) > 0 2751 break 2752 } 2753 if path[i] == '|' { 2754 pathOut = path[i:] 2755 name = path[1:i] 2756 break 2757 } 2758 if path[i] == '.' { 2759 pathOut = path[i:] 2760 name = path[1:i] 2761 break 2762 } 2763 } 2764 if fn, ok := modifiers[name]; ok { 2765 var args string 2766 if hasArgs { 2767 var parsedArgs bool 2768 switch pathOut[0] { 2769 case '{', '[', '"': 2770 // json arg 2771 res := Parse(pathOut) 2772 if res.Exists() { 2773 args = squash(pathOut) 2774 pathOut = pathOut[len(args):] 2775 parsedArgs = true 2776 } 2777 } 2778 if !parsedArgs { 2779 // simple arg 2780 i := 0 2781 for ; i < len(pathOut); i++ { 2782 if pathOut[i] == '|' { 2783 break 2784 } 2785 switch pathOut[i] { 2786 case '{', '[', '"', '(': 2787 s := squash(pathOut[i:]) 2788 i += len(s) - 1 2789 } 2790 } 2791 args = pathOut[:i] 2792 pathOut = pathOut[i:] 2793 } 2794 } 2795 return pathOut, fn(json, args), true 2796 } 2797 return pathOut, res, false 2798 } 2799 2800 // unwrap removes the '[]' or '{}' characters around json 2801 func unwrap(json string) string { 2802 json = trim(json) 2803 if len(json) >= 2 && (json[0] == '[' || json[0] == '{') { 2804 json = json[1 : len(json)-1] 2805 } 2806 return json 2807 } 2808 2809 // DisableModifiers will disable the modifier syntax 2810 var DisableModifiers = false 2811 2812 var modifiers map[string]func(json, arg string) string 2813 2814 func init() { 2815 modifiers = map[string]func(json, arg string) string{ 2816 "pretty": modPretty, 2817 "ugly": modUgly, 2818 "reverse": modReverse, 2819 "this": modThis, 2820 "flatten": modFlatten, 2821 "join": modJoin, 2822 "valid": modValid, 2823 "keys": modKeys, 2824 "values": modValues, 2825 "tostr": modToStr, 2826 "fromstr": modFromStr, 2827 "group": modGroup, 2828 "dig": modDig, 2829 } 2830 } 2831 2832 // AddModifier binds a custom modifier command to the GJSON syntax. 2833 // This operation is not thread safe and should be executed prior to 2834 // using all other gjson function. 2835 func AddModifier(name string, fn func(json, arg string) string) { 2836 modifiers[name] = fn 2837 } 2838 2839 // ModifierExists returns true when the specified modifier exists. 2840 func ModifierExists(name string, fn func(json, arg string) string) bool { 2841 _, ok := modifiers[name] 2842 return ok 2843 } 2844 2845 // cleanWS remove any non-whitespace from string 2846 func cleanWS(s string) string { 2847 for i := 0; i < len(s); i++ { 2848 switch s[i] { 2849 case ' ', '\t', '\n', '\r': 2850 continue 2851 default: 2852 var s2 []byte 2853 for i := 0; i < len(s); i++ { 2854 switch s[i] { 2855 case ' ', '\t', '\n', '\r': 2856 s2 = append(s2, s[i]) 2857 } 2858 } 2859 return string(s2) 2860 } 2861 } 2862 return s 2863 } 2864 2865 // @pretty modifier makes the json look nice. 2866 func modPretty(json, arg string) string { 2867 if len(arg) > 0 { 2868 opts := *pretty.DefaultOptions 2869 Parse(arg).ForEach(func(key, value Result) bool { 2870 switch key.String() { 2871 case "sortKeys": 2872 opts.SortKeys = value.Bool() 2873 case "indent": 2874 opts.Indent = cleanWS(value.String()) 2875 case "prefix": 2876 opts.Prefix = cleanWS(value.String()) 2877 case "width": 2878 opts.Width = int(value.Int()) 2879 } 2880 return true 2881 }) 2882 return bytesString(pretty.PrettyOptions(stringBytes(json), &opts)) 2883 } 2884 return bytesString(pretty.Pretty(stringBytes(json))) 2885 } 2886 2887 // @this returns the current element. Can be used to retrieve the root element. 2888 func modThis(json, arg string) string { 2889 return json 2890 } 2891 2892 // @ugly modifier removes all whitespace. 2893 func modUgly(json, arg string) string { 2894 return bytesString(pretty.Ugly(stringBytes(json))) 2895 } 2896 2897 // @reverse reverses array elements or root object members. 2898 func modReverse(json, arg string) string { 2899 res := Parse(json) 2900 if res.IsArray() { 2901 var values []Result 2902 res.ForEach(func(_, value Result) bool { 2903 values = append(values, value) 2904 return true 2905 }) 2906 out := make([]byte, 0, len(json)) 2907 out = append(out, '[') 2908 for i, j := len(values)-1, 0; i >= 0; i, j = i-1, j+1 { 2909 if j > 0 { 2910 out = append(out, ',') 2911 } 2912 out = append(out, values[i].Raw...) 2913 } 2914 out = append(out, ']') 2915 return bytesString(out) 2916 } 2917 if res.IsObject() { 2918 var keyValues []Result 2919 res.ForEach(func(key, value Result) bool { 2920 keyValues = append(keyValues, key, value) 2921 return true 2922 }) 2923 out := make([]byte, 0, len(json)) 2924 out = append(out, '{') 2925 for i, j := len(keyValues)-2, 0; i >= 0; i, j = i-2, j+1 { 2926 if j > 0 { 2927 out = append(out, ',') 2928 } 2929 out = append(out, keyValues[i+0].Raw...) 2930 out = append(out, ':') 2931 out = append(out, keyValues[i+1].Raw...) 2932 } 2933 out = append(out, '}') 2934 return bytesString(out) 2935 } 2936 return json 2937 } 2938 2939 // @flatten an array with child arrays. 2940 // 2941 // [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,[6,7]] 2942 // 2943 // The {"deep":true} arg can be provide for deep flattening. 2944 // 2945 // [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,6,7] 2946 // 2947 // The original json is returned when the json is not an array. 2948 func modFlatten(json, arg string) string { 2949 res := Parse(json) 2950 if !res.IsArray() { 2951 return json 2952 } 2953 var deep bool 2954 if arg != "" { 2955 Parse(arg).ForEach(func(key, value Result) bool { 2956 if key.String() == "deep" { 2957 deep = value.Bool() 2958 } 2959 return true 2960 }) 2961 } 2962 var out []byte 2963 out = append(out, '[') 2964 var idx int 2965 res.ForEach(func(_, value Result) bool { 2966 var raw string 2967 if value.IsArray() { 2968 if deep { 2969 raw = unwrap(modFlatten(value.Raw, arg)) 2970 } else { 2971 raw = unwrap(value.Raw) 2972 } 2973 } else { 2974 raw = value.Raw 2975 } 2976 raw = strings.TrimSpace(raw) 2977 if len(raw) > 0 { 2978 if idx > 0 { 2979 out = append(out, ',') 2980 } 2981 out = append(out, raw...) 2982 idx++ 2983 } 2984 return true 2985 }) 2986 out = append(out, ']') 2987 return bytesString(out) 2988 } 2989 2990 // @keys extracts the keys from an object. 2991 // 2992 // {"first":"Tom","last":"Smith"} -> ["first","last"] 2993 func modKeys(json, arg string) string { 2994 v := Parse(json) 2995 if !v.Exists() { 2996 return "[]" 2997 } 2998 obj := v.IsObject() 2999 var out strings.Builder 3000 out.WriteByte('[') 3001 var i int 3002 v.ForEach(func(key, _ Result) bool { 3003 if i > 0 { 3004 out.WriteByte(',') 3005 } 3006 if obj { 3007 out.WriteString(key.Raw) 3008 } else { 3009 out.WriteString("null") 3010 } 3011 i++ 3012 return true 3013 }) 3014 out.WriteByte(']') 3015 return out.String() 3016 } 3017 3018 // @values extracts the values from an object. 3019 // 3020 // {"first":"Tom","last":"Smith"} -> ["Tom","Smith"] 3021 func modValues(json, arg string) string { 3022 v := Parse(json) 3023 if !v.Exists() { 3024 return "[]" 3025 } 3026 if v.IsArray() { 3027 return json 3028 } 3029 var out strings.Builder 3030 out.WriteByte('[') 3031 var i int 3032 v.ForEach(func(_, value Result) bool { 3033 if i > 0 { 3034 out.WriteByte(',') 3035 } 3036 out.WriteString(value.Raw) 3037 i++ 3038 return true 3039 }) 3040 out.WriteByte(']') 3041 return out.String() 3042 } 3043 3044 // @join multiple objects into a single object. 3045 // 3046 // [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"} 3047 // 3048 // The arg can be "true" to specify that duplicate keys should be preserved. 3049 // 3050 // [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":37,"age":41} 3051 // 3052 // Without preserved keys: 3053 // 3054 // [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":41} 3055 // 3056 // The original json is returned when the json is not an object. 3057 func modJoin(json, arg string) string { 3058 res := Parse(json) 3059 if !res.IsArray() { 3060 return json 3061 } 3062 var preserve bool 3063 if arg != "" { 3064 Parse(arg).ForEach(func(key, value Result) bool { 3065 if key.String() == "preserve" { 3066 preserve = value.Bool() 3067 } 3068 return true 3069 }) 3070 } 3071 var out []byte 3072 out = append(out, '{') 3073 if preserve { 3074 // Preserve duplicate keys. 3075 var idx int 3076 res.ForEach(func(_, value Result) bool { 3077 if !value.IsObject() { 3078 return true 3079 } 3080 if idx > 0 { 3081 out = append(out, ',') 3082 } 3083 out = append(out, unwrap(value.Raw)...) 3084 idx++ 3085 return true 3086 }) 3087 } else { 3088 // Deduplicate keys and generate an object with stable ordering. 3089 var keys []Result 3090 kvals := make(map[string]Result) 3091 res.ForEach(func(_, value Result) bool { 3092 if !value.IsObject() { 3093 return true 3094 } 3095 value.ForEach(func(key, value Result) bool { 3096 k := key.String() 3097 if _, ok := kvals[k]; !ok { 3098 keys = append(keys, key) 3099 } 3100 kvals[k] = value 3101 return true 3102 }) 3103 return true 3104 }) 3105 for i := 0; i < len(keys); i++ { 3106 if i > 0 { 3107 out = append(out, ',') 3108 } 3109 out = append(out, keys[i].Raw...) 3110 out = append(out, ':') 3111 out = append(out, kvals[keys[i].String()].Raw...) 3112 } 3113 } 3114 out = append(out, '}') 3115 return bytesString(out) 3116 } 3117 3118 // @valid ensures that the json is valid before moving on. An empty string is 3119 // returned when the json is not valid, otherwise it returns the original json. 3120 func modValid(json, arg string) string { 3121 if !Valid(json) { 3122 return "" 3123 } 3124 return json 3125 } 3126 3127 // @fromstr converts a string to json 3128 // 3129 // "{\"id\":1023,\"name\":\"alert\"}" -> {"id":1023,"name":"alert"} 3130 func modFromStr(json, arg string) string { 3131 if !Valid(json) { 3132 return "" 3133 } 3134 return Parse(json).String() 3135 } 3136 3137 // @tostr converts a string to json 3138 // 3139 // {"id":1023,"name":"alert"} -> "{\"id\":1023,\"name\":\"alert\"}" 3140 func modToStr(str, arg string) string { 3141 return string(AppendJSONString(nil, str)) 3142 } 3143 3144 func modGroup(json, arg string) string { 3145 res := Parse(json) 3146 if !res.IsObject() { 3147 return "" 3148 } 3149 var all [][]byte 3150 res.ForEach(func(key, value Result) bool { 3151 if !value.IsArray() { 3152 return true 3153 } 3154 var idx int 3155 value.ForEach(func(_, value Result) bool { 3156 if idx == len(all) { 3157 all = append(all, []byte{}) 3158 } 3159 all[idx] = append(all[idx], ("," + key.Raw + ":" + value.Raw)...) 3160 idx++ 3161 return true 3162 }) 3163 return true 3164 }) 3165 var data []byte 3166 data = append(data, '[') 3167 for i, item := range all { 3168 if i > 0 { 3169 data = append(data, ',') 3170 } 3171 data = append(data, '{') 3172 data = append(data, item[1:]...) 3173 data = append(data, '}') 3174 } 3175 data = append(data, ']') 3176 return string(data) 3177 } 3178 3179 // stringHeader instead of reflect.StringHeader 3180 type stringHeader struct { 3181 data unsafe.Pointer 3182 len int 3183 } 3184 3185 // sliceHeader instead of reflect.SliceHeader 3186 type sliceHeader struct { 3187 data unsafe.Pointer 3188 len int 3189 cap int 3190 } 3191 3192 // getBytes casts the input json bytes to a string and safely returns the 3193 // results as uniquely allocated data. This operation is intended to minimize 3194 // copies and allocations for the large json string->[]byte. 3195 func getBytes(json []byte, path string) Result { 3196 var result Result 3197 if json != nil { 3198 // unsafe cast to string 3199 result = Get(*(*string)(unsafe.Pointer(&json)), path) 3200 // safely get the string headers 3201 rawhi := *(*stringHeader)(unsafe.Pointer(&result.Raw)) 3202 strhi := *(*stringHeader)(unsafe.Pointer(&result.Str)) 3203 // create byte slice headers 3204 rawh := sliceHeader{data: rawhi.data, len: rawhi.len, cap: rawhi.len} 3205 strh := sliceHeader{data: strhi.data, len: strhi.len, cap: rawhi.len} 3206 if strh.data == nil { 3207 // str is nil 3208 if rawh.data == nil { 3209 // raw is nil 3210 result.Raw = "" 3211 } else { 3212 // raw has data, safely copy the slice header to a string 3213 result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh))) 3214 } 3215 result.Str = "" 3216 } else if rawh.data == nil { 3217 // raw is nil 3218 result.Raw = "" 3219 // str has data, safely copy the slice header to a string 3220 result.Str = string(*(*[]byte)(unsafe.Pointer(&strh))) 3221 } else if uintptr(strh.data) >= uintptr(rawh.data) && 3222 uintptr(strh.data)+uintptr(strh.len) <= 3223 uintptr(rawh.data)+uintptr(rawh.len) { 3224 // Str is a substring of Raw. 3225 start := uintptr(strh.data) - uintptr(rawh.data) 3226 // safely copy the raw slice header 3227 result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh))) 3228 // substring the raw 3229 result.Str = result.Raw[start : start+uintptr(strh.len)] 3230 } else { 3231 // safely copy both the raw and str slice headers to strings 3232 result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh))) 3233 result.Str = string(*(*[]byte)(unsafe.Pointer(&strh))) 3234 } 3235 } 3236 return result 3237 } 3238 3239 // fillIndex finds the position of Raw data and assigns it to the Index field 3240 // of the resulting value. If the position cannot be found then Index zero is 3241 // used instead. 3242 func fillIndex(json string, c *parseContext) { 3243 if len(c.value.Raw) > 0 && !c.calcd { 3244 jhdr := *(*stringHeader)(unsafe.Pointer(&json)) 3245 rhdr := *(*stringHeader)(unsafe.Pointer(&(c.value.Raw))) 3246 c.value.Index = int(uintptr(rhdr.data) - uintptr(jhdr.data)) 3247 if c.value.Index < 0 || c.value.Index >= len(json) { 3248 c.value.Index = 0 3249 } 3250 } 3251 } 3252 3253 func stringBytes(s string) []byte { 3254 return *(*[]byte)(unsafe.Pointer(&sliceHeader{ 3255 data: (*stringHeader)(unsafe.Pointer(&s)).data, 3256 len: len(s), 3257 cap: len(s), 3258 })) 3259 } 3260 3261 func bytesString(b []byte) string { 3262 return *(*string)(unsafe.Pointer(&b)) 3263 } 3264 3265 func revSquash(json string) string { 3266 // reverse squash 3267 // expects that the tail character is a ']' or '}' or ')' or '"' 3268 // squash the value, ignoring all nested arrays and objects. 3269 i := len(json) - 1 3270 var depth int 3271 if json[i] != '"' { 3272 depth++ 3273 } 3274 if json[i] == '}' || json[i] == ']' || json[i] == ')' { 3275 i-- 3276 } 3277 for ; i >= 0; i-- { 3278 switch json[i] { 3279 case '"': 3280 i-- 3281 for ; i >= 0; i-- { 3282 if json[i] == '"' { 3283 esc := 0 3284 for i > 0 && json[i-1] == '\\' { 3285 i-- 3286 esc++ 3287 } 3288 if esc%2 == 1 { 3289 continue 3290 } 3291 i += esc 3292 break 3293 } 3294 } 3295 if depth == 0 { 3296 if i < 0 { 3297 i = 0 3298 } 3299 return json[i:] 3300 } 3301 case '}', ']', ')': 3302 depth++ 3303 case '{', '[', '(': 3304 depth-- 3305 if depth == 0 { 3306 return json[i:] 3307 } 3308 } 3309 } 3310 return json 3311 } 3312 3313 // Paths returns the original GJSON paths for a Result where the Result came 3314 // from a simple query path that returns an array, like: 3315 // 3316 // gjson.Get(json, "friends.#.first") 3317 // 3318 // The returned value will be in the form of a JSON array: 3319 // 3320 // ["friends.0.first","friends.1.first","friends.2.first"] 3321 // 3322 // The param 'json' must be the original JSON used when calling Get. 3323 // 3324 // Returns an empty string if the paths cannot be determined, which can happen 3325 // when the Result came from a path that contained a multipath, modifier, 3326 // or a nested query. 3327 func (t Result) Paths(json string) []string { 3328 if t.Indexes == nil { 3329 return nil 3330 } 3331 paths := make([]string, 0, len(t.Indexes)) 3332 t.ForEach(func(_, value Result) bool { 3333 paths = append(paths, value.Path(json)) 3334 return true 3335 }) 3336 if len(paths) != len(t.Indexes) { 3337 return nil 3338 } 3339 return paths 3340 } 3341 3342 // Path returns the original GJSON path for a Result where the Result came 3343 // from a simple path that returns a single value, like: 3344 // 3345 // gjson.Get(json, "friends.#(last=Murphy)") 3346 // 3347 // The returned value will be in the form of a JSON string: 3348 // 3349 // "friends.0" 3350 // 3351 // The param 'json' must be the original JSON used when calling Get. 3352 // 3353 // Returns an empty string if the paths cannot be determined, which can happen 3354 // when the Result came from a path that contained a multipath, modifier, 3355 // or a nested query. 3356 func (t Result) Path(json string) string { 3357 var path []byte 3358 var comps []string // raw components 3359 i := t.Index - 1 3360 if t.Index+len(t.Raw) > len(json) { 3361 // JSON cannot safely contain Result. 3362 goto fail 3363 } 3364 if !strings.HasPrefix(json[t.Index:], t.Raw) { 3365 // Result is not at the JSON index as exepcted. 3366 goto fail 3367 } 3368 for ; i >= 0; i-- { 3369 if json[i] <= ' ' { 3370 continue 3371 } 3372 if json[i] == ':' { 3373 // inside of object, get the key 3374 for ; i >= 0; i-- { 3375 if json[i] != '"' { 3376 continue 3377 } 3378 break 3379 } 3380 raw := revSquash(json[:i+1]) 3381 i = i - len(raw) 3382 comps = append(comps, raw) 3383 // key gotten, now squash the rest 3384 raw = revSquash(json[:i+1]) 3385 i = i - len(raw) 3386 i++ // increment the index for next loop step 3387 } else if json[i] == '{' { 3388 // Encountered an open object. The original result was probably an 3389 // object key. 3390 goto fail 3391 } else if json[i] == ',' || json[i] == '[' { 3392 // inside of an array, count the position 3393 var arrIdx int 3394 if json[i] == ',' { 3395 arrIdx++ 3396 i-- 3397 } 3398 for ; i >= 0; i-- { 3399 if json[i] == ':' { 3400 // Encountered an unexpected colon. The original result was 3401 // probably an object key. 3402 goto fail 3403 } else if json[i] == ',' { 3404 arrIdx++ 3405 } else if json[i] == '[' { 3406 comps = append(comps, strconv.Itoa(arrIdx)) 3407 break 3408 } else if json[i] == ']' || json[i] == '}' || json[i] == '"' { 3409 raw := revSquash(json[:i+1]) 3410 i = i - len(raw) + 1 3411 } 3412 } 3413 } 3414 } 3415 if len(comps) == 0 { 3416 if DisableModifiers { 3417 goto fail 3418 } 3419 return "@this" 3420 } 3421 for i := len(comps) - 1; i >= 0; i-- { 3422 rcomp := Parse(comps[i]) 3423 if !rcomp.Exists() { 3424 goto fail 3425 } 3426 comp := Escape(rcomp.String()) 3427 path = append(path, '.') 3428 path = append(path, comp...) 3429 } 3430 if len(path) > 0 { 3431 path = path[1:] 3432 } 3433 return string(path) 3434 fail: 3435 return "" 3436 } 3437 3438 // isSafePathKeyChar returns true if the input character is safe for not 3439 // needing escaping. 3440 func isSafePathKeyChar(c byte) bool { 3441 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || 3442 (c >= '0' && c <= '9') || c <= ' ' || c > '~' || c == '_' || 3443 c == '-' || c == ':' 3444 } 3445 3446 // Escape returns an escaped path component. 3447 // 3448 // json := `{ 3449 // "user":{ 3450 // "first.name": "Janet", 3451 // "last.name": "Prichard" 3452 // } 3453 // }` 3454 // user := gjson.Get(json, "user") 3455 // println(user.Get(gjson.Escape("first.name")) 3456 // println(user.Get(gjson.Escape("last.name")) 3457 // // Output: 3458 // // Janet 3459 // // Prichard 3460 func Escape(comp string) string { 3461 for i := 0; i < len(comp); i++ { 3462 if !isSafePathKeyChar(comp[i]) { 3463 ncomp := make([]byte, len(comp)+1) 3464 copy(ncomp, comp[:i]) 3465 ncomp = ncomp[:i] 3466 for ; i < len(comp); i++ { 3467 if !isSafePathKeyChar(comp[i]) { 3468 ncomp = append(ncomp, '\\') 3469 } 3470 ncomp = append(ncomp, comp[i]) 3471 } 3472 return string(ncomp) 3473 } 3474 } 3475 return comp 3476 } 3477 3478 func parseRecursiveDescent(all []Result, parent Result, path string) []Result { 3479 if res := parent.Get(path); res.Exists() { 3480 all = append(all, res) 3481 } 3482 if parent.IsArray() || parent.IsObject() { 3483 parent.ForEach(func(_, val Result) bool { 3484 all = parseRecursiveDescent(all, val, path) 3485 return true 3486 }) 3487 } 3488 return all 3489 } 3490 3491 func modDig(json, arg string) string { 3492 all := parseRecursiveDescent(nil, Parse(json), arg) 3493 var out []byte 3494 out = append(out, '[') 3495 for i, res := range all { 3496 if i > 0 { 3497 out = append(out, ',') 3498 } 3499 out = append(out, res.Raw...) 3500 } 3501 out = append(out, ']') 3502 return string(out) 3503 }