k8s.io/client-go@v0.31.1/util/jsonpath/jsonpath.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package jsonpath 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "io" 24 "reflect" 25 "strings" 26 27 "k8s.io/client-go/third_party/forked/golang/template" 28 ) 29 30 type JSONPath struct { 31 name string 32 parser *Parser 33 beginRange int 34 inRange int 35 endRange int 36 37 lastEndNode *Node 38 39 allowMissingKeys bool 40 outputJSON bool 41 } 42 43 // New creates a new JSONPath with the given name. 44 func New(name string) *JSONPath { 45 return &JSONPath{ 46 name: name, 47 beginRange: 0, 48 inRange: 0, 49 endRange: 0, 50 } 51 } 52 53 // AllowMissingKeys allows a caller to specify whether they want an error if a field or map key 54 // cannot be located, or simply an empty result. The receiver is returned for chaining. 55 func (j *JSONPath) AllowMissingKeys(allow bool) *JSONPath { 56 j.allowMissingKeys = allow 57 return j 58 } 59 60 // Parse parses the given template and returns an error. 61 func (j *JSONPath) Parse(text string) error { 62 var err error 63 j.parser, err = Parse(j.name, text) 64 return err 65 } 66 67 // Execute bounds data into template and writes the result. 68 func (j *JSONPath) Execute(wr io.Writer, data interface{}) error { 69 fullResults, err := j.FindResults(data) 70 if err != nil { 71 return err 72 } 73 for ix := range fullResults { 74 if err := j.PrintResults(wr, fullResults[ix]); err != nil { 75 return err 76 } 77 } 78 return nil 79 } 80 81 func (j *JSONPath) FindResults(data interface{}) ([][]reflect.Value, error) { 82 if j.parser == nil { 83 return nil, fmt.Errorf("%s is an incomplete jsonpath template", j.name) 84 } 85 86 cur := []reflect.Value{reflect.ValueOf(data)} 87 nodes := j.parser.Root.Nodes 88 fullResult := [][]reflect.Value{} 89 for i := 0; i < len(nodes); i++ { 90 node := nodes[i] 91 results, err := j.walk(cur, node) 92 if err != nil { 93 return nil, err 94 } 95 96 // encounter an end node, break the current block 97 if j.endRange > 0 && j.endRange <= j.inRange { 98 j.endRange-- 99 j.lastEndNode = &nodes[i] 100 break 101 } 102 // encounter a range node, start a range loop 103 if j.beginRange > 0 { 104 j.beginRange-- 105 j.inRange++ 106 if len(results) > 0 { 107 for _, value := range results { 108 j.parser.Root.Nodes = nodes[i+1:] 109 nextResults, err := j.FindResults(value.Interface()) 110 if err != nil { 111 return nil, err 112 } 113 fullResult = append(fullResult, nextResults...) 114 } 115 } else { 116 // If the range has no results, we still need to process the nodes within the range 117 // so the position will advance to the end node 118 j.parser.Root.Nodes = nodes[i+1:] 119 _, err := j.FindResults(nil) 120 if err != nil { 121 return nil, err 122 } 123 } 124 j.inRange-- 125 126 // Fast forward to resume processing after the most recent end node that was encountered 127 for k := i + 1; k < len(nodes); k++ { 128 if &nodes[k] == j.lastEndNode { 129 i = k 130 break 131 } 132 } 133 continue 134 } 135 fullResult = append(fullResult, results) 136 } 137 return fullResult, nil 138 } 139 140 // EnableJSONOutput changes the PrintResults behavior to return a JSON array of results 141 func (j *JSONPath) EnableJSONOutput(v bool) { 142 j.outputJSON = v 143 } 144 145 // PrintResults writes the results into writer 146 func (j *JSONPath) PrintResults(wr io.Writer, results []reflect.Value) error { 147 if j.outputJSON { 148 // convert the []reflect.Value to something that json 149 // will be able to marshal 150 r := make([]interface{}, 0, len(results)) 151 for i := range results { 152 r = append(r, results[i].Interface()) 153 } 154 results = []reflect.Value{reflect.ValueOf(r)} 155 } 156 for i, r := range results { 157 var text []byte 158 var err error 159 outputJSON := true 160 kind := r.Kind() 161 if kind == reflect.Interface { 162 kind = r.Elem().Kind() 163 } 164 switch kind { 165 case reflect.Map: 166 case reflect.Array: 167 case reflect.Slice: 168 case reflect.Struct: 169 default: 170 outputJSON = false 171 } 172 switch { 173 case outputJSON || j.outputJSON: 174 if j.outputJSON { 175 text, err = json.MarshalIndent(r.Interface(), "", " ") 176 text = append(text, '\n') 177 } else { 178 text, err = json.Marshal(r.Interface()) 179 } 180 default: 181 text, err = j.evalToText(r) 182 } 183 if err != nil { 184 return err 185 } 186 if i != len(results)-1 { 187 text = append(text, ' ') 188 } 189 if _, err = wr.Write(text); err != nil { 190 return err 191 } 192 } 193 194 return nil 195 196 } 197 198 // walk visits tree rooted at the given node in DFS order 199 func (j *JSONPath) walk(value []reflect.Value, node Node) ([]reflect.Value, error) { 200 switch node := node.(type) { 201 case *ListNode: 202 return j.evalList(value, node) 203 case *TextNode: 204 return []reflect.Value{reflect.ValueOf(node.Text)}, nil 205 case *FieldNode: 206 return j.evalField(value, node) 207 case *ArrayNode: 208 return j.evalArray(value, node) 209 case *FilterNode: 210 return j.evalFilter(value, node) 211 case *IntNode: 212 return j.evalInt(value, node) 213 case *BoolNode: 214 return j.evalBool(value, node) 215 case *FloatNode: 216 return j.evalFloat(value, node) 217 case *WildcardNode: 218 return j.evalWildcard(value, node) 219 case *RecursiveNode: 220 return j.evalRecursive(value, node) 221 case *UnionNode: 222 return j.evalUnion(value, node) 223 case *IdentifierNode: 224 return j.evalIdentifier(value, node) 225 default: 226 return value, fmt.Errorf("unexpected Node %v", node) 227 } 228 } 229 230 // evalInt evaluates IntNode 231 func (j *JSONPath) evalInt(input []reflect.Value, node *IntNode) ([]reflect.Value, error) { 232 result := make([]reflect.Value, len(input)) 233 for i := range input { 234 result[i] = reflect.ValueOf(node.Value) 235 } 236 return result, nil 237 } 238 239 // evalFloat evaluates FloatNode 240 func (j *JSONPath) evalFloat(input []reflect.Value, node *FloatNode) ([]reflect.Value, error) { 241 result := make([]reflect.Value, len(input)) 242 for i := range input { 243 result[i] = reflect.ValueOf(node.Value) 244 } 245 return result, nil 246 } 247 248 // evalBool evaluates BoolNode 249 func (j *JSONPath) evalBool(input []reflect.Value, node *BoolNode) ([]reflect.Value, error) { 250 result := make([]reflect.Value, len(input)) 251 for i := range input { 252 result[i] = reflect.ValueOf(node.Value) 253 } 254 return result, nil 255 } 256 257 // evalList evaluates ListNode 258 func (j *JSONPath) evalList(value []reflect.Value, node *ListNode) ([]reflect.Value, error) { 259 var err error 260 curValue := value 261 for _, node := range node.Nodes { 262 curValue, err = j.walk(curValue, node) 263 if err != nil { 264 return curValue, err 265 } 266 } 267 return curValue, nil 268 } 269 270 // evalIdentifier evaluates IdentifierNode 271 func (j *JSONPath) evalIdentifier(input []reflect.Value, node *IdentifierNode) ([]reflect.Value, error) { 272 results := []reflect.Value{} 273 switch node.Name { 274 case "range": 275 j.beginRange++ 276 results = input 277 case "end": 278 if j.inRange > 0 { 279 j.endRange++ 280 } else { 281 return results, fmt.Errorf("not in range, nothing to end") 282 } 283 default: 284 return input, fmt.Errorf("unrecognized identifier %v", node.Name) 285 } 286 return results, nil 287 } 288 289 // evalArray evaluates ArrayNode 290 func (j *JSONPath) evalArray(input []reflect.Value, node *ArrayNode) ([]reflect.Value, error) { 291 result := []reflect.Value{} 292 for _, value := range input { 293 294 value, isNil := template.Indirect(value) 295 if isNil { 296 continue 297 } 298 if value.Kind() != reflect.Array && value.Kind() != reflect.Slice { 299 return input, fmt.Errorf("%v is not array or slice", value.Type()) 300 } 301 params := node.Params 302 if !params[0].Known { 303 params[0].Value = 0 304 } 305 if params[0].Value < 0 { 306 params[0].Value += value.Len() 307 } 308 if !params[1].Known { 309 params[1].Value = value.Len() 310 } 311 312 if params[1].Value < 0 || (params[1].Value == 0 && params[1].Derived) { 313 params[1].Value += value.Len() 314 } 315 sliceLength := value.Len() 316 if params[1].Value != params[0].Value { // if you're requesting zero elements, allow it through. 317 if params[0].Value >= sliceLength || params[0].Value < 0 { 318 return input, fmt.Errorf("array index out of bounds: index %d, length %d", params[0].Value, sliceLength) 319 } 320 if params[1].Value > sliceLength || params[1].Value < 0 { 321 return input, fmt.Errorf("array index out of bounds: index %d, length %d", params[1].Value-1, sliceLength) 322 } 323 if params[0].Value > params[1].Value { 324 return input, fmt.Errorf("starting index %d is greater than ending index %d", params[0].Value, params[1].Value) 325 } 326 } else { 327 return result, nil 328 } 329 330 value = value.Slice(params[0].Value, params[1].Value) 331 332 step := 1 333 if params[2].Known { 334 if params[2].Value <= 0 { 335 return input, fmt.Errorf("step must be > 0") 336 } 337 step = params[2].Value 338 } 339 for i := 0; i < value.Len(); i += step { 340 result = append(result, value.Index(i)) 341 } 342 } 343 return result, nil 344 } 345 346 // evalUnion evaluates UnionNode 347 func (j *JSONPath) evalUnion(input []reflect.Value, node *UnionNode) ([]reflect.Value, error) { 348 result := []reflect.Value{} 349 for _, listNode := range node.Nodes { 350 temp, err := j.evalList(input, listNode) 351 if err != nil { 352 return input, err 353 } 354 result = append(result, temp...) 355 } 356 return result, nil 357 } 358 359 func (j *JSONPath) findFieldInValue(value *reflect.Value, node *FieldNode) (reflect.Value, error) { 360 t := value.Type() 361 var inlineValue *reflect.Value 362 for ix := 0; ix < t.NumField(); ix++ { 363 f := t.Field(ix) 364 jsonTag := f.Tag.Get("json") 365 parts := strings.Split(jsonTag, ",") 366 if len(parts) == 0 { 367 continue 368 } 369 if parts[0] == node.Value { 370 return value.Field(ix), nil 371 } 372 if len(parts[0]) == 0 { 373 val := value.Field(ix) 374 inlineValue = &val 375 } 376 } 377 if inlineValue != nil { 378 if inlineValue.Kind() == reflect.Struct { 379 // handle 'inline' 380 match, err := j.findFieldInValue(inlineValue, node) 381 if err != nil { 382 return reflect.Value{}, err 383 } 384 if match.IsValid() { 385 return match, nil 386 } 387 } 388 } 389 return value.FieldByName(node.Value), nil 390 } 391 392 // evalField evaluates field of struct or key of map. 393 func (j *JSONPath) evalField(input []reflect.Value, node *FieldNode) ([]reflect.Value, error) { 394 results := []reflect.Value{} 395 // If there's no input, there's no output 396 if len(input) == 0 { 397 return results, nil 398 } 399 for _, value := range input { 400 var result reflect.Value 401 value, isNil := template.Indirect(value) 402 if isNil { 403 continue 404 } 405 406 if value.Kind() == reflect.Struct { 407 var err error 408 if result, err = j.findFieldInValue(&value, node); err != nil { 409 return nil, err 410 } 411 } else if value.Kind() == reflect.Map { 412 mapKeyType := value.Type().Key() 413 nodeValue := reflect.ValueOf(node.Value) 414 // node value type must be convertible to map key type 415 if !nodeValue.Type().ConvertibleTo(mapKeyType) { 416 return results, fmt.Errorf("%s is not convertible to %s", nodeValue, mapKeyType) 417 } 418 result = value.MapIndex(nodeValue.Convert(mapKeyType)) 419 } 420 if result.IsValid() { 421 results = append(results, result) 422 } 423 } 424 if len(results) == 0 { 425 if j.allowMissingKeys { 426 return results, nil 427 } 428 return results, fmt.Errorf("%s is not found", node.Value) 429 } 430 return results, nil 431 } 432 433 // evalWildcard extracts all contents of the given value 434 func (j *JSONPath) evalWildcard(input []reflect.Value, node *WildcardNode) ([]reflect.Value, error) { 435 results := []reflect.Value{} 436 for _, value := range input { 437 value, isNil := template.Indirect(value) 438 if isNil { 439 continue 440 } 441 442 kind := value.Kind() 443 if kind == reflect.Struct { 444 for i := 0; i < value.NumField(); i++ { 445 results = append(results, value.Field(i)) 446 } 447 } else if kind == reflect.Map { 448 for _, key := range value.MapKeys() { 449 results = append(results, value.MapIndex(key)) 450 } 451 } else if kind == reflect.Array || kind == reflect.Slice || kind == reflect.String { 452 for i := 0; i < value.Len(); i++ { 453 results = append(results, value.Index(i)) 454 } 455 } 456 } 457 return results, nil 458 } 459 460 // evalRecursive visits the given value recursively and pushes all of them to result 461 func (j *JSONPath) evalRecursive(input []reflect.Value, node *RecursiveNode) ([]reflect.Value, error) { 462 result := []reflect.Value{} 463 for _, value := range input { 464 results := []reflect.Value{} 465 value, isNil := template.Indirect(value) 466 if isNil { 467 continue 468 } 469 470 kind := value.Kind() 471 if kind == reflect.Struct { 472 for i := 0; i < value.NumField(); i++ { 473 results = append(results, value.Field(i)) 474 } 475 } else if kind == reflect.Map { 476 for _, key := range value.MapKeys() { 477 results = append(results, value.MapIndex(key)) 478 } 479 } else if kind == reflect.Array || kind == reflect.Slice || kind == reflect.String { 480 for i := 0; i < value.Len(); i++ { 481 results = append(results, value.Index(i)) 482 } 483 } 484 if len(results) != 0 { 485 result = append(result, value) 486 output, err := j.evalRecursive(results, node) 487 if err != nil { 488 return result, err 489 } 490 result = append(result, output...) 491 } 492 } 493 return result, nil 494 } 495 496 // evalFilter filters array according to FilterNode 497 func (j *JSONPath) evalFilter(input []reflect.Value, node *FilterNode) ([]reflect.Value, error) { 498 results := []reflect.Value{} 499 for _, value := range input { 500 value, _ = template.Indirect(value) 501 502 if value.Kind() != reflect.Array && value.Kind() != reflect.Slice { 503 return input, fmt.Errorf("%v is not array or slice and cannot be filtered", value) 504 } 505 for i := 0; i < value.Len(); i++ { 506 temp := []reflect.Value{value.Index(i)} 507 lefts, err := j.evalList(temp, node.Left) 508 509 //case exists 510 if node.Operator == "exists" { 511 if len(lefts) > 0 { 512 results = append(results, value.Index(i)) 513 } 514 continue 515 } 516 517 if err != nil { 518 return input, err 519 } 520 521 var left, right interface{} 522 switch { 523 case len(lefts) == 0: 524 continue 525 case len(lefts) > 1: 526 return input, fmt.Errorf("can only compare one element at a time") 527 } 528 left = lefts[0].Interface() 529 530 rights, err := j.evalList(temp, node.Right) 531 if err != nil { 532 return input, err 533 } 534 switch { 535 case len(rights) == 0: 536 continue 537 case len(rights) > 1: 538 return input, fmt.Errorf("can only compare one element at a time") 539 } 540 right = rights[0].Interface() 541 542 pass := false 543 switch node.Operator { 544 case "<": 545 pass, err = template.Less(left, right) 546 case ">": 547 pass, err = template.Greater(left, right) 548 case "==": 549 pass, err = template.Equal(left, right) 550 case "!=": 551 pass, err = template.NotEqual(left, right) 552 case "<=": 553 pass, err = template.LessEqual(left, right) 554 case ">=": 555 pass, err = template.GreaterEqual(left, right) 556 default: 557 return results, fmt.Errorf("unrecognized filter operator %s", node.Operator) 558 } 559 if err != nil { 560 return results, err 561 } 562 if pass { 563 results = append(results, value.Index(i)) 564 } 565 } 566 } 567 return results, nil 568 } 569 570 // evalToText translates reflect value to corresponding text 571 func (j *JSONPath) evalToText(v reflect.Value) ([]byte, error) { 572 iface, ok := template.PrintableValue(v) 573 if !ok { 574 return nil, fmt.Errorf("can't print type %s", v.Type()) 575 } 576 if iface == nil { 577 return []byte("null"), nil 578 } 579 var buffer bytes.Buffer 580 fmt.Fprint(&buffer, iface) 581 return buffer.Bytes(), nil 582 }