// Package json_tool ... // // Description : 将复杂数据结构转化为 JSONNode 树 // // Author : go_developer@163.com<白茶清欢> // // Date : 2021-03-14 10:40 下午 package json_tool import ( "encoding/json" "fmt" "reflect" "strings" "github.com/tidwall/gjson" "github.com/pkg/errors" "git.zhangdeman.cn/zhangdeman/gopkg/util" ) // NewFilter 获取解析的实例 // // Author : go_developer@163.com<白茶清欢> // // Date : 10:43 下午 2021/3/14 func NewFilter(data interface{}, rule map[string]string) *Filter { return &Filter{ data: data, rule: rule, } } // Filter 解析json树 // // Author : go_developer@163.com<白茶清欢> // // Date : 10:41 下午 2021/3/14 type Filter struct { data interface{} rule map[string]string } // Result 数据过滤结果 // // Author : go_developer@163.com<白茶清欢> // // Date : 10:44 下午 2021/3/14 func (f *Filter) Result() (*DynamicJSON, error) { if !f.isLegalData() { return nil, errors.New("非法的数据,无法转换成json") } result := NewDynamicJSON() byteData, _ := json.Marshal(f.data) source := string(byteData) for extraDataPath, newDataPath := range f.rule { // 为数组的处理 pathArr := strings.Split(extraDataPath, ".[].") val := gjson.Get(source, pathArr[0]) if len(pathArr) == 1 { f.SetValue(result, newDataPath, val.Value(), false, 0) continue } // 支持list再抽取一层,处于性能考虑,这么限制,不做递归无限深度处理 // 还能继续抽取,就认为是 []map[string]interface{} ketList := strings.Split(pathArr[1], ".") for idx, item := range val.Array() { data := item.Map() for _, key := range ketList { if v, exist := data[key]; exist { result.SetValue(strings.ReplaceAll(newDataPath, "[]", fmt.Sprintf("[%d]", idx)), data[key].Raw, v.IsObject() || v.IsArray()) } // 结果集中不存在对应key,丢弃 } } } return result, nil } // SetValue 设置值 // // Author : go_developer@163.com<白茶清欢> // // Date : 12:14 下午 2021/9/10 func (f *Filter) SetValue(result *DynamicJSON, path string, val interface{}, isSetSlice bool, sliceIndex int) { if !isSetSlice { result.SetValue(path, val, false) return } } // isLegalData 判断是否能转换成json结构, 只有slice/map/struct/能转换成slice或map的[]byte是合法的 // // Author : go_developer@163.com<白茶清欢> // // Date : 10:46 下午 2021/3/14 func (f *Filter) isLegalData() bool { val := reflect.ValueOf(f.data) switch val.Kind() { case reflect.Slice: // slice 情况下,对字节数组进行特殊判断 var ( byteData []byte ok bool err error ) if byteData, ok = f.data.([]byte); ok { // 字节数组转map或者slice if err = json.Unmarshal(byteData, &f.data); nil != err { return false } return true } return true case reflect.Map: return true case reflect.Struct: // 结构体转为字符串处理 fallthrough case reflect.Ptr: // 指针 var err error if f.data, err = util.StructToMap(f.data); nil != err { return false } return true default: return false } }