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