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