I would like to directly navigate to a value in a map. Lets be more specific with the following go code example which should give me the value of "Walter" directly: (https://play.golang.org/p/tYJsvp39hn)
type Signature struct{
Name string
Signed bool
}
path := "Document.Signatures.1.Name"
map := map[string]interface{}{
"Document": map[string]interface{}{
"Signatures": []interface{}{
Signature{ Name: "Hugo", Signed: false },
Signature{ Name: "Walter", Signed: false },
},
"Otherstuff": "asadwa",
},
"AlsoOtherStuff": "adwaw",
}
// map.giveMe(path)
// even better (if possible:) map.change(path,"ToThisNewValue")
I have searched for solutions, but I can't find any on the internet. Maybe one of you knows how to do this or knows a library to use for me.
Thank you so much in advance!
Quite a lot of reflect calls will be needed if there is no predefined struct.
That being said, you can do it by iterating through the map with type checking on every iteration and handling cases accordingly.
// Splitting the path into keys
keys := strings.Split(path, ".")
var value interface{} = map1
for _, key := range keys {
if value, err = Get(key, value); err != nil {
break
}
}
if err == nil {
fmt.Println("Value:", value)
} else {
fmt.Println("Error:", err)
}
func Get(key string, s interface{}) (v interface{}, err error) {
var (
i int64
ok bool
)
switch s.(type) {
case map[string]interface{}:
if v, ok = s.(map[string]interface{})[key]; !ok {
err = fmt.Errorf("Key not present. [Key:%s]", key)
}
case []interface{}:
if i, err = strconv.ParseInt(key, 10, 64); err == nil {
array := s.([]interface{})
if int(i) < len(array) {
v = array[i]
} else {
err = fmt.Errorf("Index out of bounds. [Index:%d] [Array:%v]", i, array)
}
}
case Signature:
r := reflect.ValueOf(s)
v = reflect.Indirect(r).FieldByName(key)
}
//fmt.Println("Value:", v, " Key:", key, "Error:", err)
return v, err
}