package response import ( "strconv" "strings" ) type _Node struct { data interface{} parent *_Node index int key string } func (node *_Node) Set(v interface{}) { if node.parent == nil { return } } func (node *_Node) child(key string, callback func(*_Node)) bool { return false } func (node *_Node) get(key string) *_Node { if key == "" { return nil } if key == "*" { return node } switch node.data.(type) { case []interface{}: { sl := node.data.([]interface{}) if i, e := strconv.Atoi(key); e == nil { if i < len(sl) { n := &_Node{ data: sl[i], parent: node, index: i, } return n } } } case map[string]interface{}: { sm := node.data.(map[string]interface{}) if v, has := sm[key]; has { n := &_Node{ data: v, parent: node, key: key, } return n } } } return nil } func (node *_Node) Make(path []string) { if node.data == nil { node.data = make(map[string]interface{}) } makePath(node.data, path) } func makePath(data interface{}, path []string) { if len(path) == 0 { return } k := path[0] next := path[1:] switch data.(type) { case []interface{}: dl := data.([]interface{}) if k == "*" { for _, d := range dl { makePath(d, next) } } else if i, err := strconv.Atoi(k); err != nil { if i < len(dl) { makePath(dl[i], next) } } case map[string]interface{}: dm := data.(map[string]interface{}) if k == "*" { for _, d := range dm { makePath(d, next) } } else { d, has := dm[k] if !has { d = make(map[string]interface{}) dm[k] = d } makePath(d, next) } } } //Pattern 匹配节点并执行callback //pattern 的格式为,使用 . 分割字段层级,对于数组,可以使用 * 或者 数字 指定项目,对于map也可以使用 * 表示匹配该层的所有字段 //优先匹配短路径,例如 a.b 将优先匹配 "a.b", func (node *_Node) Pattern(pattern string, callback func(*_Node) bool) (match bool, isBreak bool) { if pattern == "" { return true, callback(node) } isMatch := false for key := pattern; len(key) > 0; key = spiltKey(key) { next := next(pattern, key) if key == "*" { data := node.data switch data.(type) { case []interface{}: { sl := data.([]interface{}) for i, s := range sl { n := &_Node{ data: s, parent: node, index: i, } match, isBreak := n.Pattern(next, callback) if isBreak { return true, true } isMatch = isMatch || match } } case map[string]interface{}: { sm := data.(map[string]interface{}) if len(sm) > 0 { for k, s := range sm { n := &_Node{ data: s, parent: node, key: k, } match, isBreak := n.Pattern(next, callback) if isBreak { return true, true } isMatch = isMatch || match } } else { n := &_Node{ data: nil, parent: node, key: "", } match, isBreak := n.Pattern(next, callback) if isBreak { return true, true } isMatch = isMatch || match } } } } else { child := node.get(key) if child != nil { match, isBreak := child.Pattern(next, callback) if isBreak { return true, true } isMatch = match } } if isMatch { return true, false } } return false, false } func next(pattern, key string) string { l := len(key) if len(pattern) > l { return pattern[l+1:] } return "" } func spiltKey(key string) string { if index := strings.LastIndex(key, "."); index != -1 { return key[:index] } return "" }