@@ -5,84 +5,119 @@ import (
55	"strings" 
66)
77
8- // Field takes a root value or an array of root values, navigates through the 
9- // data tree according to a keypath, and returns the targeted values. `keypath` 
10- // is a dot-separated list of keys, each used as either field name in a struct, 
11- // a key in a map, or a niladic method name. Any error during key evaluation 
12- // results in a nil value. If a method invocation yields multiple return values, 
13- // only the first one is captured. 
8+ // Field takes a value or an array of values, navigates through the data tree 
9+ // according to a keypath, and returns the targeted values. `keypath` is a 
10+ // dot-separated list of keys, each used as either field name in a struct, a key 
11+ // in a map, or a niladic method name. Once a lookup is successful on the first 
12+ // fragment of the keypath, the evaluation continue recursively with the lookup 
13+ // result and the remainder of the keypath. If a key lookup fails, a nil value 
14+ // is returned. If a key lookup results in a method invocation that yields 
15+ // multiple values, only the first one is captured. 
1416// 
15- // When the root is a single object and all the fields along the keypath are 
16- // scalar types, the result is a scalar value. For each array or slice type 
17- // along the path, the result become a slice collecting the result of 
17+ // In cases where the value is a map[string]..., and the first keypath fragment 
18+ // is not a valid key, all partial keypaths are considered as potential keys. 
19+ // For example, if the keypath is "foo.bar.baz", "foo" is considered first, then 
20+ // "foo.bar", then "foo.bar.baz". However, if the map contains both "foo" and 
21+ // "foo.bar" keys, only "foo" will be accessible with this method. 
22+ // 
23+ // When the current value is a single object and all the fields along the 
24+ // keypath are scalar types, the result is a scalar value. For each array or 
25+ // slice type along the path, the result become a slice collecting the result of 
1826// evaluating the sub-path on each individual element. The shape of the result 
1927// is then a N-dimensional array, where N is the number of arrays traversed 
20- // along the path. 
21- // 
22- // Because the implementation is using the reflect package and is mostly type 
23- // agnostic, the resulting arrays are always of type []interface{}, even if the 
24- // field types are consistent across values. 
28+ // along the path. Arrays are always returns as a type agnostic array 
29+ // (`[]interface{}`), even if all the values have a consistent type. 
2530func  Field (value  interface {}, keypath  string ) interface {} {
2631	var  keys  =  strings .Split (keypath , "." )
27- 	return  field (value , keys )
32+ 	var  v  =  reflect .ValueOf (value )
33+ 	var  rv  =  field (v , keys )
34+ 	if  rv .IsValid () &&  rv .CanInterface () {
35+ 		return  rv .Interface ()
36+ 	}
37+ 	return  nil 
2838}
2939
30- func  field (value  interface {}, keypath  []string ) interface {} {
31- 	if  len (keypath ) ==  0  ||  value  ==  nil  {
32- 		return  value 
40+ func  isNil (v  reflect.Value ) bool  {
41+ 	switch  v .Kind () {
42+ 	case  reflect .Chan , reflect .Func , reflect .Map , reflect .Ptr ,
43+ 		reflect .UnsafePointer , reflect .Interface , reflect .Slice :
44+ 
45+ 		return  v .IsNil ()
46+ 	default :
47+ 		return  false 
48+ 	}
49+ }
50+ 
51+ func  field (v  reflect.Value , keypath  []string ) reflect.Value  {
52+ 	if  len (keypath ) ==  0  ||  isNil (v ) ||  ! v .IsValid () {
53+ 		return  v 
3354	}
3455
35- 	v  :=  reflect .ValueOf (value )
3656	switch  v .Type ().Kind () {
37- 	case  reflect .Ptr :
38- 		return  field (v .Elem (). Interface () , keypath )
57+ 	case  reflect .Ptr ,  reflect . Interface :
58+ 		return  field (v .Elem (), keypath )
3959
4060	case  reflect .Array , reflect .Slice :
41- 		r   : =  make ([]interface {}, v .Len ())
61+ 		var   r   =  make ([]interface {}, v .Len ())
4262		for  i  :=  0 ; i  <  v .Len (); i ++  {
43- 			vv  :=  v .Index (i )
44- 			r [i ] =  field (vv .Interface (), keypath )
63+ 			var  vv  =  v .Index (i )
64+ 			var  rv  =  field (vv , keypath )
65+ 			if  rv .IsValid () &&  rv .CanInterface () {
66+ 				r [i ] =  rv .Interface ()
67+ 			}
4568		}
46- 		return  r 
69+ 		return  reflect . ValueOf ( r ) 
4770
4871	case  reflect .Struct :
49- 		r   : =  extractStructField (v , keypath [0 ])
72+ 		var   r   =  extractStructField (v , keypath [0 ])
5073		return  field (r , keypath [1 :])
5174
5275	case  reflect .Map :
53- 		r   : =  extractMapField (v , keypath [ 0 ] )
54- 		return  field (r , keypath [ 1 :] )
76+ 		var   r ,  remainingKeypath   =  extractMapField (v , keypath )
77+ 		return  field (r , remainingKeypath )
5578
5679	}
57- 	return  nil 
80+ 	return  reflect. Value {} 
5881}
5982
60- func  extractStructField (v  reflect.Value , key  string ) ( r   interface {})  {
83+ func  extractStructField (v  reflect.Value , key  string ) reflect. Value  {
6184	vt  :=  v .Type ()
6285	if  field , ok  :=  vt .FieldByName (key ); ok  {
6386		rv  :=  v .FieldByIndex (field .Index )
6487		if  rv .IsValid () &&  rv .CanInterface () {
65- 			return  rv . Interface () 
88+ 			return  rv 
6689		}
6790	}
6891	if  m , ok  :=  vt .MethodByName (key ); ok  {
6992		return  invokeMethod (v , m )
7093	}
71- 	return  nil 
94+ 
95+ 	if  v .CanAddr () {
96+ 		var  pv  =  v .Addr ()
97+ 		var  pvt  =  pv .Type ()
98+ 		if  m , ok  :=  pvt .MethodByName (key ); ok  {
99+ 			return  invokeMethod (pv , m )
100+ 		}
101+ 	}
102+ 
103+ 	return  reflect.Value {}
72104}
73105
74- func  extractMapField (v  reflect.Value , key  string ) (r  interface {}) {
75- 	rv  :=  v .MapIndex (reflect .ValueOf (key ))
76- 	if  rv .IsValid () &&  rv .CanInterface () {
77- 		return  rv .Interface ()
106+ func  extractMapField (v  reflect.Value , keypath  []string ) (r  reflect.Value , remainingKeypath  []string ) {
107+ 	for  i  :=  range  keypath  {
108+ 		var  key  =  strings .Join (keypath [:i + 1 ], "." )
109+ 		var  rv  =  v .MapIndex (reflect .ValueOf (key ))
110+ 		if  rv .IsValid () &&  rv .CanInterface () {
111+ 			return  rv , keypath [i + 1 :]
112+ 		}
78113	}
79- 	return  nil 
114+ 	return  reflect. Value {},  nil 
80115}
81116
82- func  invokeMethod (v  reflect.Value , m  reflect.Method ) ( r   interface {})  {
117+ func  invokeMethod (v  reflect.Value , m  reflect.Method ) reflect. Value  {
83118	if  m .Type .NumIn () ==  1  &&  m .Type .NumOut () >=  1  {
84119		rvs  :=  m .Func .Call ([]reflect.Value {v })
85- 		return  rvs [0 ]. Interface () 
120+ 		return  rvs [0 ]
86121	}
87- 	return  nil 
122+ 	return  reflect. Value {} 
88123}
0 commit comments