github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/util/jsonpath/jsonpath.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors All rights reserved.
     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  	"fmt"
    22  	"io"
    23  	"reflect"
    24  	"strings"
    25  
    26  	"k8s.io/kubernetes/third_party/golang/template"
    27  )
    28  
    29  type JSONPath struct {
    30  	name       string
    31  	parser     *Parser
    32  	stack      [][]reflect.Value //push and pop values in different scopes
    33  	cur        []reflect.Value   //current scope values
    34  	beginRange int
    35  	inRange    int
    36  	endRange   int
    37  }
    38  
    39  func New(name string) *JSONPath {
    40  	return &JSONPath{
    41  		name:       name,
    42  		beginRange: 0,
    43  		inRange:    0,
    44  		endRange:   0,
    45  	}
    46  }
    47  
    48  // Parse parse the given template, return error
    49  func (j *JSONPath) Parse(text string) (err error) {
    50  	j.parser, err = Parse(j.name, text)
    51  	return
    52  }
    53  
    54  // Execute bounds data into template and write the result
    55  func (j *JSONPath) Execute(wr io.Writer, data interface{}) error {
    56  	fullResults, err := j.FindResults(data)
    57  	if err != nil {
    58  		return err
    59  	}
    60  	for ix := range fullResults {
    61  		if err := j.PrintResults(wr, fullResults[ix]); err != nil {
    62  			return err
    63  		}
    64  	}
    65  	return nil
    66  }
    67  
    68  func (j *JSONPath) FindResults(data interface{}) ([][]reflect.Value, error) {
    69  	if j.parser == nil {
    70  		return nil, fmt.Errorf("%s is an incomplete jsonpath template", j.name)
    71  	}
    72  
    73  	j.cur = []reflect.Value{reflect.ValueOf(data)}
    74  	nodes := j.parser.Root.Nodes
    75  	fullResult := [][]reflect.Value{}
    76  	for i := 0; i < len(nodes); i++ {
    77  		node := nodes[i]
    78  		results, err := j.walk(j.cur, node)
    79  		if err != nil {
    80  			return nil, err
    81  		}
    82  
    83  		//encounter an end node, break the current block
    84  		if j.endRange > 0 && j.endRange <= j.inRange {
    85  			j.endRange -= 1
    86  			break
    87  		}
    88  		//encounter a range node, start a range loop
    89  		if j.beginRange > 0 {
    90  			j.beginRange -= 1
    91  			j.inRange += 1
    92  			for k, value := range results {
    93  				j.parser.Root.Nodes = nodes[i+1:]
    94  				if k == len(results)-1 {
    95  					j.inRange -= 1
    96  				}
    97  				nextResults, err := j.FindResults(value.Interface())
    98  				if err != nil {
    99  					return nil, err
   100  				}
   101  				fullResult = append(fullResult, nextResults...)
   102  			}
   103  			break
   104  		}
   105  		fullResult = append(fullResult, results)
   106  	}
   107  	return fullResult, nil
   108  }
   109  
   110  // PrintResults write the results into writer
   111  func (j *JSONPath) PrintResults(wr io.Writer, results []reflect.Value) error {
   112  	for i, r := range results {
   113  		text, err := j.evalToText(r)
   114  		if err != nil {
   115  			return err
   116  		}
   117  		if i != len(results)-1 {
   118  			text = append(text, ' ')
   119  		}
   120  		if _, err = wr.Write(text); err != nil {
   121  			return err
   122  		}
   123  	}
   124  	return nil
   125  }
   126  
   127  // walk visits tree rooted at the given node in DFS order
   128  func (j *JSONPath) walk(value []reflect.Value, node Node) ([]reflect.Value, error) {
   129  	switch node := node.(type) {
   130  	case *ListNode:
   131  		return j.evalList(value, node)
   132  	case *TextNode:
   133  		return []reflect.Value{reflect.ValueOf(node.Text)}, nil
   134  	case *FieldNode:
   135  		return j.evalField(value, node)
   136  	case *ArrayNode:
   137  		return j.evalArray(value, node)
   138  	case *FilterNode:
   139  		return j.evalFilter(value, node)
   140  	case *IntNode:
   141  		return j.evalInt(value, node)
   142  	case *FloatNode:
   143  		return j.evalFloat(value, node)
   144  	case *WildcardNode:
   145  		return j.evalWildcard(value, node)
   146  	case *RecursiveNode:
   147  		return j.evalRecursive(value, node)
   148  	case *UnionNode:
   149  		return j.evalUnion(value, node)
   150  	case *IdentifierNode:
   151  		return j.evalIdentifier(value, node)
   152  	default:
   153  		return value, fmt.Errorf("unexpected Node %v", node)
   154  	}
   155  }
   156  
   157  // evalInt evaluates IntNode
   158  func (j *JSONPath) evalInt(input []reflect.Value, node *IntNode) ([]reflect.Value, error) {
   159  	result := make([]reflect.Value, len(input))
   160  	for i := range input {
   161  		result[i] = reflect.ValueOf(node.Value)
   162  	}
   163  	return result, nil
   164  }
   165  
   166  // evalFloat evaluates FloatNode
   167  func (j *JSONPath) evalFloat(input []reflect.Value, node *FloatNode) ([]reflect.Value, error) {
   168  	result := make([]reflect.Value, len(input))
   169  	for i := range input {
   170  		result[i] = reflect.ValueOf(node.Value)
   171  	}
   172  	return result, nil
   173  }
   174  
   175  // evalList evaluates ListNode
   176  func (j *JSONPath) evalList(value []reflect.Value, node *ListNode) ([]reflect.Value, error) {
   177  	var err error
   178  	curValue := value
   179  	for _, node := range node.Nodes {
   180  		curValue, err = j.walk(curValue, node)
   181  		if err != nil {
   182  			return curValue, err
   183  		}
   184  	}
   185  	return curValue, nil
   186  }
   187  
   188  // evalIdentifier evaluates IdentifierNode
   189  func (j *JSONPath) evalIdentifier(input []reflect.Value, node *IdentifierNode) ([]reflect.Value, error) {
   190  	results := []reflect.Value{}
   191  	switch node.Name {
   192  	case "range":
   193  		j.stack = append(j.stack, j.cur)
   194  		j.beginRange += 1
   195  		results = input
   196  	case "end":
   197  		if j.endRange < j.inRange { //inside a loop, break the current block
   198  			j.endRange += 1
   199  			break
   200  		}
   201  		// the loop is about to end, pop value and continue the following execution
   202  		if len(j.stack) > 0 {
   203  			j.cur, j.stack = j.stack[len(j.stack)-1], j.stack[:len(j.stack)-1]
   204  		} else {
   205  			return results, fmt.Errorf("not in range, nothing to end")
   206  		}
   207  	default:
   208  		return input, fmt.Errorf("unrecongnized identifier %v", node.Name)
   209  	}
   210  	return results, nil
   211  }
   212  
   213  // evalArray evaluates ArrayNode
   214  func (j *JSONPath) evalArray(input []reflect.Value, node *ArrayNode) ([]reflect.Value, error) {
   215  	result := []reflect.Value{}
   216  	for _, value := range input {
   217  
   218  		value, isNil := template.Indirect(value)
   219  		if isNil || (value.Kind() != reflect.Array && value.Kind() != reflect.Slice) {
   220  			return input, fmt.Errorf("%v is not array or slice", value.Type())
   221  		}
   222  		params := node.Params
   223  		if !params[0].Known {
   224  			params[0].Value = 0
   225  		}
   226  		if params[0].Value < 0 {
   227  			params[0].Value += value.Len()
   228  		}
   229  		if !params[1].Known {
   230  			params[1].Value = value.Len()
   231  		}
   232  
   233  		if params[1].Value < 0 {
   234  			params[1].Value += value.Len()
   235  		}
   236  
   237  		sliceLength := value.Len()
   238  		if params[1].Value != params[0].Value { // if you're requesting zero elements, allow it through.
   239  			if params[0].Value >= sliceLength {
   240  				return input, fmt.Errorf("array index out of bounds: index %d, length %d", params[0].Value, sliceLength)
   241  			}
   242  			if params[1].Value > sliceLength {
   243  				return input, fmt.Errorf("array index out of bounds: index %d, length %d", params[1].Value-1, sliceLength)
   244  			}
   245  		}
   246  
   247  		if !params[2].Known {
   248  			value = value.Slice(params[0].Value, params[1].Value)
   249  		} else {
   250  			value = value.Slice3(params[0].Value, params[1].Value, params[2].Value)
   251  		}
   252  		for i := 0; i < value.Len(); i++ {
   253  			result = append(result, value.Index(i))
   254  		}
   255  	}
   256  	return result, nil
   257  }
   258  
   259  // evalUnion evaluates UnionNode
   260  func (j *JSONPath) evalUnion(input []reflect.Value, node *UnionNode) ([]reflect.Value, error) {
   261  	result := []reflect.Value{}
   262  	for _, listNode := range node.Nodes {
   263  		temp, err := j.evalList(input, listNode)
   264  		if err != nil {
   265  			return input, err
   266  		}
   267  		result = append(result, temp...)
   268  	}
   269  	return result, nil
   270  }
   271  
   272  func (j *JSONPath) findFieldInValue(value *reflect.Value, node *FieldNode) (reflect.Value, error) {
   273  	t := value.Type()
   274  	var inlineValue *reflect.Value
   275  	for ix := 0; ix < t.NumField(); ix++ {
   276  		f := t.Field(ix)
   277  		jsonTag := f.Tag.Get("json")
   278  		parts := strings.Split(jsonTag, ",")
   279  		if len(parts) == 0 {
   280  			continue
   281  		}
   282  		if parts[0] == node.Value {
   283  			return value.Field(ix), nil
   284  		}
   285  		if len(parts[0]) == 0 {
   286  			val := value.Field(ix)
   287  			inlineValue = &val
   288  		}
   289  	}
   290  	if inlineValue != nil {
   291  		if inlineValue.Kind() == reflect.Struct {
   292  			// handle 'inline'
   293  			match, err := j.findFieldInValue(inlineValue, node)
   294  			if err != nil {
   295  				return reflect.Value{}, err
   296  			}
   297  			if match.IsValid() {
   298  				return match, nil
   299  			}
   300  		}
   301  	}
   302  	return value.FieldByName(node.Value), nil
   303  }
   304  
   305  // evalField evaluates filed of struct or key of map.
   306  func (j *JSONPath) evalField(input []reflect.Value, node *FieldNode) ([]reflect.Value, error) {
   307  	results := []reflect.Value{}
   308  	// If there's no input, there's no output
   309  	if len(input) == 0 {
   310  		return results, nil
   311  	}
   312  	for _, value := range input {
   313  		var result reflect.Value
   314  		value, isNil := template.Indirect(value)
   315  		if isNil {
   316  			continue
   317  		}
   318  
   319  		if value.Kind() == reflect.Struct {
   320  			var err error
   321  			if result, err = j.findFieldInValue(&value, node); err != nil {
   322  				return nil, err
   323  			}
   324  		} else if value.Kind() == reflect.Map {
   325  			result = value.MapIndex(reflect.ValueOf(node.Value))
   326  		}
   327  		if result.IsValid() {
   328  			results = append(results, result)
   329  		}
   330  	}
   331  	if len(results) == 0 {
   332  		return results, fmt.Errorf("%s is not found", node.Value)
   333  	}
   334  	return results, nil
   335  }
   336  
   337  // evalWildcard extract all contents of the given value
   338  func (j *JSONPath) evalWildcard(input []reflect.Value, node *WildcardNode) ([]reflect.Value, error) {
   339  	results := []reflect.Value{}
   340  	for _, value := range input {
   341  		value, isNil := template.Indirect(value)
   342  		if isNil {
   343  			continue
   344  		}
   345  
   346  		kind := value.Kind()
   347  		if kind == reflect.Struct {
   348  			for i := 0; i < value.NumField(); i++ {
   349  				results = append(results, value.Field(i))
   350  			}
   351  		} else if kind == reflect.Map {
   352  			for _, key := range value.MapKeys() {
   353  				results = append(results, value.MapIndex(key))
   354  			}
   355  		} else if kind == reflect.Array || kind == reflect.Slice || kind == reflect.String {
   356  			for i := 0; i < value.Len(); i++ {
   357  				results = append(results, value.Index(i))
   358  			}
   359  		}
   360  	}
   361  	return results, nil
   362  }
   363  
   364  // evalRecursive visit the given value recursively and push all of them to result
   365  func (j *JSONPath) evalRecursive(input []reflect.Value, node *RecursiveNode) ([]reflect.Value, error) {
   366  	result := []reflect.Value{}
   367  	for _, value := range input {
   368  		results := []reflect.Value{}
   369  		value, isNil := template.Indirect(value)
   370  		if isNil {
   371  			continue
   372  		}
   373  
   374  		kind := value.Kind()
   375  		if kind == reflect.Struct {
   376  			for i := 0; i < value.NumField(); i++ {
   377  				results = append(results, value.Field(i))
   378  			}
   379  		} else if kind == reflect.Map {
   380  			for _, key := range value.MapKeys() {
   381  				results = append(results, value.MapIndex(key))
   382  			}
   383  		} else if kind == reflect.Array || kind == reflect.Slice || kind == reflect.String {
   384  			for i := 0; i < value.Len(); i++ {
   385  				results = append(results, value.Index(i))
   386  			}
   387  		}
   388  		if len(results) != 0 {
   389  			result = append(result, value)
   390  			output, err := j.evalRecursive(results, node)
   391  			if err != nil {
   392  				return result, err
   393  			}
   394  			result = append(result, output...)
   395  		}
   396  	}
   397  	return result, nil
   398  }
   399  
   400  // evalFilter filter array according to FilterNode
   401  func (j *JSONPath) evalFilter(input []reflect.Value, node *FilterNode) ([]reflect.Value, error) {
   402  	results := []reflect.Value{}
   403  	for _, value := range input {
   404  		value, _ = template.Indirect(value)
   405  
   406  		if value.Kind() != reflect.Array && value.Kind() != reflect.Slice {
   407  			return input, fmt.Errorf("%v is not array or slice", value)
   408  		}
   409  		for i := 0; i < value.Len(); i++ {
   410  			temp := []reflect.Value{value.Index(i)}
   411  			lefts, err := j.evalList(temp, node.Left)
   412  
   413  			//case exists
   414  			if node.Operator == "exists" {
   415  				if len(lefts) > 0 {
   416  					results = append(results, value.Index(i))
   417  				}
   418  				continue
   419  			}
   420  
   421  			if err != nil {
   422  				return input, err
   423  			}
   424  
   425  			var left, right interface{}
   426  			if len(lefts) != 1 {
   427  				return input, fmt.Errorf("can only compare one element at a time")
   428  			}
   429  			left = lefts[0].Interface()
   430  
   431  			rights, err := j.evalList(temp, node.Right)
   432  			if err != nil {
   433  				return input, err
   434  			}
   435  			if len(rights) != 1 {
   436  				return input, fmt.Errorf("can only compare one element at a time")
   437  			}
   438  			right = rights[0].Interface()
   439  
   440  			pass := false
   441  			switch node.Operator {
   442  			case "<":
   443  				pass, err = template.Less(left, right)
   444  			case ">":
   445  				pass, err = template.Greater(left, right)
   446  			case "==":
   447  				pass, err = template.Equal(left, right)
   448  			case "!=":
   449  				pass, err = template.NotEqual(left, right)
   450  			case "<=":
   451  				pass, err = template.LessEqual(left, right)
   452  			case ">=":
   453  				pass, err = template.GreaterEqual(left, right)
   454  			default:
   455  				return results, fmt.Errorf("unrecognized filter operator %s", node.Operator)
   456  			}
   457  			if err != nil {
   458  				return results, err
   459  			}
   460  			if pass {
   461  				results = append(results, value.Index(i))
   462  			}
   463  		}
   464  	}
   465  	return results, nil
   466  }
   467  
   468  // evalToText translates reflect value to corresponding text
   469  func (j *JSONPath) evalToText(v reflect.Value) ([]byte, error) {
   470  	iface, ok := template.PrintableValue(v)
   471  	if !ok {
   472  		return nil, fmt.Errorf("can't print type %s", v.Type())
   473  	}
   474  	var buffer bytes.Buffer
   475  	fmt.Fprint(&buffer, iface)
   476  	return buffer.Bytes(), nil
   477  }