// evalRecursive visit the given value recursively and push all of them to result func (j *JSONPath) evalRecursive(input []reflect.Value, node *RecursiveNode) ([]reflect.Value, error) { result := []reflect.Value{} for _, value := range input { results := []reflect.Value{} value, isNil := template.Indirect(value) if isNil { continue } kind := value.Kind() if kind == reflect.Struct { for i := 0; i < value.NumField(); i++ { results = append(results, value.Field(i)) } } else if kind == reflect.Map { for _, key := range value.MapKeys() { results = append(results, value.MapIndex(key)) } } else if kind == reflect.Array || kind == reflect.Slice || kind == reflect.String { for i := 0; i < value.Len(); i++ { results = append(results, value.Index(i)) } } if len(results) != 0 { result = append(result, value) output, err := j.evalRecursive(results, node) if err != nil { return result, err } result = append(result, output...) } } return result, nil }
// evalWildcard extract all contents of the given value func (j *JSONPath) evalWildcard(input []reflect.Value, node *WildcardNode) ([]reflect.Value, error) { results := []reflect.Value{} for _, value := range input { value, isNil := template.Indirect(value) if isNil { continue } kind := value.Kind() if kind == reflect.Struct { for i := 0; i < value.NumField(); i++ { results = append(results, value.Field(i)) } } else if kind == reflect.Map { for _, key := range value.MapKeys() { results = append(results, value.MapIndex(key)) } } else if kind == reflect.Array || kind == reflect.Slice || kind == reflect.String { for i := 0; i < value.Len(); i++ { results = append(results, value.Index(i)) } } } return results, nil }
// evalArray evaluates ArrayNode func (j *JSONPath) evalArray(input []reflect.Value, node *ArrayNode) ([]reflect.Value, error) { result := []reflect.Value{} for _, value := range input { value, isNil := template.Indirect(value) if isNil { continue } if value.Kind() != reflect.Array && value.Kind() != reflect.Slice { return input, fmt.Errorf("%v is not array or slice", value.Type()) } params := node.Params if !params[0].Known { params[0].Value = 0 } if params[0].Value < 0 { params[0].Value += value.Len() } if !params[1].Known { params[1].Value = value.Len() } if params[1].Value < 0 { params[1].Value += value.Len() } sliceLength := value.Len() if params[1].Value != params[0].Value { // if you're requesting zero elements, allow it through. if params[0].Value >= sliceLength { return input, fmt.Errorf("array index out of bounds: index %d, length %d", params[0].Value, sliceLength) } if params[1].Value > sliceLength { return input, fmt.Errorf("array index out of bounds: index %d, length %d", params[1].Value-1, sliceLength) } } if !params[2].Known { value = value.Slice(params[0].Value, params[1].Value) } else { value = value.Slice3(params[0].Value, params[1].Value, params[2].Value) } for i := 0; i < value.Len(); i++ { result = append(result, value.Index(i)) } } return result, nil }
// evalField evaluates field of struct or key of map. func (j *JSONPath) evalField(input []reflect.Value, node *FieldNode) ([]reflect.Value, error) { results := []reflect.Value{} // If there's no input, there's no output if len(input) == 0 { return results, nil } for _, value := range input { var result reflect.Value value, isNil := template.Indirect(value) if isNil { continue } if value.Kind() == reflect.Struct { var err error if result, err = j.findFieldInValue(&value, node); err != nil { return nil, err } } else if value.Kind() == reflect.Map { mapKeyType := value.Type().Key() nodeValue := reflect.ValueOf(node.Value) // node value type must be convertible to map key type if !nodeValue.Type().ConvertibleTo(mapKeyType) { return results, fmt.Errorf("%s is not convertible to %s", nodeValue, mapKeyType) } result = value.MapIndex(nodeValue.Convert(mapKeyType)) } if result.IsValid() { results = append(results, result) } } if len(results) == 0 { if j.allowMissingKeys { return results, nil } return results, fmt.Errorf("%s is not found", node.Value) } return results, nil }
// evalFilter filter array according to FilterNode func (j *JSONPath) evalFilter(input []reflect.Value, node *FilterNode) ([]reflect.Value, error) { results := []reflect.Value{} for _, value := range input { value, _ = template.Indirect(value) if value.Kind() != reflect.Array && value.Kind() != reflect.Slice { return input, fmt.Errorf("%v is not array or slice and cannot be filtered", value) } for i := 0; i < value.Len(); i++ { temp := []reflect.Value{value.Index(i)} lefts, err := j.evalList(temp, node.Left) //case exists if node.Operator == "exists" { if len(lefts) > 0 { results = append(results, value.Index(i)) } continue } if err != nil { return input, err } var left, right interface{} if len(lefts) != 1 { return input, fmt.Errorf("can only compare one element at a time") } left = lefts[0].Interface() rights, err := j.evalList(temp, node.Right) if err != nil { return input, err } if len(rights) != 1 { return input, fmt.Errorf("can only compare one element at a time") } right = rights[0].Interface() pass := false switch node.Operator { case "<": pass, err = template.Less(left, right) case ">": pass, err = template.Greater(left, right) case "==": pass, err = template.Equal(left, right) case "!=": pass, err = template.NotEqual(left, right) case "<=": pass, err = template.LessEqual(left, right) case ">=": pass, err = template.GreaterEqual(left, right) default: return results, fmt.Errorf("unrecognized filter operator %s", node.Operator) } if err != nil { return results, err } if pass { results = append(results, value.Index(i)) } } } return results, nil }