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