基于gjson,递归获取全部key的路径
This commit is contained in:
parent
d115e1c5ba
commit
435edb0ea3
31
gjson_hack/define.go
Normal file
31
gjson_hack/define.go
Normal file
@ -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 // 路径对应的值
|
||||
}
|
122
gjson_hack/path.go
Normal file
122
gjson_hack/path.go
Normal file
@ -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
|
||||
}
|
94
gjson_hack/path_test.go
Normal file
94
gjson_hack/path_test.go
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user