...

Source file src/github.com/qri-io/jsonpointer/traversal.go

Documentation: github.com/qri-io/jsonpointer

     1  package jsonpointer
     2  
     3  import (
     4  	"reflect"
     5  )
     6  
     7  // JSONContainer returns any existing child value for a given JSON property string
     8  type JSONContainer interface {
     9  	// JSONProp takes a string reference for a given JSON property.
    10  	// implementations must return any matching property of that name,
    11  	// nil if no such subproperty exists.
    12  	// Note that implementations on slice-types are expected to convert
    13  	// prop to an integer value
    14  	JSONProp(prop string) interface{}
    15  }
    16  
    17  // JSONParent is an interface that enables tree traversal by listing
    18  // all immediate children of an object
    19  type JSONParent interface {
    20  	// JSONChildren should return all immidiate children of this element
    21  	// with json property names as keys, go types as values
    22  	// Note that implementations on slice-types are expected to convert
    23  	// integers to string keys
    24  	JSONProps() map[string]interface{}
    25  }
    26  
    27  // WalkJSON calls visit on all elements in a tree of decoded json
    28  func WalkJSON(tree interface{}, visit func(elem interface{}) error) error {
    29  	if tree == nil {
    30  		return nil
    31  	}
    32  
    33  	if err := visit(tree); err != nil {
    34  		return err
    35  	}
    36  
    37  	if con, ok := tree.(JSONParent); ok {
    38  		for _, ch := range con.JSONProps() {
    39  			if err := WalkJSON(ch, visit); err != nil {
    40  				return err
    41  			}
    42  		}
    43  		return nil
    44  	}
    45  
    46  	// fast-path for common json types
    47  	switch t := tree.(type) {
    48  	case map[string]interface{}:
    49  		for _, val := range t {
    50  			if err := WalkJSON(val, visit); err != nil {
    51  				return err
    52  			}
    53  		}
    54  		return nil
    55  	case []interface{}:
    56  		for _, val := range t {
    57  			if err := WalkJSON(val, visit); err != nil {
    58  				return err
    59  			}
    60  		}
    61  		return nil
    62  	}
    63  
    64  	return walkValue(reflect.ValueOf(tree), visit)
    65  }
    66  
    67  func walkValue(v reflect.Value, visit func(elem interface{}) error) error {
    68  	switch v.Kind() {
    69  	case reflect.Invalid:
    70  		return nil
    71  	case reflect.Ptr:
    72  		if !v.IsNil() {
    73  			walkValue(v.Elem(), visit)
    74  		}
    75  	case reflect.Map:
    76  		for _, key := range v.MapKeys() {
    77  			mi := v.MapIndex(key)
    78  			if mi.CanInterface() {
    79  				WalkJSON(mi.Interface(), visit)
    80  			}
    81  		}
    82  	case reflect.Struct:
    83  		// t := v.Type()
    84  		// TypeOf returns the reflection Type that represents the dynamic type of variable.
    85  		// If variable is a nil interface value, TypeOf returns nil.
    86  		for i := 0; i < v.NumField(); i++ {
    87  			f := v.Field(i)
    88  			// fmt.Printf("%d: %s %s %s = %v\n", i, t.Field(i).Name, f.Type(), t.Field(i).Tag.Get("json"), f.CanInterface())
    89  			if f.CanInterface() {
    90  				WalkJSON(f.Interface(), visit)
    91  			}
    92  		}
    93  	case reflect.Slice, reflect.Array:
    94  		for i := 0; i < v.Len(); i++ {
    95  			WalkJSON(v.Index(i).Interface(), visit)
    96  		}
    97  	}
    98  	return nil
    99  }
   100  

View as plain text