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