From 435edb0ea3b7e1a93dc7abc39df436eb06bb481d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Wed, 27 Nov 2024 16:07:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E4=BA=8Egjson=EF=BC=8C=E9=80=92?= =?UTF-8?q?=E5=BD=92=E8=8E=B7=E5=8F=96=E5=85=A8=E9=83=A8key=E7=9A=84?= =?UTF-8?q?=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gjson_hack/define.go | 31 ++++++++++ gjson_hack/path.go | 122 ++++++++++++++++++++++++++++++++++++++++ gjson_hack/path_test.go | 94 +++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 gjson_hack/define.go create mode 100644 gjson_hack/path.go create mode 100644 gjson_hack/path_test.go diff --git a/gjson_hack/define.go b/gjson_hack/define.go new file mode 100644 index 0000000..2c78ff5 --- /dev/null +++ b/gjson_hack/define.go @@ -0,0 +1,31 @@ +// Package gjson_hack ... +// +// Description : gjson_hack ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2024-11-27 11:59 +package gjson_hack + +import "github.com/tidwall/gjson" + +// PathOption 路径操作的选项 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 12:01 2024/11/27 +type PathOption struct { + UnfoldArray bool `json:"unfold_array"` // 展开数组 + MaxDeep int `json:"max_deep"` // 迭代最大深度, 默认 0 不限制 + OnlyFinalPath bool `json:"only_final_path"` // 仅展示最终路径 +} + +// PathResult ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 12:00 2024/11/27 +type PathResult struct { + List []string // 全部路径列表 + ValueTable map[string]gjson.Result // 路径对应的值 +} diff --git a/gjson_hack/path.go b/gjson_hack/path.go new file mode 100644 index 0000000..6d8fab7 --- /dev/null +++ b/gjson_hack/path.go @@ -0,0 +1,122 @@ +// Package gjson_hack ... +// +// Description : gjson_hack ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2024-11-27 11:58 +package gjson_hack + +import ( + "fmt" + "github.com/tidwall/gjson" + "strings" +) + +// newDefaultPathOption 默认路径展开选项 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 12:06 2024/11/27 +func newDefaultPathOption() *PathOption { + return &PathOption{ + UnfoldArray: true, + MaxDeep: 0, + OnlyFinalPath: false, + } +} + +// newPathResult ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 12:17 2024/11/27 +func newPathResult() *PathResult { + return &PathResult{ + List: make([]string, 0), + ValueTable: make(map[string]gjson.Result), + } +} + +// Path 查看全部路径 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 12:03 2024/11/27 +func Path(jsonStr string, pathOption *PathOption) (*PathResult, error) { + gjsonResult := gjson.Parse(jsonStr) + pathResult := newPathResult() + if nil == pathOption { + pathOption = newDefaultPathOption() + } + doExpandPath(gjsonResult, "", true, pathOption, pathResult) + return pathResult, nil +} + +// doExpandPath 展开路径 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 14:57 2024/11/27 +func doExpandPath(gjsonResult gjson.Result, rootPath string, hasChildren bool, pathOption *PathOption, pathResult *PathResult) { + if gjsonResult.IsObject() { + // 处理object + gjsonResult.ForEach(func(key, value gjson.Result) bool { + newRootPath := "" + if len(rootPath) == 0 { + newRootPath = key.String() + } else { + newRootPath = rootPath + "." + key.String() + } + if value.IsArray() || value.IsObject() { + if !pathOption.OnlyFinalPath { + // 中间key路径也存储下来 + pathResult.List = append(pathResult.List, newRootPath) + pathResult.ValueTable[newRootPath] = value + } + doExpandPath(value, newRootPath, true, pathOption, pathResult) + } else { + pathResult.List = append(pathResult.List, newRootPath) + pathResult.ValueTable[newRootPath] = value + } + return true + }) + } + if gjsonResult.IsArray() { + arrayList := gjsonResult.Array() + if len(arrayList) == 0 { + pathResult.List = append(pathResult.List, rootPath) + pathResult.ValueTable[rootPath] = gjsonResult + return + } + if arrayList[0].IsObject() || arrayList[0].IsArray() { + // 每一项是对象或者数组 + if pathOption.UnfoldArray { + // 展开数组 + for idx, itemRes := range arrayList { + doExpandPath(itemRes, rootPath+"."+fmt.Sprintf("%v", idx), true, pathOption, pathResult) + } + } else { + // 不展开数组 + doExpandPath(arrayList[0], rootPath+".#", true, pathOption, pathResult) + } + } else { + // 每一项是基础类型 + pathResult.List = append(pathResult.List, rootPath) + pathResult.ValueTable[rootPath] = gjsonResult + return + } + } + if strings.HasSuffix(rootPath, ".#") { + // 处理不展开类型数组 + return + } + if pathOption.OnlyFinalPath && hasChildren { + return + } + if _, exist := pathResult.ValueTable[rootPath]; !exist { + pathResult.List = append(pathResult.List, rootPath) + pathResult.ValueTable[rootPath] = gjsonResult + } + return +} diff --git a/gjson_hack/path_test.go b/gjson_hack/path_test.go new file mode 100644 index 0000000..d1211bf --- /dev/null +++ b/gjson_hack/path_test.go @@ -0,0 +1,94 @@ +// Package gjson_hack ... +// +// Description : gjson_hack ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2024-11-27 15:52 +package gjson_hack + +import ( + "encoding/json" + "fmt" + "testing" +) + +func TestPath(t *testing.T) { + mapData := map[string]any{ + "person_list": []map[string]any{ + {"name": "zhang", "age": 10}, + {"name": "li", "age": 20}, + {"name": "wang", "age": 30}, + }, + "company_info": map[string]any{ + "address": "Beijing", + "email": "xxx@xxx.com", + }, + "sex": "man", + } + byteData, _ := json.Marshal(mapData) + pathRes, err := Path(string(byteData), nil) + if nil != err { + fmt.Println(err.Error()) + } else { + for _, item := range pathRes.List { + fmt.Println(item) + } + } +} + +func TestPathOnlyFinallyPath(t *testing.T) { + mapData := map[string]any{ + "person_list": []map[string]any{ + {"name": "zhang", "age": 10}, + {"name": "li", "age": 20}, + {"name": "wang", "age": 30}, + }, + "company_info": map[string]any{ + "address": "Beijing", + "email": "xxx@xxx.com", + }, + "sex": "man", + } + byteData, _ := json.Marshal(mapData) + pathRes, err := Path(string(byteData), &PathOption{ + UnfoldArray: false, + MaxDeep: 0, + OnlyFinalPath: true, + }) + if nil != err { + fmt.Println(err.Error()) + } else { + for _, item := range pathRes.List { + fmt.Println(item) + } + } +} + +func TestPathOnlyFinallyPathWithUnfoldArray(t *testing.T) { + mapData := map[string]any{ + "person_list": []map[string]any{ + {"name": "zhang", "age": 10}, + {"name": "li", "age": 20}, + {"name": "wang", "age": 30}, + }, + "company_info": map[string]any{ + "address": "Beijing", + "email": "xxx@xxx.com", + }, + "sex": "man", + } + byteData, _ := json.Marshal(mapData) + pathRes, err := Path(string(byteData), &PathOption{ + UnfoldArray: true, + MaxDeep: 0, + OnlyFinalPath: false, + }) + if nil != err { + fmt.Println(err.Error()) + } else { + for _, item := range pathRes.List { + fmt.Println(item) + } + } +}