// Package filter ... // // Description : filter ... // // Author : go_developer@163.com<白茶清欢> // // Date : 2022-07-04 17:47 package filter import ( "encoding/json" "fmt" "git.zhangdeman.cn/zhangdeman/consts" "git.zhangdeman.cn/zhangdeman/serialize" "git.zhangdeman.cn/zhangdeman/wrapper" "reflect" "strings" "github.com/tidwall/gjson" "github.com/tidwall/sjson" "errors" ) // NewFilter 过滤器实例 // // Author : go_developer@163.com<白茶清欢> // // Date : 11:54 2022/7/4 func NewFilter(sourceData string, filterRuleList []MapRule) *filter { return &filter{ sourceData: sourceData, formatResult: "{}", filterRuleList: filterRuleList, } } // filter 数据过滤 // // Author : go_developer@163.com<白茶清欢> // // Date : 11:58 2022/7/4 type filter struct { sourceData string formatResult string filterRuleList []MapRule } // Deal ... // // Author : go_developer@163.com<白茶清欢> // // Date : 11:59 2022/7/4 func (f *filter) Deal() error { var ( err error formatVal any ) for _, rule := range f.filterRuleList { if f.IsArray(rule) { // 对于list的处理 if err = f.handleArray(rule); nil != err { return err } continue } sourceResult := gjson.Get(f.sourceData, rule.SourcePath) if formatVal, err = f.getValue(rule.DataType, sourceResult, rule.DefaultValue); nil != err { return fmt.Errorf("%s = %v can not convert to %s : %s", rule.SourcePath, sourceResult.Value(), rule.DataType, err.Error()) } if reflect.TypeOf(formatVal).Kind() == reflect.Map { // 获取的数据是map类型, 处理数据覆盖 // eg : 配置如下两个规则 process.id(string) 、process(map[string]any) // 若输入数据的process.id为int类型, 则格式化后的process.id必为 string, 应为 process.id 规则的控制更精细 gjsonVal := gjson.Get(f.formatResult, rule.TargetPath) if gjsonVal.Exists() && gjsonVal.IsObject() { var ( existRes = map[string]any{} formatRes = map[string]any{} ) // 已存在, 且是对象 _ = serialize.JSON.UnmarshalWithNumber([]byte(gjsonVal.String()), &existRes) if err = serialize.JSON.Transition(formatVal, &formatRes); nil != err { return errors.New("conflict data path config deal fail : " + err.Error()) } for k, v := range existRes { formatRes[k] = v } formatVal = formatRes // 重新赋值 formatVal } } if f.formatResult, err = sjson.Set(f.formatResult, rule.TargetPath, formatVal); nil != err { return err } } return nil } // IsArray 判断是否为数组 // // Author : zhangdeman001@ke.com<张德满> // // Date : 17:48 2023/1/1 func (f *filter) IsArray(rule MapRule) bool { return strings.Contains(rule.SourcePath, "[]") } // handleArray 处理数组(最复杂的场景) // // Author : go_developer@163.com<白茶清欢> // // Date : 17:41 2023/1/1 func (f *filter) handleArray(rule MapRule) error { var ( err error ) sourcePathArray := strings.Split(rule.SourcePath, "[]") for idx, item := range sourcePathArray { sourcePathArray[idx] = strings.Trim(item, ".") } mapPathArray := strings.Split(strings.TrimRight(rule.TargetPath, ".[]"), "[]") for idx, item := range mapPathArray { mapPathArray[idx] = strings.Trim(item, ".") } if len(sourcePathArray) != len(mapPathArray) { if len(mapPathArray) != 1 { return errors.New("map rule is invalid") } // 提取某一个list下的字段, 组成一个list res := make([]string, 0) if len(sourcePathArray[0]) == 0 { f.getAllFinalData(&res, gjson.Parse(f.sourceData).Array(), sourcePathArray[1:]) } else { f.getAllFinalData(&res, gjson.Get(f.sourceData, sourcePathArray[0]).Array(), sourcePathArray[1:]) } if f.formatResult, err = sjson.Set(f.formatResult, mapPathArray[0], res); nil != err { return err } return nil } return nil } // extraFinalResult 提取全部最底层结果 // // Author : zhangdeman001@ke.com<张德满> // // Date : 14:00 2023/1/2 func (f *filter) getAllFinalData(res *[]string, resultList []gjson.Result, pathArr []string) { if len(pathArr) == 1 { for _, item := range resultList { *res = append(*res, item.Get(pathArr[0]).String()) } return } for _, item := range resultList { f.getAllFinalData(res, item.Array(), pathArr[1:]) } return } // String 获取格式化之后的字符串 // // Author : go_developer@163.com<白茶清欢> // // Date : 21:18 2022/12/31 func (f *filter) String() string { return f.formatResult } // Byte 获取格式化之后的字节数组 // // Author : zhangdeman001@ke.com<张德满> // // Date : 21:18 2022/12/31 func (f *filter) Byte() []byte { return []byte(f.String()) } // Parse 解析返回结果 // // Author : go_developer@163.com<白茶清欢> // // Date : 21:20 2022/12/31 func (f *filter) Parse(receiver interface{}) error { if nil == receiver { return errors.New("receiver is nil") } return json.Unmarshal(f.Byte(), receiver) } // getValue 获取值 // // Author : go_developer@163.com<白茶清欢> // // Date : 12:25 2022/7/4 func (f *filter) getValue(dataType consts.DataType, sourceValue gjson.Result, defaultValue string) (any, error) { sourceValueStr := defaultValue if sourceValue.Exists() { str := sourceValue.String() if len(str) > 0 { sourceValueStr = str } } strVal := wrapper.String(sourceValueStr) switch dataType { case consts.DataTypeInt: intVal := strVal.ToInt() return intVal.Value, intVal.Err case consts.DataTypeUint: uintVal := strVal.ToUint64() return uintVal.Value, uintVal.Err case consts.DataTypeBool: boolVal := strVal.ToBool() return boolVal.Value, boolVal.Err case consts.DataTypeFloat: floatVal := strVal.ToFloat64() return floatVal.Value, floatVal.Err case consts.DataTypeString: return strVal.Value(), nil case consts.DataTypeAny: if sourceValue.Exists() { return sourceValue.Value(), nil } return defaultValue, nil case consts.DataTypeSliceAny: // 任意类型的list sliceVal := strVal.ToAnySlice() return sliceVal.Value, sliceVal.Err case consts.DataTypeSliceInt, consts.DataTypeSliceIntWithChar: // 任意类型的list if strings.HasPrefix(strVal.Value(), "[") && strings.HasPrefix(strVal.Value(), "]") { // 序列化之后的数组 sliceVal := strVal.ToInt64Slice() return sliceVal.Value, sliceVal.Err } // 分隔的数组 sliceVal := strVal.ToInt64Slice(",") return sliceVal.Value, sliceVal.Err case consts.DataTypeSliceUint, consts.DataTypeSliceUintWithChar: // 任意类型的list if strings.HasPrefix(strVal.Value(), "[") && strings.HasPrefix(strVal.Value(), "]") { // 序列化之后的数组 sliceVal := strVal.ToUint64Slice() return sliceVal.Value, sliceVal.Err } // 分隔的数组 sliceVal := strVal.ToUint64Slice(",") return sliceVal.Value, sliceVal.Err case consts.DataTypeSliceFloat, consts.DataTypeSliceFloatWithChar: // 任意类型的list if strings.HasPrefix(strVal.Value(), "[") && strings.HasPrefix(strVal.Value(), "]") { // 序列化之后的数组 sliceVal := strVal.ToFloat64Slice() return sliceVal.Value, sliceVal.Err } // 分隔的数组 sliceVal := strVal.ToFloat64Slice(",") return sliceVal.Value, sliceVal.Err case consts.DataTypeSliceBool, consts.DataTypeSliceBoolWithChar: // 任意类型的list if strings.HasPrefix(strVal.Value(), "[") && strings.HasPrefix(strVal.Value(), "]") { // 序列化之后的数组 sliceVal := strVal.ToBoolSlice() return sliceVal.Value, sliceVal.Err } // 分隔的数组 sliceVal := strVal.ToBoolSlice(",") return sliceVal.Value, sliceVal.Err case consts.DataTypeSliceString, consts.DataTypeSliceStringWithChar: // 任意类型的list if strings.HasPrefix(strVal.Value(), "[") && strings.HasPrefix(strVal.Value(), "]") { // 序列化之后的数组 sliceVal := strVal.ToStringSlice() return sliceVal.Value, sliceVal.Err } // 分隔的数组 sliceVal := strVal.ToStringSlice(",") return sliceVal.Value, sliceVal.Err case consts.DataTypeSliceSlice, consts.DataTypeMapAnyAny: return nil, errors.New(consts.DataTypeSliceSlice.String() + " : data type is not support") case consts.DataTypeSliceMapStringAny: if !sourceValue.IsArray() { return nil, errors.New("data type is not array") } var res []map[string]any err := strVal.ToStruct(&res) return res, err case consts.DataTypeMapStrInt: if !sourceValue.IsObject() { return nil, errors.New("data type is not object") } var res map[string]int64 err := strVal.ToStruct(&res) return res, err case consts.DataTypeMapStrUint: if !sourceValue.IsObject() { return nil, errors.New("data type is not object") } var res map[string]uint64 err := strVal.ToStruct(&res) return res, err case consts.DataTypeMapStrFloat: if !sourceValue.IsObject() { return nil, errors.New("data type is not object") } var res map[string]float64 err := strVal.ToStruct(&res) return res, err case consts.DataTypeMapStrBool: if !sourceValue.IsObject() { return nil, errors.New("data type is not object") } var res map[string]bool err := strVal.ToStruct(&res) return res, err case consts.DataTypeMapStrAny: if !sourceValue.IsObject() { return nil, errors.New("data type is not object") } var res map[string]any err := strVal.ToStruct(&res) return res, err case consts.DataTypeMapStrStr: if !sourceValue.IsObject() { return nil, errors.New("data type is not object") } var res map[string]string err := strVal.ToStruct(&res) return res, err case consts.DataTypeMapStrSlice: if !sourceValue.IsObject() { return nil, errors.New("data type is not object") } var res map[string][]any err := strVal.ToStruct(&res) return res, err default: return nil, errors.New(dataType.String() + " is not support!") } }