diff --git a/tool/gabs.go b/tool/gabs.go index 52d6736..1107a0c 100644 --- a/tool/gabs.go +++ b/tool/gabs.go @@ -19,6 +19,11 @@ import ( "github.com/tidwall/sjson" ) +const ( + // virtualRoot 虚拟根节点 + virtualRoot = "__VIRTUAL_ROOT__" +) + // FilterOption 过滤选项 // // Author : go_developer@163.com<白茶清欢> @@ -54,17 +59,36 @@ func NewDataFilter(source string, filterRule []*FilterDataRule, filterOption *Fi filterOption.LogInstance = os.Stdout log.SetOutput(filterOption.LogInstance) } + df := &DataFilter{ + source: source, + filterRule: make([]*FilterDataRule, 0), + rewriteResult: "{}", + filterOption: filterOption, + } // 去除末尾的 .[] for _, item := range filterRule { item.MapKey = strings.TrimRight(item.MapKey, ".[]") item.SourceKey = strings.TrimRight(item.SourceKey, ".[]") + mapIsArr := df.isArrPath(item.MapKey) + if !mapIsArr { + df.filterRule = append(df.filterRule, item) + continue + } + if len(df.getArrPathList(item.SourceKey)) < len(df.getArrPathList(item.MapKey)) { + panic("map result deep more than source data deep") + } + formatRes := make([]*FilterDataRule, 0) + r, _ := df.unfoldSameDeepArr(item.SourceKey, item.MapKey, "", "") + for _, itemUnfoldResult := range r { + itemMapArr := strings.Split(itemUnfoldResult.MapKey, ".") + if len(itemMapArr) != len(strings.Split(item.MapKey, ".")) { + continue + } + formatRes = append(formatRes, itemUnfoldResult) + } + df.filterRule = append(df.filterRule, formatRes...) } - return &DataFilter{ - source: source, - filterRule: filterRule, - rewriteResult: "{}", - filterOption: filterOption, - } + return df } // DataFilter 数据过滤 @@ -120,8 +144,8 @@ func (df *DataFilter) Filter() (string, error) { // 数组深度一致 continue } - } + df.logPrint(logLevelDebug, "过滤结果", df.rewriteResult) return df.rewriteResult, nil } @@ -134,22 +158,72 @@ func (df *DataFilter) isArrPath(path string) bool { return strings.Contains(path, "[]") } -// setSameDeepArr 设置同深度的数组 +// setSameDeepArr 展开同深度数组的 // // Author : go_developer@163.com<白茶清欢> // // Date : 12:19 2023/9/2 -func (df *DataFilter) setSameDeepArr(sourceVal string, sourcePath string, mapPath string) error { +func (df *DataFilter) unfoldSameDeepArr(sourcePath string, mapPath string, sourceRootPath string, mapRootPath string) ([]*FilterDataRule, error) { + df.logPrint(logLevelDebug, " 同深数组展开", sourceRootPath, mapRootPath) + result := make([]*FilterDataRule, 0) + if len(sourcePath) == 0 { + return result, nil + } sourcePathArr := df.getArrPathList(sourcePath) mapPathArr := df.getArrPathList(mapPath) - for idx, itemSourcePath := range sourcePathArr { - sourceValueArr := gjson.Get(sourceVal, sourcePath).Array() + if 1 == len(mapPathArr) { + sourceKey := sourceRootPath + "." + sourcePathArr[0] + if len(sourcePathArr[0:]) > 0 { + sourceKey = sourceRootPath + "." + strings.Join(sourcePathArr[0:], ".[].") + } + result = append(result, &FilterDataRule{ + SourceKey: sourceKey, + MapKey: mapRootPath + "." + mapPathArr[0], + DefaultValue: nil, + WithDefault: false, + }) + return result, nil } - return nil + // 数组 展开 + for idx := 0; idx < len(mapPathArr); idx++ { + if len(sourceRootPath) > 0 { + sourceRootPath = fmt.Sprintf("%v.%v", sourceRootPath, sourcePathArr[idx]) + } else { + sourceRootPath = sourcePathArr[idx] + } + if len(mapRootPath) > 0 { + mapRootPath = fmt.Sprintf("%v.%v", mapRootPath, mapPathArr[idx]) + } else { + mapRootPath = mapPathArr[idx] + } + valList := gjson.Get(df.source, sourceRootPath) + if valList.Value() == nil { + continue + } + for i := 0; i < len(valList.Array()); i++ { + result = append(result, &FilterDataRule{ + SourceKey: sourceRootPath, + MapKey: mapRootPath, + DefaultValue: nil, + WithDefault: false, + }) + r, e := df.unfoldSameDeepArr( + strings.Join(sourcePathArr[idx+1:], "[]"), + strings.Join(mapPathArr[idx+1:], "[]"), + fmt.Sprintf("%v.%v", sourceRootPath, i), + fmt.Sprintf("%v.%v", mapRootPath, i), + ) + if nil != e { + return nil, e + } + result = append(result, r...) + } + } + return result, nil } // a.[].b.[].c.[].d -// e.[].f.[].g +// g // getDataAsSlice 抽取制定深度,生成list // // Author : go_developer@163.com<白茶清欢> diff --git a/tool/gabs_test.go b/tool/gabs_test.go index 0953156..f37f1c6 100644 --- a/tool/gabs_test.go +++ b/tool/gabs_test.go @@ -10,6 +10,7 @@ package json_tool import ( "encoding/json" "fmt" + "strings" "testing" "git.zhangdeman.cn/zhangdeman/serialize" @@ -140,3 +141,145 @@ func TestDataFilter_sourceArrAndMapSingle(t *testing.T) { } fmt.Println(df.Filter()) } + +// TestDataFilter_unfoldSameDeepArr 测试展开同深度数组 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 15:42 2023/9/2 +func TestDataFilter_unfoldSameDeepArr(t *testing.T) { + source := map[string]interface{}{ + "list": []interface{}{ + map[string]interface{}{ + "name": "1", + "age": "2", + "list_test": []interface{}{ + map[string]interface{}{ + "a": "a", + "b": "b", + "c": map[string]interface{}{ + "a": "1", + }, + "d": []int{1, 2, 3}, + }, + }, + }, + map[string]interface{}{ + "name": "3", + "age": "4", + "list_test": []interface{}{ + map[string]interface{}{ + "a": "a1", + "b": "b1", + "c": map[string]interface{}{ + "a": "a", + }, + "d": []int{1, 2, 3}, + }, + map[string]interface{}{ + "a": "a2", + "b": "b1", + "c": map[string]interface{}{ + "a": "a", + }, + "d": []int{1, 2, 3}, + }, + }, + }, + map[string]interface{}{ + "name": "5", + "age": "6", + }, + }, + } + df := &DataFilter{ + source: serialize.JSON.MarshalForString(source), + filterRule: []*FilterDataRule{ + {SourceKey: "list.[].list_test.[].a", MapKey: "a_list.[].a.[].val", DefaultValue: "[]", WithDefault: true}, + {SourceKey: "list.[].list_test.[].b", MapKey: "b_list.[].b.[].val", DefaultValue: "[]", WithDefault: true}, + {SourceKey: "list.[].list_test.[].c", MapKey: "c_list.[].c.[].val", DefaultValue: "[]", WithDefault: true}, + {SourceKey: "list.[].list_test.[].d", MapKey: "d_list.[].d.[].val", DefaultValue: "[]", WithDefault: true}, + }, + filterOption: &FilterOption{DebugModel: true}, + } + r, _ := df.unfoldSameDeepArr("list.[].list_test.[].a", "a_list.[].a_not_equal_list", "", "") + + formatRes := make([]*FilterDataRule, 0) + for _, item := range r { + itemMapArr := strings.Split(item.MapKey, ".") + if len(itemMapArr) != 3 && len(itemMapArr) != 5 { + continue + } + formatRes = append(formatRes, item) + } + fmt.Println(serialize.JSON.MarshalForString(formatRes)) +} + +// TestDataFilter_filterSameDeepArr ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 20:41 2023/9/2 +func TestDataFilter_filterSameDeepArr(t *testing.T) { + source := map[string]interface{}{ + "list": []interface{}{ + map[string]interface{}{ + "name": "1", + "age": "2", + "list_test": []interface{}{ + map[string]interface{}{ + "a": "a", + "b": "b", + "c": map[string]interface{}{ + "a": "1", + }, + "d": []int{1, 2, 3}, + }, + }, + }, + map[string]interface{}{ + "name": "3", + "age": "4", + "list_test": []interface{}{ + map[string]interface{}{ + "a": "a1", + "b": "b1", + "c": map[string]interface{}{ + "a": "a", + }, + "d": []int{1, 2, 3}, + }, + map[string]interface{}{ + "a": "a2", + "b": "b1", + "c": map[string]interface{}{ + "a": "a", + }, + "d": []int{1, 2, 3}, + }, + }, + }, + map[string]interface{}{ + "name": "5", + "age": "6", + }, + }, + } + filterRuleList := []*FilterDataRule{ + {SourceKey: "name", MapKey: "user_name", DefaultValue: "油猴", WithDefault: true}, + {SourceKey: "extra.age", MapKey: "user_age", DefaultValue: "18", WithDefault: true}, + {SourceKey: "slice", MapKey: "user_index", DefaultValue: "[4,5,6]", WithDefault: true}, + {SourceKey: "none", MapKey: "none_default", DefaultValue: map[string]interface{}{"a": "a"}, WithDefault: true}, + {SourceKey: "extra", MapKey: "extra_object", DefaultValue: map[string]interface{}{"a": "a"}, WithDefault: true}, + {SourceKey: "list.[].list_test.[].a", MapKey: "a_list.[].a.[].val", DefaultValue: "[]", WithDefault: true}, + {SourceKey: "list.[].list_test.[].a", MapKey: "a_list.[].a_not_equal_list", DefaultValue: "[]", WithDefault: true}, + {SourceKey: "list.[].list_test.[].a", MapKey: "a_list.[].a.[].val1", DefaultValue: "[]", WithDefault: true}, + {SourceKey: "list.[].list_test.[].b", MapKey: "b_list.[].b.[].val", DefaultValue: "[]", WithDefault: true}, + {SourceKey: "list.[].list_test.[].c", MapKey: "c_list.[].c.[].val", DefaultValue: "[]", WithDefault: true}, + {SourceKey: "list.[].list_test.[].d", MapKey: "d_list.[].d.[].val", DefaultValue: "[]", WithDefault: true}, + } + filterOption := &FilterOption{DebugModel: true} + + df := NewDataFilter(serialize.JSON.MarshalForString(source), filterRuleList, filterOption) + _, _ = df.Filter() +}