mirror of
https://github.com/spf13/viper
synced 2025-05-07 20:57:18 +00:00
Added support for parsing keys with index notation (eg.: "prop[0].sub-prop")
This commit is contained in:
parent
907c19d40d
commit
02aa8552a1
1 changed files with 26 additions and 2 deletions
28
viper.go
28
viper.go
|
@ -29,6 +29,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -480,6 +482,8 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var prefixIndexRE = regexp.MustCompile(`^([^\[]+)(?:\[(\d+)\])?$`)
|
||||||
|
|
||||||
// searchMapWithPathPrefixes recursively searches for a value for path in source map.
|
// searchMapWithPathPrefixes recursively searches for a value for path in source map.
|
||||||
//
|
//
|
||||||
// While searchMap() considers each path element as a single map key, this
|
// While searchMap() considers each path element as a single map key, this
|
||||||
|
@ -500,6 +504,12 @@ func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []
|
||||||
for i := len(path); i > 0; i-- {
|
for i := len(path); i > 0; i-- {
|
||||||
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
|
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
|
||||||
|
|
||||||
|
prefixIndex := prefixIndexRE.ReplaceAllString(prefixKey, "$2")
|
||||||
|
if prefixIndex != "" {
|
||||||
|
// remove the index from the key
|
||||||
|
prefixKey = prefixIndexRE.ReplaceAllString(prefixKey, "$1")
|
||||||
|
}
|
||||||
|
|
||||||
next, ok := source[prefixKey]
|
next, ok := source[prefixKey]
|
||||||
if ok {
|
if ok {
|
||||||
// Fast path
|
// Fast path
|
||||||
|
@ -509,13 +519,27 @@ func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []
|
||||||
|
|
||||||
// Nested case
|
// Nested case
|
||||||
var val interface{}
|
var val interface{}
|
||||||
switch next.(type) {
|
switch n := next.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[interface{}]interface{}:
|
||||||
val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:])
|
val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:])
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
// Type assertion is safe here since it is only reached
|
// Type assertion is safe here since it is only reached
|
||||||
// if the type of `next` is the same as the type being asserted
|
// if the type of `next` is the same as the type being asserted
|
||||||
val = v.searchMapWithPathPrefixes(next.(map[string]interface{}), path[i:])
|
val = v.searchMapWithPathPrefixes(n, path[i:])
|
||||||
|
case []interface{}:
|
||||||
|
if prefixIndex != "" {
|
||||||
|
index, err := strconv.Atoi(prefixIndex)
|
||||||
|
if err == nil {
|
||||||
|
item := n[index]
|
||||||
|
|
||||||
|
switch nextItem := item.(type) {
|
||||||
|
case map[interface{}]interface{}:
|
||||||
|
val = v.searchMapWithPathPrefixes(cast.ToStringMap(nextItem), path[i:])
|
||||||
|
case map[string]interface{}:
|
||||||
|
val = v.searchMapWithPathPrefixes(nextItem, path[i:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// got a value but nested key expected, do nothing and look for next prefix
|
// got a value but nested key expected, do nothing and look for next prefix
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue