diff --git a/abstract/json_read.go b/abstract/json_read.go new file mode 100644 index 0000000..e9c07a8 --- /dev/null +++ b/abstract/json_read.go @@ -0,0 +1,36 @@ +// Package abstract ... +// +// Description : abstract ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-05-06 10:42 +package abstract + +// IJsonRead json数据读取接口约束 +type IJsonRead interface { + // Exist 指定路径是否存在 + Exist(dataPath string) bool + // IsNil 指定路径是否为nil + IsNil(dataPath string) bool + // Type 路径数据类型 + Type(dataPath string) string + // Int 转换为int类型 + Int(dataPath string) (int64, error) + // Uint 转换为uint类型 + Uint(dataPath string) (uint64, error) + // Float 转换为float类型 + Float(dataPath string) (float64, error) + // String 转换为string类型 + String(dataPath string) (string, error) + // Map 转换为map + Map(dataPath string) (map[string]any, error) + // MapWithReceiver 通过指针接收 + MapWithReceiver(dataPath string, receiver any) error + // Array 转换为数组 + Array(dataPath string) ([]any, error) + // ArrayWithReceiver 通过指针接收 + ArrayWithReceiver(dataPath string, receiver any) error + // Value 自适应类型数据读取 + Value(dataPath string, dataType string, defaultValue any) (any, error) +} diff --git a/abstract/json_write.go b/abstract/json_write.go new file mode 100644 index 0000000..3706c9e --- /dev/null +++ b/abstract/json_write.go @@ -0,0 +1,24 @@ +// Package abstract ... +// +// Description : abstract ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-05-06 10:53 +package abstract + +// IJsonWrite json数据写入 +type IJsonWrite interface { + // Set 设置一个路径的值 + Set(dataPath string, data any) error + // Result 最终结果以字符串形式返回 + Result() string + // Map 最终结果以map返回 + Map() (map[string]any, error) + // MapWithReceiver 外部指针接收返回值 + MapWithReceiver(receiver any) error + // Array 最终结果以数组返回 + Array() ([]any, error) + // ArrayWithReceiver 外部指针接收返回值 + ArrayWithReceiver(receiver any) error +} diff --git a/filter.go b/filter.go index 07233ec..58ba091 100644 --- a/filter.go +++ b/filter.go @@ -8,19 +8,31 @@ package filter import ( - "encoding/json" "fmt" - "reflect" + "git.zhangdeman.cn/zhangdeman/json_filter/abstract" + "git.zhangdeman.cn/zhangdeman/json_filter/implement" "strings" - "git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack" - "git.zhangdeman.cn/zhangdeman/serialize" - "github.com/tidwall/gjson" - "github.com/tidwall/sjson" - "errors" + "git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack" + "github.com/tidwall/gjson" ) +func NewFilterWithJson(sourceData string, filterRuleList []MapRule, jsonRead abstract.IJsonRead, jsonWrite abstract.IJsonWrite) *filter { + if nil == jsonRead { + jsonRead = implement.NewGjsonRead(sourceData) + } + if nil == jsonWrite { + jsonWrite = implement.NewSjsonWrite() + } + return &filter{ + jsonRaad: jsonRead, + jsonWrite: jsonWrite, + sourceData: sourceData, + filterRuleList: filterRuleList, + } +} + // NewFilter 过滤器实例 // // Author : go_developer@163.com<白茶清欢> @@ -29,7 +41,8 @@ import ( func NewFilter(sourceData string, filterRuleList []MapRule) *filter { return &filter{ sourceData: sourceData, - formatResult: "{}", + jsonRaad: implement.NewGjsonRead(sourceData), + jsonWrite: implement.NewSjsonWrite(), filterRuleList: filterRuleList, } } @@ -40,8 +53,9 @@ func NewFilter(sourceData string, filterRuleList []MapRule) *filter { // // Date : 11:58 2022/7/4 type filter struct { + jsonRaad abstract.IJsonRead + jsonWrite abstract.IJsonWrite sourceData string - formatResult string filterRuleList []MapRule } @@ -126,33 +140,10 @@ func (f *filter) setResult(rule MapRule) error { err error formatVal any ) - - sourceResult := gjson.Get(f.sourceData, rule.SourcePath) - if formatVal, err = gjson_hack.Value(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 formatVal, err = f.jsonRaad.Value(rule.SourcePath, rule.DataType.String(), rule.DefaultValue); nil != err { + return fmt.Errorf("%s = %v can not convert to %s : %s", rule.SourcePath, gjson.Get(f.sourceData, rule.SourcePath).String(), 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 { + if err = f.jsonWrite.Set(rule.TargetPath, formatVal); nil != err { return err } return nil @@ -182,7 +173,7 @@ func (f *filter) getAllFinalData(res *[]string, resultList []gjson.Result, pathA // // Date : 21:18 2022/12/31 func (f *filter) String() string { - return f.formatResult + return f.jsonWrite.Result() } // Byte 获取格式化之后的字节数组 @@ -199,9 +190,10 @@ func (f *filter) Byte() []byte { // Author : go_developer@163.com<白茶清欢> // // Date : 21:20 2022/12/31 -func (f *filter) Parse(receiver interface{}) error { +func (f *filter) Parse(receiver any) error { if nil == receiver { return errors.New("receiver is nil") } - return json.Unmarshal(f.Byte(), receiver) + return f.jsonWrite.MapWithReceiver(receiver) + // return json.Unmarshal(f.Byte(), receiver) } diff --git a/implement/gjson_read.go b/implement/gjson_read.go new file mode 100644 index 0000000..9ba9eb9 --- /dev/null +++ b/implement/gjson_read.go @@ -0,0 +1,126 @@ +// Package implement ... +// +// Description : implement ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-05-06 11:00 +package implement + +import ( + "errors" + "git.zhangdeman.cn/zhangdeman/consts" + "git.zhangdeman.cn/zhangdeman/json_filter/abstract" + "git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack" + "git.zhangdeman.cn/zhangdeman/serialize" + "github.com/tidwall/gjson" +) + +// NewGjsonRead ... +func NewGjsonRead(sourceData string) abstract.IJsonRead { + return &gjsonRead{ + sourceData: sourceData, + gjsonResult: gjson.Parse(sourceData), + } +} + +type gjsonRead struct { + sourceData string + gjsonResult gjson.Result +} + +func (g *gjsonRead) Exist(dataPath string) bool { + return g.gjsonResult.Get(dataPath).Exists() +} + +func (g *gjsonRead) IsNil(dataPath string) bool { + return g.gjsonResult.Get(dataPath).Value() == nil +} + +func (g *gjsonRead) Type(dataPath string) string { + pathRes := g.gjsonResult.Get(dataPath) + if pathRes.IsObject() { // map + return consts.DataTypeMapStrAny.String() + } + if pathRes.IsArray() { // slice + return consts.DataTypeSliceAny.String() + } + if pathRes.IsBool() { // bool + return consts.DataTypeBool.String() + } + dataType := pathRes.Type + switch dataType { + case gjson.String: + return consts.DataTypeString.String() + case gjson.Number: + return consts.DataTypeFloat64.String() + case gjson.Null: + return consts.DataTypeAny.String() + case gjson.True, gjson.False: + return consts.DataTypeBool.String() + } + return consts.DataTypeAny.String() // any类型兜底 +} + +func (g *gjsonRead) Int(dataPath string) (int64, error) { + return gjson_hack.Int(g.gjsonResult.Get(dataPath)) +} + +func (g *gjsonRead) Uint(dataPath string) (uint64, error) { + return gjson_hack.Uint(g.gjsonResult.Get(dataPath)) +} + +func (g *gjsonRead) Float(dataPath string) (float64, error) { + return gjson_hack.Float64(g.gjsonResult.Get(dataPath)) +} + +func (g *gjsonRead) String(dataPath string) (string, error) { + if !g.Exist(dataPath) { + return "", errors.New(dataPath + ": not found") + } + return g.gjsonResult.Get(dataPath).String(), nil +} + +func (g *gjsonRead) Map(dataPath string) (map[string]any, error) { + var ( + err error + dataMap map[string]any + ) + if err = g.MapWithReceiver(dataPath, &dataMap); nil != err { + return map[string]any{}, err + } + return dataMap, nil +} + +func (g *gjsonRead) MapWithReceiver(dataPath string, receiver any) error { + strVal, err := g.String(dataPath) + if nil != err { + return err + } + return serialize.JSON.UnmarshalWithNumber([]byte(strVal), receiver) +} + +func (g *gjsonRead) Array(dataPath string) ([]any, error) { + var ( + err error + dataArr []any + ) + if err = g.ArrayWithReceiver(dataPath, &dataArr); nil != err { + return []any{}, err + } + return dataArr, nil +} + +func (g *gjsonRead) ArrayWithReceiver(dataPath string, receiver any) error { + strVal, err := g.String(dataPath) + if nil != err { + return err + } + return serialize.JSON.UnmarshalWithNumber([]byte(strVal), receiver) +} +func (g *gjsonRead) Value(dataPath string, dataType string, defaultValue any) (any, error) { + if len(dataType) == 0 { + dataType = g.Type(dataPath) + } + return gjson_hack.Value(consts.DataType(dataType), g.gjsonResult.Get(dataPath), defaultValue) +} diff --git a/implement/sjson_write.go b/implement/sjson_write.go new file mode 100644 index 0000000..01e3ef4 --- /dev/null +++ b/implement/sjson_write.go @@ -0,0 +1,114 @@ +// Package implement ... +// +// Description : implement ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-05-06 11:53 +package implement + +import ( + "git.zhangdeman.cn/zhangdeman/consts" + "git.zhangdeman.cn/zhangdeman/json_filter/abstract" + "git.zhangdeman.cn/zhangdeman/serialize" + "github.com/tidwall/sjson" + "reflect" + "sync" +) + +func NewSjsonWrite() abstract.IJsonWrite { + return &SjsonWrite{ + res: "", + l: &sync.RWMutex{}, + } +} + +type SjsonWrite struct { + res string + l *sync.RWMutex +} + +func (s *SjsonWrite) Set(dataPath string, data any) error { + var ( + err error + ) + + s.l.Lock() + defer s.l.Unlock() + existResRead := NewGjsonRead(s.res) + if !existResRead.Exist(dataPath) || data == nil { + // 路径不存在 + if s.res, err = sjson.Set(s.res, dataPath, data); nil != err { + return err + } + return nil + } + // 路径已存在, 判断是否为map + if existResRead.Type(dataPath) != consts.DataTypeMapStrAny.String() { + if s.res, err = sjson.Set(s.res, dataPath, data); nil != err { + return err + } + return nil + } + // 判断data是否为map + dataType := reflect.TypeOf(data) + if dataType.Kind() == reflect.Ptr { + dataType = dataType.Elem() + } + if dataType.Kind() != reflect.Struct && dataType.Kind() != reflect.Map { + // 既不是map, 也不是struct + if s.res, err = sjson.Set(s.res, dataPath, data); nil != err { + return err + } + return nil + } + // 路径已存在, 已存在数据为map, 且要设置的数据也为map, 进行数据合并 + mergeDataMap := map[string]any{} + existMapVal := map[string]any{} + + if existMapVal, err = existResRead.Map(dataPath); nil != err { + return err + } + // 合并输入数据 + if err = serialize.JSON.MergeDataForReceiver(&mergeDataMap, existMapVal, data); nil != err { + return err + } + if s.res, err = sjson.Set(s.res, dataPath, mergeDataMap); nil != err { + return err + } + return nil +} + +func (s *SjsonWrite) Result() string { + return s.res +} + +func (s *SjsonWrite) Map() (map[string]any, error) { + var ( + mapRes map[string]any + err error + ) + if err = s.MapWithReceiver(&mapRes); nil != err { + return nil, err + } + return mapRes, nil +} + +func (s *SjsonWrite) MapWithReceiver(receiver any) error { + return serialize.JSON.UnmarshalWithNumberForString(s.res, receiver) +} + +func (s *SjsonWrite) Array() ([]any, error) { + var ( + arrRes []any + err error + ) + if err = s.ArrayWithReceiver(&arrRes); nil != err { + return nil, err + } + return arrRes, nil +} + +func (s *SjsonWrite) ArrayWithReceiver(receiver any) error { + return serialize.JSON.UnmarshalWithNumberForString(s.res, receiver) +} diff --git a/sjson_hack/set.go b/sjson_hack/set.go index 809fb11..91693a5 100644 --- a/sjson_hack/set.go +++ b/sjson_hack/set.go @@ -9,7 +9,6 @@ package sjson_hack import ( "errors" - "fmt" "git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack" "git.zhangdeman.cn/zhangdeman/wrapper" "github.com/tidwall/sjson" @@ -27,7 +26,6 @@ var ( // // Date : 11:36 2024/12/3 func Set(jsonRes string, path string, value any) (string, error) { - fmt.Println(jsonRes, value) var ( err error res string = jsonRes