Compare commits
86 Commits
a83ef6a1b2
...
master
Author | SHA1 | Date | |
---|---|---|---|
2e1ece4c82 | |||
dfae2fda76 | |||
80e62625f2 | |||
b0db389ca3 | |||
a0c2fb37e3 | |||
c403047e9f | |||
777a5cb93c | |||
691bee91a5 | |||
c7ce590e3b | |||
6c2c68c53e | |||
38b2d74f35 | |||
a28bc364e4 | |||
47726c20b8 | |||
042aad254b | |||
1124ff6a33 | |||
8489acbef8 | |||
761058f8fe | |||
587a9bbe9d | |||
50a8474e4d | |||
28fbd1e820 | |||
bbe5eb089f | |||
786c03293a | |||
b8c8c9d433 | |||
96ff376470 | |||
f61f9b28b1 | |||
f88826411f | |||
df6e554d03 | |||
48639ba59a | |||
355144b623 | |||
ee2326af91 | |||
5b509aaee7 | |||
5fc2e0a613 | |||
7214767a90 | |||
4a318f3638 | |||
d25e579ecf | |||
5ae1841023 | |||
d466b7526d | |||
c10486b403 | |||
8cca556d6f | |||
68d3d76062 | |||
ce1e7fe9da | |||
c1775552cc | |||
0ca808c4fb | |||
cb23772664 | |||
be69c71d4a | |||
7743ee14ce | |||
69066c35c2 | |||
33815072ea | |||
435edb0ea3 | |||
d115e1c5ba | |||
fd1f3367ed | |||
fcf1a7fbd4 | |||
44de8814d8 | |||
31af48e926 | |||
eba6a67875 | |||
3107ca239f | |||
0e4fabcaee | |||
d5db651282 | |||
b6a27fffd5 | |||
cd52bbb02b | |||
45b7aea925 | |||
60c8893537 | |||
00a7b0a47a | |||
3b77b6fbd8 | |||
024f35ac67 | |||
2230411f76 | |||
f3baa17bd5 | |||
2634c53b79 | |||
34913edf28 | |||
e79ac95858 | |||
bae9380210 | |||
8fd5b54a0c | |||
e6c97685e7 | |||
f802550a49 | |||
48f3d80275 | |||
435b339604 | |||
1cdf5449fd | |||
81f9c552dd | |||
78b3ae43e5 | |||
4bf4d84db4 | |||
f87b2d08c2 | |||
988acc124b | |||
7004fb4808 | |||
ca6ced064e | |||
70a1fe7c06 | |||
4be118d7c6 |
38
abstract/json_read.go
Normal file
38
abstract/json_read.go
Normal file
@ -0,0 +1,38 @@
|
||||
// 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)
|
||||
// Bool 转换为bool类型
|
||||
Bool(dataPath string) (bool, 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)
|
||||
}
|
26
abstract/json_write.go
Normal file
26
abstract/json_write.go
Normal file
@ -0,0 +1,26 @@
|
||||
// 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
|
||||
// Delete 删除一个路径
|
||||
Delete(dataPath string) 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
|
||||
}
|
14
define.go
14
define.go
@ -7,15 +7,19 @@
|
||||
// Date : 2022-07-04 18:02
|
||||
package filter
|
||||
|
||||
import (
|
||||
"git.zhangdeman.cn/zhangdeman/consts"
|
||||
)
|
||||
|
||||
// MapRule 映射规则
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:21 2022/7/4
|
||||
type MapRule struct {
|
||||
SourcePath string `json:"source_path"` // 原路径
|
||||
MapPath string `json:"map_path"` // 映射路径
|
||||
Required bool `json:"required"` // 必须存在
|
||||
DataType string `json:"data_type"` // 数据类型
|
||||
DefaultValue string `json:"default_value"` // 默认值, 以字符串传入, 会转换成 DataType
|
||||
SourcePath string `json:"source_path"` // 原路径
|
||||
TargetPath string `json:"target_path"` // 目标路径路径
|
||||
Required bool `json:"required"` // 必须存在
|
||||
DataType consts.DataType `json:"data_type"` // 数据类型
|
||||
DefaultValue string `json:"default_value"` // 默认值, 以字符串传入, 会转换成 DataType
|
||||
}
|
||||
|
171
filter.go
171
filter.go
@ -8,17 +8,31 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"git.zhangdeman.cn/zhangdeman/json_filter/abstract"
|
||||
"git.zhangdeman.cn/zhangdeman/json_filter/implement"
|
||||
"strings"
|
||||
|
||||
"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<白茶清欢>
|
||||
@ -27,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,
|
||||
}
|
||||
}
|
||||
@ -38,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
|
||||
}
|
||||
|
||||
@ -50,23 +66,22 @@ type filter struct {
|
||||
// Date : 11:59 2022/7/4
|
||||
func (f *filter) Deal() error {
|
||||
var (
|
||||
err error
|
||||
formatVal interface{}
|
||||
err error
|
||||
)
|
||||
|
||||
for _, rule := range f.filterRuleList {
|
||||
if len(rule.TargetPath) == 0 {
|
||||
// 未配置目标路径则, 目标路径和源路径保持一致
|
||||
rule.TargetPath = rule.SourcePath
|
||||
}
|
||||
if f.IsArray(rule) {
|
||||
// 对于list的处理
|
||||
// 对于list的处理, 展开层级, 并自动追加到f.filterRuleList 后面
|
||||
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 f.formatResult, err = sjson.Set(f.formatResult, rule.MapPath, formatVal); nil != err {
|
||||
if err = f.setResult(rule); nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -79,7 +94,7 @@ func (f *filter) Deal() error {
|
||||
//
|
||||
// Date : 17:48 2023/1/1
|
||||
func (f *filter) IsArray(rule MapRule) bool {
|
||||
return strings.Contains(rule.SourcePath, "[]")
|
||||
return strings.Contains(rule.SourcePath, gjson_hack.ArrayIdxTpl)
|
||||
}
|
||||
|
||||
// handleArray 处理数组(最复杂的场景)
|
||||
@ -88,33 +103,48 @@ func (f *filter) IsArray(rule MapRule) bool {
|
||||
//
|
||||
// Date : 17:41 2023/1/1
|
||||
func (f *filter) handleArray(rule MapRule) error {
|
||||
// 对于list的处理, 展开层级, 并自动追加到f.filterRuleList 后面
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
sourcePathArray := strings.Split(rule.SourcePath, "[]")
|
||||
for idx, item := range sourcePathArray {
|
||||
sourcePathArray[idx] = strings.Trim(item, ".")
|
||||
expendRes := &gjson_hack.ExpendArrayResult{
|
||||
PathList: make([]string, 0),
|
||||
PathMap: map[string]string{},
|
||||
}
|
||||
mapPathArray := strings.Split(strings.TrimRight(rule.MapPath, ".[]"), "[]")
|
||||
for idx, item := range mapPathArray {
|
||||
mapPathArray[idx] = strings.Trim(item, ".")
|
||||
if err = gjson_hack.ExpandArrayPath(f.sourceData, rule.SourcePath, rule.TargetPath, expendRes); nil != err {
|
||||
return err
|
||||
}
|
||||
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 {
|
||||
for _, itemPath := range expendRes.PathList {
|
||||
if err = f.setResult(MapRule{
|
||||
SourcePath: itemPath,
|
||||
TargetPath: expendRes.PathMap[itemPath],
|
||||
Required: rule.Required,
|
||||
DataType: rule.DataType,
|
||||
DefaultValue: rule.DefaultValue,
|
||||
}); nil != err {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setResult 设置结果
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 19:03 2024/11/30
|
||||
func (f *filter) setResult(rule MapRule) error {
|
||||
var (
|
||||
err error
|
||||
formatVal any
|
||||
)
|
||||
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 err = f.jsonWrite.Set(rule.TargetPath, formatVal); nil != err {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -143,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 获取格式化之后的字节数组
|
||||
@ -160,73 +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)
|
||||
}
|
||||
|
||||
// getValue 获取值
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:25 2022/7/4
|
||||
func (f *filter) getValue(dataType string, sourceValue gjson.Result, defaultValue string) (interface{}, error) {
|
||||
sourceValueStr := defaultValue
|
||||
if sourceValue.Exists() {
|
||||
str := sourceValue.String()
|
||||
if len(str) > 0 {
|
||||
sourceValueStr = str
|
||||
}
|
||||
}
|
||||
|
||||
strVal := wrapper.String(sourceValueStr)
|
||||
|
||||
switch dataType {
|
||||
case wrapper.DataTypeInt8:
|
||||
return strVal.ToInt8()
|
||||
case wrapper.DataTypeInt16:
|
||||
return strVal.ToInt16()
|
||||
case wrapper.DataTypeInt32:
|
||||
return strVal.ToInt32()
|
||||
case wrapper.DataTypeInt64:
|
||||
return strVal.ToInt64()
|
||||
case wrapper.DataTypeInt:
|
||||
return strVal.ToInt()
|
||||
case wrapper.DataTypeUint8:
|
||||
return strVal.ToUint8()
|
||||
case wrapper.DataTypeUint16:
|
||||
return strVal.ToUint16()
|
||||
case wrapper.DataTypeUint32:
|
||||
return strVal.ToUint32()
|
||||
case wrapper.DataTypeUint64:
|
||||
return strVal.ToUint64()
|
||||
case wrapper.DataTypeUint:
|
||||
return strVal.ToUint()
|
||||
case wrapper.DataTypeBool:
|
||||
return strVal.ToBool()
|
||||
case wrapper.DataTypeFloat32:
|
||||
return strVal.ToFloat64()
|
||||
case wrapper.DataTypeFloat64:
|
||||
fallthrough
|
||||
case wrapper.DataTypeFloat:
|
||||
fallthrough
|
||||
case wrapper.DataTypeDouble:
|
||||
return strVal.ToFloat64()
|
||||
case wrapper.DataTypeNumber:
|
||||
return strVal.ToNumber()
|
||||
case wrapper.DataTypeString:
|
||||
return sourceValueStr, nil
|
||||
case wrapper.DataTypeAny:
|
||||
return sourceValue.Value(), nil
|
||||
case wrapper.DataTypeAnySlice:
|
||||
// 任意类型的list
|
||||
return strVal.ToAnySlice()
|
||||
case wrapper.DataTypeObject:
|
||||
// object
|
||||
return strVal.ToObject()
|
||||
default:
|
||||
return nil, errors.New(dataType + " is not support!")
|
||||
}
|
||||
return f.jsonWrite.MapWithReceiver(receiver)
|
||||
// return json.Unmarshal(f.Byte(), receiver)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
@ -37,35 +38,35 @@ func TestNewFilter(t *testing.T) {
|
||||
filterRuleList := []MapRule{
|
||||
{
|
||||
SourcePath: "base.name",
|
||||
MapPath: "user_name",
|
||||
TargetPath: "user_name",
|
||||
Required: true,
|
||||
DataType: "string",
|
||||
DefaultValue: "",
|
||||
},
|
||||
{
|
||||
SourcePath: "base.age",
|
||||
MapPath: "user_age",
|
||||
TargetPath: "user_age",
|
||||
Required: true,
|
||||
DataType: "int",
|
||||
DefaultValue: "",
|
||||
},
|
||||
{
|
||||
SourcePath: "base.height",
|
||||
MapPath: "user_height",
|
||||
TargetPath: "user_height",
|
||||
Required: true,
|
||||
DataType: "string",
|
||||
DefaultValue: "",
|
||||
},
|
||||
{
|
||||
SourcePath: "company.name",
|
||||
MapPath: "company_name",
|
||||
TargetPath: "company_name",
|
||||
Required: true,
|
||||
DataType: "string",
|
||||
DefaultValue: "",
|
||||
},
|
||||
{
|
||||
SourcePath: "company.start",
|
||||
MapPath: "company_start",
|
||||
TargetPath: "company_start",
|
||||
Required: true,
|
||||
DataType: "string",
|
||||
DefaultValue: "",
|
||||
@ -105,7 +106,7 @@ func TestNewFilterForArrayOne(t *testing.T) {
|
||||
filterRuleList := []MapRule{
|
||||
{
|
||||
SourcePath: "[].name",
|
||||
MapPath: "user_name.[]",
|
||||
TargetPath: "user_name.[]",
|
||||
Required: true,
|
||||
DataType: "string",
|
||||
DefaultValue: "",
|
||||
@ -145,7 +146,7 @@ func TestNewFilterForArrayTwo(t *testing.T) {
|
||||
filterRuleList := []MapRule{
|
||||
{
|
||||
SourcePath: "user_list.[].name",
|
||||
MapPath: "user.name_list.[]",
|
||||
TargetPath: "user.name_list.[]",
|
||||
Required: true,
|
||||
DataType: "string",
|
||||
DefaultValue: "",
|
||||
@ -158,3 +159,13 @@ func TestNewFilterForArrayTwo(t *testing.T) {
|
||||
fmt.Println(f.String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestAntMap(t *testing.T) {
|
||||
testMap := map[any]any{
|
||||
"name": "zhangde",
|
||||
1: 1,
|
||||
1.234: 2.345,
|
||||
}
|
||||
byteData, err := json.Marshal(testMap)
|
||||
fmt.Println(string(byteData), err)
|
||||
}
|
||||
|
3
gjson_hack/README.md
Normal file
3
gjson_hack/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# 对gjson库一些已知问题的pack
|
||||
|
||||
- 大数字 res.Int() 缺失精度
|
50
gjson_hack/define.go
Normal file
50
gjson_hack/define.go
Normal file
@ -0,0 +1,50 @@
|
||||
// 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 // 路径对应的值
|
||||
}
|
||||
|
||||
const (
|
||||
ArrayIdxTpl = "[]"
|
||||
)
|
||||
|
||||
// ExpendArrayResult 展开数组的结果
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:46 2024/11/29
|
||||
type ExpendArrayResult struct {
|
||||
PathList []string `json:"path_list"` // 路径列表
|
||||
PathMap map[string]string `json:"path_map"` // 数据源路径 => 目标路径的处理
|
||||
}
|
||||
|
||||
const (
|
||||
SpecialKeyStart = "{{#"
|
||||
SpecialKeyEnd = "#}}"
|
||||
)
|
15
gjson_hack/error.go
Normal file
15
gjson_hack/error.go
Normal file
@ -0,0 +1,15 @@
|
||||
// Package gjson_hack ...
|
||||
//
|
||||
// Description : filter ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-11-30 19:14
|
||||
package gjson_hack
|
||||
|
||||
var (
|
||||
ErrDataPathNotFound = "data_path_not_found"
|
||||
ErrDataIsNotObject = "data_is_not_object"
|
||||
ErrDataIsNotArray = "data_is_not_an_array"
|
||||
ErrDataTypeIsNotSupport = "data_type_is_not_support"
|
||||
)
|
363
gjson_hack/path.go
Normal file
363
gjson_hack/path.go
Normal file
@ -0,0 +1,363 @@
|
||||
// Package gjson_hack ...
|
||||
//
|
||||
// Description : gjson_hack ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-11-27 11:58
|
||||
package gjson_hack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
// 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 = getPathKey(key.String())
|
||||
} else {
|
||||
newRootPath = rootPath + "." + getPathKey(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 _, itemRes := range arrayList {
|
||||
// doExpandPath(itemRes, rootPath+"."+fmt.Sprintf("%v", idx), true, pathOption, pathResult)
|
||||
doExpandPath(itemRes, rootPath+"."+ArrayIdxTpl, 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, ".#") || strings.HasSuffix(rootPath, ArrayIdxTpl) {
|
||||
// 处理不展开类型数组
|
||||
return
|
||||
}
|
||||
if pathOption.OnlyFinalPath && hasChildren {
|
||||
// 仅记录最终完整路径, 中间路径不记录
|
||||
return
|
||||
}
|
||||
if _, exist := pathResult.ValueTable[rootPath]; !exist {
|
||||
pathResult.List = append(pathResult.List, rootPath)
|
||||
pathResult.ValueTable[rootPath] = gjsonResult
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getPathKey ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 20:54 2024/12/4
|
||||
func getPathKey(key string) string {
|
||||
if !strings.Contains(key, ".") {
|
||||
// 非特殊key
|
||||
return key
|
||||
}
|
||||
if IsSpecialKey(key) {
|
||||
// 已经是special key
|
||||
return key
|
||||
}
|
||||
return SpecialKeyStart + key + SpecialKeyEnd
|
||||
}
|
||||
|
||||
// IsArrayItemPath 是否为数组子项路径
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:49 2024/12/5
|
||||
func IsArrayItemPath(path string) bool {
|
||||
return strings.Contains(path, ArrayIdxTpl)
|
||||
}
|
||||
|
||||
// ExpandArrayPath 根据真实数据展开数组路径
|
||||
//
|
||||
// 路径中若是包含 {{idx}} 占位符, 说明是需要展开的数组, 根据数组的实际数据, 进行数组的逐级展开
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:13 2024/11/29
|
||||
func ExpandArrayPath(jsonStr string, pathConfig string, mapConfig string, expendArrayResult *ExpendArrayResult) error {
|
||||
if nil == expendArrayResult {
|
||||
return errors.New("expendArrayResult can not be nil")
|
||||
}
|
||||
if nil == expendArrayResult.PathList {
|
||||
expendArrayResult.PathList = make([]string, 0)
|
||||
}
|
||||
if nil == expendArrayResult.PathMap {
|
||||
expendArrayResult.PathMap = make(map[string]string)
|
||||
}
|
||||
if len(mapConfig) == 0 {
|
||||
mapConfig = pathConfig
|
||||
}
|
||||
if !IsArrayItemPath(pathConfig) {
|
||||
// 不是数组模板配置, 无需展开
|
||||
expendArrayResult.PathList = append(expendArrayResult.PathList, pathConfig)
|
||||
expendArrayResult.PathMap[pathConfig] = mapConfig
|
||||
return nil
|
||||
}
|
||||
mapConfigArr := strings.Split(mapConfig, ArrayIdxTpl)
|
||||
mapConfigArr[0] = strings.TrimSuffix(mapConfigArr[0], ".")
|
||||
mapSuffixPathTpl := strings.TrimPrefix(strings.Join(mapConfigArr[1:], ArrayIdxTpl), ".")
|
||||
|
||||
pathConfigArr := strings.Split(pathConfig, ArrayIdxTpl)
|
||||
pathConfigArr[0] = strings.TrimSuffix(pathConfigArr[0], ".")
|
||||
suffixPathTpl := strings.TrimPrefix(strings.Join(pathConfigArr[1:], ArrayIdxTpl), ".")
|
||||
|
||||
if len(mapConfigArr) != len(pathConfigArr) {
|
||||
return errors.New("mapConfig depth not equal pathConfig deep")
|
||||
}
|
||||
|
||||
valueResult := Get(gjson.Parse(jsonStr), pathConfigArr[0])
|
||||
if !valueResult.Exists() {
|
||||
// 路径不存在, 无需设置具体值
|
||||
return nil
|
||||
}
|
||||
if !valueResult.IsArray() {
|
||||
// 不是数组,不要继续再向后展开了
|
||||
expendArrayResult.PathList = append(expendArrayResult.PathList, pathConfigArr[0])
|
||||
expendArrayResult.PathMap[pathConfigArr[0]] = mapConfigArr[0]
|
||||
return nil
|
||||
}
|
||||
// 继续展开子项
|
||||
for idx, _ := range valueResult.Array() {
|
||||
idxStr := fmt.Sprintf("%v", idx)
|
||||
if err := ExpandArrayPath(jsonStr, pathConfigArr[0]+"."+idxStr+"."+suffixPathTpl, mapConfigArr[0]+"."+idxStr+"."+mapSuffixPathTpl, expendArrayResult); nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsObject 判断是否是对象, 兼容序列化之后的对象
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:04 2024/12/1
|
||||
func IsObject(gjsonResult gjson.Result) bool {
|
||||
return gjsonResult.IsObject() || gjson.Parse(gjsonResult.String()).IsObject()
|
||||
}
|
||||
|
||||
// IsArray 判断是否为数组
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:05 2024/12/1
|
||||
func IsArray(gjsonResult gjson.Result) bool {
|
||||
return gjsonResult.IsArray() || gjson.Parse(gjsonResult.String()).IsArray()
|
||||
}
|
||||
|
||||
// Object 兼容序列化之后的对象
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:09 2024/12/1
|
||||
func Object(gjsonResult gjson.Result) gjson.Result {
|
||||
res := gjson.Parse(gjsonResult.String())
|
||||
if res.IsObject() {
|
||||
return res
|
||||
}
|
||||
return gjsonResult
|
||||
}
|
||||
|
||||
// Array ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:09 2024/12/1
|
||||
func Array(gjsonResult gjson.Result) gjson.Result {
|
||||
res := gjson.Parse(gjsonResult.String())
|
||||
if res.IsArray() {
|
||||
return res
|
||||
}
|
||||
return gjsonResult
|
||||
}
|
||||
|
||||
// Result ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:12 2024/12/1
|
||||
func Result(gjsonResult gjson.Result) gjson.Result {
|
||||
if IsObject(gjsonResult) {
|
||||
return gjsonResult
|
||||
}
|
||||
if IsArray(gjsonResult) {
|
||||
return Array(gjsonResult)
|
||||
}
|
||||
return Object(gjsonResult)
|
||||
}
|
||||
|
||||
// Get 主要解决 key 中包含 . 的问题
|
||||
//
|
||||
// 如 : {"person.name": "test"} 如何将 person.name 整体作为一个字段而非两个层级
|
||||
//
|
||||
// 解决方案 :
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 20:17 2024/12/4
|
||||
func Get(gjsonResult gjson.Result, path string) gjson.Result {
|
||||
if len(path) == 0 {
|
||||
return gjsonResult
|
||||
}
|
||||
if !gjsonResult.Exists() {
|
||||
return gjsonResult
|
||||
}
|
||||
if !gjsonResult.IsObject() && !gjsonResult.IsArray() {
|
||||
return gjsonResult.Get(path)
|
||||
}
|
||||
if !IsSpecialPath(path) {
|
||||
// 不是特殊路径
|
||||
return gjsonResult.Get(path)
|
||||
}
|
||||
pathArr := strings.Split(path, ".")
|
||||
normalPathList := make([]string, 0)
|
||||
specialKeyList := make([]string, 0)
|
||||
specialKeyHasStart := false
|
||||
for idx, item := range pathArr {
|
||||
if strings.HasPrefix(item, SpecialKeyStart) {
|
||||
specialKeyHasStart = true
|
||||
specialKeyList = append(specialKeyList, item)
|
||||
continue
|
||||
}
|
||||
if strings.HasSuffix(item, SpecialKeyEnd) {
|
||||
specialKeyHasStart = false
|
||||
specialKeyList = append(specialKeyList, item)
|
||||
sourceResult := gjsonResult
|
||||
if len(normalPathList) > 0 {
|
||||
sourceResult = gjsonResult.Get(strings.Join(normalPathList, "."))
|
||||
}
|
||||
realKeyName := GetRealKeyName(strings.Join(specialKeyList, "."))
|
||||
return Get(sourceResult.Map()[realKeyName], strings.Join(pathArr[idx+1:], "."))
|
||||
}
|
||||
if specialKeyHasStart {
|
||||
specialKeyList = append(specialKeyList, item)
|
||||
continue
|
||||
}
|
||||
normalPathList = append(normalPathList, item)
|
||||
}
|
||||
return gjsonResult
|
||||
}
|
||||
|
||||
// GetMany 兼容 gjson GetMany 方法
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:32 2024/12/5
|
||||
func GetMany(jsonStr string, pathList ...string) []gjson.Result {
|
||||
res := make([]gjson.Result, 0)
|
||||
gjsonResult := gjson.Parse(jsonStr)
|
||||
for _, itemPath := range pathList {
|
||||
res = append(res, Get(gjsonResult, itemPath))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// IsSpecialPath 判断传入的是否为特殊路径
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 20:27 2024/12/4
|
||||
func IsSpecialPath(path string) bool {
|
||||
return strings.Contains(path, SpecialKeyStart) && strings.Contains(path, SpecialKeyEnd)
|
||||
}
|
||||
|
||||
// IsSpecialKey 判断是否特殊key
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 20:29 2024/12/4
|
||||
func IsSpecialKey(key string) bool {
|
||||
return strings.HasPrefix(key, SpecialKeyStart) && strings.HasSuffix(key, SpecialKeyEnd)
|
||||
}
|
||||
|
||||
// GetRealKeyName ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 20:31 2024/12/4
|
||||
func GetRealKeyName(key string) string {
|
||||
return strings.TrimSuffix(strings.TrimPrefix(key, SpecialKeyStart), SpecialKeyEnd)
|
||||
}
|
201
gjson_hack/path_test.go
Normal file
201
gjson_hack/path_test.go
Normal file
@ -0,0 +1,201 @@
|
||||
// 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"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
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",
|
||||
"user_list": [][]map[string]any{
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 10},
|
||||
{"name": "li", "age": 20},
|
||||
{"name": "wang", "age": 30},
|
||||
},
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 20},
|
||||
{"name": "li", "age": 20},
|
||||
{"name": "wang", "age": 30},
|
||||
},
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 30},
|
||||
{"name": "li", "age": 20},
|
||||
{"name": "wang", "age": 30},
|
||||
},
|
||||
},
|
||||
}
|
||||
byteData, _ := json.Marshal(mapData)
|
||||
fmt.Println(gjson.GetBytes(byteData, "user_list.#.#.age"))
|
||||
fmt.Println(gjson.GetBytes(byteData, "user_list.0.0.age"))
|
||||
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",
|
||||
"a.b": "cd",
|
||||
},
|
||||
"sex": "man",
|
||||
"user_list": [][]map[string]any{
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 10, "e.f": "g"},
|
||||
{"name": "li", "age": 20, "e.f": "g"},
|
||||
{"name": "wang", "age": 30, "e.f": "g"},
|
||||
},
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 10},
|
||||
{"name": "li", "age": 20},
|
||||
{"name": "wang", "age": 30},
|
||||
},
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 10},
|
||||
{"name": "li", "age": 20},
|
||||
{"name": "wang", "age": 30},
|
||||
},
|
||||
},
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpandArrayPath(t *testing.T) {
|
||||
mapData := map[string]any{
|
||||
"person_list": []map[string]any{
|
||||
{"name": "zhang", "age": 10, "a.b": "people_name"},
|
||||
{"name": "li", "age": 20, "a.b": "people_name"},
|
||||
{"name": "wang", "age": 30, "a.b": "people_name"},
|
||||
},
|
||||
"company_info": map[string]any{
|
||||
"address": "Beijing",
|
||||
"email": "xxx@xxx.com",
|
||||
"level.a.b": "deep level",
|
||||
},
|
||||
"sex": "man",
|
||||
"user_list": [][]map[string]any{
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 10},
|
||||
{"name": "li", "age": 20},
|
||||
{"name": "wang", "age": 30},
|
||||
},
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 10},
|
||||
{"name": "li", "age": 20},
|
||||
{"name": "wang", "age": 30},
|
||||
},
|
||||
[]map[string]any{
|
||||
{"name": "zhang", "age": 10},
|
||||
{"name": "li", "age": 20},
|
||||
{"name": "wang", "age": 30},
|
||||
},
|
||||
},
|
||||
}
|
||||
byteData, _ := json.Marshal(mapData)
|
||||
jsonStr := string(byteData)
|
||||
|
||||
var pathExpendRes = &ExpendArrayResult{
|
||||
PathList: nil,
|
||||
PathMap: nil,
|
||||
}
|
||||
ExpandArrayPath(jsonStr, "company_info.{{#level.a.b#}}", "company_info.a-b", pathExpendRes)
|
||||
ExpandArrayPath(jsonStr, "person_list.{{idx}}.{{#a.b#}}", "person_list.{{idx}}.a-b", pathExpendRes)
|
||||
ExpandArrayPath(jsonStr, "user_list.{{idx}}.{{idx}}.age", "a.{{idx}}.{{idx}}.b", pathExpendRes)
|
||||
ExpandArrayPath(jsonStr, "user_list.{{idx}}.{{idx}}.name", "e.{{idx}}.{{idx}}.c", pathExpendRes)
|
||||
ExpandArrayPath(jsonStr, "user_list.{{idx}}.{{idx}}.sex", "f.{{idx}}.{{idx}}.c", pathExpendRes)
|
||||
// res := ""
|
||||
for _, item := range pathExpendRes.PathList {
|
||||
// fmt.Println(item, pathExpendRes.PathMap[item])
|
||||
fmt.Println(item, pathExpendRes.PathMap[item], Get(gjson.Parse(jsonStr), item).String())
|
||||
// res, _ = sjson.Set(res, pathExpendRes.PathMap[item], Get(gjson.Parse(jsonStr), item).Value())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
mapData := map[string]any{
|
||||
"person.name": "test",
|
||||
"test": map[string]any{
|
||||
"a.b": "c",
|
||||
"d.e": map[string]any{
|
||||
"e.f": "g",
|
||||
},
|
||||
},
|
||||
}
|
||||
byteData, _ := json.Marshal(mapData)
|
||||
gjsonResult := gjson.ParseBytes(byteData)
|
||||
fmt.Println(Get(gjsonResult, "{{#person.name#}}").String())
|
||||
fmt.Println(Get(gjsonResult, "test.{{#a.b#}}").String())
|
||||
fmt.Println(Get(gjsonResult, "test.{{#d.e#}}.{{#e.f#}}").String())
|
||||
}
|
469
gjson_hack/precision.go
Normal file
469
gjson_hack/precision.go
Normal file
@ -0,0 +1,469 @@
|
||||
// Package gjson_hack 精确地类型转换
|
||||
//
|
||||
// Description : gjson_hack ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-11-27 10:47
|
||||
package gjson_hack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.zhangdeman.cn/zhangdeman/consts"
|
||||
"git.zhangdeman.cn/zhangdeman/exception"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"git.zhangdeman.cn/zhangdeman/util"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"github.com/tidwall/gjson"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Number 结果转换为数字(int64 / uint64 / float64)
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:57 2024/11/27
|
||||
func Number(gjsonResult gjson.Result, numberReceiver any) error {
|
||||
if !gjsonResult.Exists() {
|
||||
return errors.New("gjson result not found")
|
||||
}
|
||||
if gjsonResult.Type != gjson.Number {
|
||||
return errors.New(gjsonResult.String() + " : value not a number")
|
||||
}
|
||||
if err := util.ConvertAssign(numberReceiver, gjsonResult.String()); nil != err {
|
||||
return errors.New(gjsonResult.String() + " : convert to num fail -> " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int 转int
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:19 2024/11/27
|
||||
func Int[T int8 | int16 | int32 | int64 | int](gjsonResult gjson.Result) (T, error) {
|
||||
var intResult T
|
||||
if err := Number(gjsonResult, &intResult); nil != err {
|
||||
return 0, err
|
||||
}
|
||||
return intResult, nil
|
||||
}
|
||||
|
||||
// Uint 转为uint64
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:21 2024/11/27
|
||||
func Uint[T uint8 | uint16 | uint32 | uint64 | uint](gjsonResult gjson.Result) (T, error) {
|
||||
var uintResult T
|
||||
if err := Number(gjsonResult, &uintResult); nil != err {
|
||||
return 0, err
|
||||
}
|
||||
return uintResult, nil
|
||||
}
|
||||
|
||||
// Float 转为float64
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:24 2024/11/27
|
||||
func Float[T float32 | float64](gjsonResult gjson.Result) (T, error) {
|
||||
var floatResult T
|
||||
if err := Number(gjsonResult, &floatResult); nil != err {
|
||||
return 0, err
|
||||
}
|
||||
return floatResult, nil
|
||||
}
|
||||
|
||||
// String 获取字符串值
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:55 2024/12/1
|
||||
func String(sourceValue gjson.Result, defaultValue string) string {
|
||||
sourceValueStr := defaultValue
|
||||
if sourceValue.Exists() {
|
||||
str := sourceValue.String()
|
||||
if len(str) > 0 {
|
||||
sourceValueStr = str
|
||||
}
|
||||
}
|
||||
return sourceValueStr
|
||||
}
|
||||
|
||||
// MapAnyAny ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:48 2024/12/1
|
||||
func MapAnyAny(sourceValue gjson.Result) (map[string]any, error) {
|
||||
if !sourceValue.Exists() {
|
||||
return nil, exception.New(ErrDataPathNotFound, nil, "data path not found")
|
||||
}
|
||||
if !sourceValue.IsObject() {
|
||||
return nil, exception.New(ErrDataIsNotObject, nil)
|
||||
}
|
||||
res := make(map[string]any)
|
||||
sourceValue.ForEach(func(key, value gjson.Result) bool {
|
||||
res[key.String()] = value
|
||||
return true
|
||||
})
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Any 获取任意类型的值
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:00 2024/12/1
|
||||
func Any(sourceValue gjson.Result) (any, error) {
|
||||
if !sourceValue.Exists() {
|
||||
return nil, nil
|
||||
}
|
||||
// 可能存在精度丢失, 原因 : gjson.Value 内置的转换, int64 超过一定大小会存在丢失精度问题
|
||||
if sourceValue.Type == gjson.Number {
|
||||
// 说明是数字
|
||||
if strings.Contains(sourceValue.String(), ".") {
|
||||
// 小数
|
||||
var res float64
|
||||
if err := Number(sourceValue, &res); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
} else {
|
||||
// 整数
|
||||
if strings.HasPrefix(sourceValue.String(), "-") {
|
||||
// 负数
|
||||
var res int64
|
||||
if err := Number(sourceValue, &res); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
} else {
|
||||
// 正数
|
||||
var res uint64
|
||||
if err := Number(sourceValue, &res); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if sourceValue.IsObject() {
|
||||
return MapAnyAny(sourceValue)
|
||||
}
|
||||
if sourceValue.IsArray() {
|
||||
return SliceAny(sourceValue)
|
||||
}
|
||||
return sourceValue.Value(), nil
|
||||
|
||||
}
|
||||
|
||||
// getRealDataType ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:28 2024/12/1
|
||||
func getRealDataType(dataType consts.DataType, sourceValue gjson.Result) consts.DataType {
|
||||
// 指针数据类型, 转换为普通数据类型处理
|
||||
dataType = consts.DataType(strings.TrimLeft(dataType.String(), "*"))
|
||||
// 没指定数据类型或者数据类型是any
|
||||
if dataType == consts.DataTypeAny || dataType == "" {
|
||||
if sourceValue.IsObject() {
|
||||
dataType = consts.DataTypeMapAnyAny
|
||||
} else if sourceValue.IsArray() {
|
||||
dataType = consts.DataTypeSliceAny
|
||||
} else if sourceValue.IsBool() {
|
||||
dataType = consts.DataTypeBool
|
||||
} else {
|
||||
if sourceValue.Type == gjson.Number {
|
||||
dataType = consts.DataTypeFloat64
|
||||
} else if sourceValue.Type == gjson.String {
|
||||
dataType = consts.DataTypeString
|
||||
} else {
|
||||
dataType = consts.DataTypeAny
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataType
|
||||
}
|
||||
|
||||
// SliceAny ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:53 2024/12/1
|
||||
func SliceAny(gjsonResult gjson.Result) ([]any, error) {
|
||||
if gjsonResult.Value() == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
strVal := strings.TrimSpace(gjsonResult.String())
|
||||
// 任意类型的list
|
||||
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
|
||||
// 序列化之后的数组
|
||||
sliceVal := wrapper.String(strVal).ToAnySlice()
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
// 分隔的数组
|
||||
sliceVal := wrapper.String(strVal).ToAnySlice(",")
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
|
||||
// SliceInt 获取int list
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:43 2024/12/1
|
||||
func SliceInt(gjsonResult gjson.Result) ([]int64, error) {
|
||||
if gjsonResult.Value() == nil {
|
||||
return nil, nil
|
||||
}
|
||||
strVal := strings.TrimSpace(gjsonResult.String())
|
||||
// 任意类型的list
|
||||
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
|
||||
// 序列化之后的数组
|
||||
sliceVal := wrapper.String(strVal).ToInt64Slice()
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
// 分隔的数组
|
||||
sliceVal := wrapper.String(strVal).ToInt64Slice(",")
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
|
||||
// SliceUint ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:58 2024/12/1
|
||||
func SliceUint(gjsonResult gjson.Result) ([]uint64, error) {
|
||||
if gjsonResult.Value() == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
strVal := strings.TrimSpace(gjsonResult.String())
|
||||
// 任意类型的list
|
||||
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
|
||||
// 序列化之后的数组
|
||||
sliceVal := wrapper.String(strVal).ToUint64Slice()
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
// 分隔的数组
|
||||
sliceVal := wrapper.String(strVal).ToUint64Slice(",")
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
|
||||
// SliceFloat ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:59 2024/12/1
|
||||
func SliceFloat(gjsonResult gjson.Result) ([]float64, error) {
|
||||
if gjsonResult.Value() == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
strVal := strings.TrimSpace(gjsonResult.String())
|
||||
// 任意类型的list
|
||||
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
|
||||
// 序列化之后的数组
|
||||
sliceVal := wrapper.String(strVal).ToFloat64Slice()
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
// 分隔的数组
|
||||
sliceVal := wrapper.String(strVal).ToFloat64Slice(",")
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
|
||||
// SliceBool ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:00 2024/12/1
|
||||
func SliceBool(gjsonResult gjson.Result) ([]bool, error) {
|
||||
if gjsonResult.Value() == nil {
|
||||
return nil, nil
|
||||
}
|
||||
strVal := strings.TrimSpace(gjsonResult.String())
|
||||
// 任意类型的list
|
||||
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
|
||||
// 序列化之后的数组
|
||||
sliceVal := wrapper.String(strVal).ToBoolSlice()
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
// 分隔的数组
|
||||
sliceVal := wrapper.String(strVal).ToBoolSlice(",")
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
|
||||
// SliceString ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:03 2024/12/1
|
||||
func SliceString(gjsonResult gjson.Result) ([]string, error) {
|
||||
if gjsonResult.Value() == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
strVal := strings.TrimSpace(gjsonResult.String())
|
||||
// 任意类型的list
|
||||
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
|
||||
// 序列化之后的数组
|
||||
sliceVal := wrapper.String(strVal).ToStringSlice()
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
// 分隔的数组
|
||||
sliceVal := wrapper.String(strVal).ToStringSlice(",")
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
}
|
||||
|
||||
// SliceMapStringAny ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:41 2024/12/1
|
||||
func SliceMapStringAny(gjsonResult gjson.Result) ([]map[string]any, error) {
|
||||
if gjsonResult.Value() == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
strVal := strings.TrimSpace(gjsonResult.String())
|
||||
// 任意类型的list
|
||||
if !gjsonResult.IsArray() {
|
||||
return nil, exception.New(ErrDataIsNotArray, nil)
|
||||
}
|
||||
var res []map[string]any
|
||||
if err := serialize.JSON.UnmarshalWithNumber([]byte(strVal), &res); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SliceSlice ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:44 2024/12/1
|
||||
func SliceSlice(gjsonResult gjson.Result) ([][]any, error) {
|
||||
if gjsonResult.Value() == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
strVal := strings.TrimSpace(gjsonResult.String())
|
||||
// 任意类型的list
|
||||
if !gjsonResult.IsArray() {
|
||||
return nil, exception.New(ErrDataIsNotArray, nil)
|
||||
}
|
||||
var res [][]any
|
||||
if err := serialize.JSON.UnmarshalWithNumber([]byte(strVal), &res); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// MapStrAny 获取任意map类型的结果
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:26 2024/12/2
|
||||
func MapStrAny[T string | int64 | uint64 | bool | float64 | []any | map[string]any | any](gjsonResult gjson.Result) (map[string]T, error) {
|
||||
if !gjsonResult.IsObject() {
|
||||
return nil, exception.New(ErrDataIsNotArray, nil)
|
||||
}
|
||||
var res map[string]T
|
||||
if err := serialize.JSON.UnmarshalWithNumber([]byte(gjsonResult.String()), &res); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Value 获取指定的值
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:52 2024/12/1
|
||||
func Value(dataType consts.DataType, sourceValue gjson.Result, defaultValue any) (any, error) {
|
||||
if !sourceValue.Exists() {
|
||||
return defaultValue, nil
|
||||
}
|
||||
// 归一化处理对象、数组等
|
||||
sourceValue = Result(sourceValue)
|
||||
dataType = getRealDataType(dataType, sourceValue)
|
||||
strVal := wrapper.String(sourceValue.String())
|
||||
switch dataType {
|
||||
case consts.DataTypeInt:
|
||||
return Int[int](sourceValue)
|
||||
case consts.DataTypeInt8:
|
||||
return Int[int8](sourceValue)
|
||||
case consts.DataTypeInt16:
|
||||
return Int[int16](sourceValue)
|
||||
case consts.DataTypeInt32:
|
||||
return Int[int32](sourceValue)
|
||||
case consts.DataTypeInt64:
|
||||
return Int[int64](sourceValue)
|
||||
case consts.DataTypeUint:
|
||||
return Uint[uint](sourceValue)
|
||||
case consts.DataTypeUint8:
|
||||
return Uint[uint8](sourceValue)
|
||||
case consts.DataTypeUint16:
|
||||
return Uint[uint16](sourceValue)
|
||||
case consts.DataTypeUint32:
|
||||
return Uint[uint32](sourceValue)
|
||||
case consts.DataTypeUint64:
|
||||
return Uint[uint64](sourceValue)
|
||||
case consts.DataTypeFloat64:
|
||||
return Float[float64](sourceValue)
|
||||
case consts.DataTypeFloat32:
|
||||
return Float[float32](sourceValue)
|
||||
case consts.DataTypeBool:
|
||||
boolVal := strVal.ToBool()
|
||||
return boolVal.Value, boolVal.Err
|
||||
case consts.DataTypeString:
|
||||
return sourceValue.String(), nil
|
||||
case consts.DataTypeAny:
|
||||
// 经过getRealDataType类型处理后依旧是any,不考虑精度问题
|
||||
return sourceValue.Value(), nil
|
||||
case consts.DataTypeSliceAny:
|
||||
// 任意类型的list
|
||||
sliceVal := strVal.ToAnySlice()
|
||||
return sliceVal.Value, sliceVal.Err
|
||||
case consts.DataTypeSliceInt, consts.DataTypeSliceIntWithChar:
|
||||
// 任意类型的list
|
||||
return SliceInt(sourceValue)
|
||||
case consts.DataTypeSliceUint, consts.DataTypeSliceUintWithChar:
|
||||
// 任意类型的list
|
||||
return SliceUint(sourceValue)
|
||||
case consts.DataTypeSliceFloat, consts.DataTypeSliceFloatWithChar:
|
||||
// 任意类型的list
|
||||
return SliceFloat(sourceValue)
|
||||
case consts.DataTypeSliceBool, consts.DataTypeSliceBoolWithChar:
|
||||
// 任意类型的list
|
||||
return SliceBool(sourceValue)
|
||||
case consts.DataTypeSliceString, consts.DataTypeSliceStringWithChar:
|
||||
// 任意类型的list
|
||||
return SliceString(sourceValue)
|
||||
case consts.DataTypeSliceSlice:
|
||||
return SliceSlice(sourceValue)
|
||||
case consts.DataTypeMapAnyAny:
|
||||
return MapAnyAny(sourceValue)
|
||||
case consts.DataTypeSliceMapStringAny:
|
||||
return SliceMapStringAny(sourceValue)
|
||||
case consts.DataTypeMapStrInt:
|
||||
return MapStrAny[int64](sourceValue)
|
||||
case consts.DataTypeMapStrUint:
|
||||
return MapStrAny[uint64](sourceValue)
|
||||
case consts.DataTypeMapStrFloat:
|
||||
return MapStrAny[float64](sourceValue)
|
||||
case consts.DataTypeMapStrBool:
|
||||
return MapStrAny[bool](sourceValue)
|
||||
case consts.DataTypeMapStrAny:
|
||||
return MapStrAny[any](sourceValue)
|
||||
case consts.DataTypeMapStrStr:
|
||||
return MapStrAny[string](sourceValue)
|
||||
case consts.DataTypeMapStrSlice:
|
||||
return MapStrAny[[]any](sourceValue)
|
||||
default:
|
||||
return nil, exception.New(ErrDataTypeIsNotSupport, map[string]any{"data_type": dataType.String()})
|
||||
}
|
||||
}
|
32
go.mod
32
go.mod
@ -1,31 +1,35 @@
|
||||
module git.zhangdeman.cn/zhangdeman/json_filter
|
||||
|
||||
go 1.18
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.3
|
||||
|
||||
require (
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20220627070212-c590a0a1c216
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230505025924-96532aff0019
|
||||
github.com/Jeffail/gabs v1.4.0
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250425024726-cc17224cb995
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20230731062340-983985c12eda
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250504055908-8d68e6106ea9
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/smartystreets/goconvey v1.7.2
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/smartystreets/goconvey v1.8.1
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20230505080742-fa2f27724d76 // indirect
|
||||
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20250510123912-a0d52fc093ab // indirect
|
||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
|
||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mssola/user_agent v0.6.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
github.com/mozillazg/go-pinyin v0.20.0 // indirect
|
||||
github.com/sbabiv/xml2map v1.2.1 // indirect
|
||||
github.com/smarty/assertions v1.15.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
79
go.sum
79
go.sum
@ -1,57 +1,56 @@
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20220627070212-c590a0a1c216 h1:5M6YsHmbTqLDGkqKykeoxrrd5WsAme6I+akn9sgKUZk=
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20220627070212-c590a0a1c216/go.mod h1:8Jh+q/L0pWAKQy67m8AKIs0WGGrVKypoSZZbBm4nDVc=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20220626081130-cbac0b676fb8/go.mod h1:G2/OKMbEn89d+YUXQtv9Nlh0LGg14pOqDnbOgBTTRXY=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230211164227-256094968151 h1:j537bRLQL1FlkdXTIaT9Ecjx5eogkPsGiTOWIEFQlc8=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230211164227-256094968151/go.mod h1:SyRTkOz6gxUVn3S/Qtkf+rhKV0I1ym8lwsT8YjggYFs=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230330065032-faba0a5a9ea1 h1:u2FdNfcGvRmlKpuPBk2qvYenkZjinHY2PLu5Wmhka8A=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230330065032-faba0a5a9ea1/go.mod h1:SyRTkOz6gxUVn3S/Qtkf+rhKV0I1ym8lwsT8YjggYFs=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230330082619-662152cb682d h1:kMQZmkYBceHM3O7wiCelSADjTyOF3EBxXTX8fgZA+6c=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230330082619-662152cb682d/go.mod h1:qeVsrMae8ljqzcsmI+lWPU/4Rdjb9cOt4oaDUNEf1Ck=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230505025924-96532aff0019 h1:eJ/9rEj2iI8P9I1DfCmMUvsV+n2EiAWCXnI9yVVDHO0=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230505025924-96532aff0019/go.mod h1:z2bP5LIwRVpWSQV0/a3WIFaoarJUP8kA/0Clv0bP+8I=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20230505064614-5e785171ed67 h1:DH9K3fNddpFxRGLkcLP5MHsAQVinpWpmGzbVBf8yrKM=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20230505064614-5e785171ed67/go.mod h1:2jc48WuVoHxZjkvlBewzp+ey8khP1K4OOcibVD1yL2k=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20230505070245-b182b21e039b h1:ZwAA10/+v3FFAq5/EzjXdXDodmKppXb5gBkCcgaYVBo=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20230505070245-b182b21e039b/go.mod h1:2jc48WuVoHxZjkvlBewzp+ey8khP1K4OOcibVD1yL2k=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20230505080742-fa2f27724d76 h1:IEixZNZY3/nqb5v9PzzgSeXLPp0U7wRaxrM+ZaSh+j0=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20230505080742-fa2f27724d76/go.mod h1:2jc48WuVoHxZjkvlBewzp+ey8khP1K4OOcibVD1yL2k=
|
||||
github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo=
|
||||
github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca h1:uxjzbY5fDozjyK6jkoQtuQouVTcVfXjbe3chARYSjRM=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250328040304-7e4a6f9f148c h1:cl3gQGXQpJ8ugDs0C/hQLfcvF4lGBm5BeABLvROFDoM=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250328040304-7e4a6f9f148c/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250425024726-cc17224cb995 h1:LmPRAf0AsxRVFPibdpZR89ajlsz8hof2IvMMyTqiEq4=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250425024726-cc17224cb995/go.mod h1:5p8CEKGBxi7qPtTXDI3HDmqKAfIm5i/aBWdrbkbdNjc=
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20230731062340-983985c12eda h1:bMD6r9gjRy7cO+T4zRQVYAesgIblBdTnhzT1vN5wjvI=
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20230731062340-983985c12eda/go.mod h1:dT0rmHcJ9Z9IqWeMIt7YzR88nKkNV2V3dfG0j9Q6lK0=
|
||||
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20250510123912-a0d52fc093ab h1:O0XaAKKb8qrjcjewonmKfnRsMFoCfJF+tUv6RfhRe94=
|
||||
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20250510123912-a0d52fc093ab/go.mod h1:Voc8J4ordx7nuMWpgACXXZULQy7ZIuBzcEIoS8VnDIw=
|
||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 h1:gUDlQMuJ4xNfP2Abl1Msmpa3fASLWYkNlqDFF/6GN0Y=
|
||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0/go.mod h1:VHb9qmhaPDAQDcS6vUiDCamYjZ4R5lD1XtVsh55KsMI=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd h1:q7GG14qgXKB4MEXQFOe7/UYebsqMfPaSX80TcPdOosI=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd/go.mod h1:+D6uPSljwHywjVY5WSBY4TRVMj26TN5f5cFGEYMldjs=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250504055908-8d68e6106ea9 h1:/GLQaFoLb+ciHOtAS2BIyPNnf4O5ME3AC5PUaJY9kfs=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250504055908-8d68e6106ea9/go.mod h1:ABJ655C5QenQNOzf7LjCe4sSB52CXvaWLX2Zg4uwDJY=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e h1:Q973S6CcWr1ICZhFI1STFOJ+KUImCl2BaIXm6YppBqI=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740 h1:zPUoylfJTbc0EcxW+NEzOTBmoeFZ2I/rLFBnEzxb4Wk=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740/go.mod h1:1ct92dbVc49pmXusA/iGfcQUJzcYmJ+cjAhgc3sDv1I=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mssola/user_agent v0.6.0 h1:uwPR4rtWlCHRFyyP9u2KOV0u8iQXmS7Z7feTrstQwk4=
|
||||
github.com/mssola/user_agent v0.6.0/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw=
|
||||
github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ=
|
||||
github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||
github.com/sbabiv/xml2map v1.2.1 h1:1lT7t0hhUvXZCkdxqtq4n8/ZCnwLWGq4rDuDv5XOoFE=
|
||||
github.com/sbabiv/xml2map v1.2.1/go.mod h1:2TPoAfcaM7+Sd4iriPvzyntb2mx7GY+kkQpB/GQa/eo=
|
||||
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
||||
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
||||
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
||||
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
@ -59,13 +58,7 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
142
implement/gjson_read.go
Normal file
142
implement/gjson_read.go
Normal file
@ -0,0 +1,142 @@
|
||||
// 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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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:
|
||||
valStr := pathRes.String()
|
||||
if strings.Contains(valStr, ".") {
|
||||
return consts.DataTypeFloat64.String()
|
||||
}
|
||||
if strings.HasPrefix(valStr, "-") {
|
||||
return consts.DataTypeInt64.String()
|
||||
}
|
||||
return consts.DataTypeUint64.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[int64](g.gjsonResult.Get(dataPath))
|
||||
}
|
||||
|
||||
func (g *gjsonRead) Uint(dataPath string) (uint64, error) {
|
||||
return gjson_hack.Uint[uint64](g.gjsonResult.Get(dataPath))
|
||||
}
|
||||
|
||||
func (g *gjsonRead) Float(dataPath string) (float64, error) {
|
||||
return gjson_hack.Float[float64](g.gjsonResult.Get(dataPath))
|
||||
}
|
||||
|
||||
func (g *gjsonRead) Bool(dataPath string) (bool, error) {
|
||||
res := g.gjsonResult.Get(dataPath)
|
||||
if !res.IsBool() {
|
||||
return false, errors.New(dataPath + ": is not a bool")
|
||||
}
|
||||
return res.Bool(), nil
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
128
implement/sjson_write.go
Normal file
128
implement/sjson_write.go
Normal file
@ -0,0 +1,128 @@
|
||||
// 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) Delete(dataPath string) error {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
s.l.Lock()
|
||||
defer s.l.Unlock()
|
||||
if s.res, err = sjson.Delete(s.res, dataPath); nil != err {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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 {
|
||||
s.l.RLock()
|
||||
defer s.l.RUnlock()
|
||||
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.Result(), 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.Result(), receiver)
|
||||
}
|
66
sjson_hack/set.go
Normal file
66
sjson_hack/set.go
Normal file
@ -0,0 +1,66 @@
|
||||
// Package sjson_hack ...
|
||||
//
|
||||
// Description : sjson_hack ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-12-03 11:36
|
||||
package sjson_hack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"github.com/tidwall/sjson"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
reg = regexp.MustCompile(`({\{\#.*?\#\}\})`)
|
||||
)
|
||||
|
||||
// Set 设置路径的值
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:36 2024/12/3
|
||||
func Set(jsonRes string, path string, value any) (string, error) {
|
||||
var (
|
||||
err error
|
||||
res string = jsonRes
|
||||
)
|
||||
|
||||
// 包含特殊字符串, 匹配出特殊字符串
|
||||
specialKeyList := getSpecialKeyList(path)
|
||||
specialKeyTale := map[string]string{}
|
||||
for _, item := range specialKeyList {
|
||||
// 替换掉占位字符串
|
||||
specialKeyTale[item] = wrapper.StringFromRandom(64, "").Md5().Value
|
||||
path = strings.ReplaceAll(path, item, specialKeyTale[item])
|
||||
}
|
||||
|
||||
if res, err = sjson.Set(res, path, value); nil != err {
|
||||
return "", errors.New(path + " -> set json fail:" + err.Error())
|
||||
}
|
||||
|
||||
// 将特殊字符串替换回来
|
||||
for sourceKey, convertKey := range specialKeyTale {
|
||||
res = strings.ReplaceAll(res, convertKey, gjson_hack.GetRealKeyName(sourceKey))
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// getSpecialKeyList 获取特殊key列表
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:35 2024/12/5
|
||||
func getSpecialKeyList(path string) []string {
|
||||
matchList := reg.FindAllString(path, -1)
|
||||
if len(matchList) == 0 {
|
||||
return make([]string, 0)
|
||||
}
|
||||
return matchList
|
||||
}
|
18
sjson_hack/set_test.go
Normal file
18
sjson_hack/set_test.go
Normal file
@ -0,0 +1,18 @@
|
||||
// Package sjson_hack ...
|
||||
//
|
||||
// Description : sjson_hack ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-12-05 17:32
|
||||
package sjson_hack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
res, err := Set("{}", "{{#a.b#}}.c.{{#c.d#}}.e", "test")
|
||||
fmt.Println(res, err)
|
||||
}
|
@ -10,14 +10,10 @@ package json_tool
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"github.com/tidwall/gjson"
|
||||
"strings"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/util"
|
||||
)
|
||||
|
||||
// MapDataRule 数据映射结果
|
||||
@ -109,37 +105,7 @@ func (f *Filter) SetValue(result *DynamicJSON, path string, val interface{}, isS
|
||||
//
|
||||
// Date : 10:46 下午 2021/3/14
|
||||
func (f *Filter) isLegalData() bool {
|
||||
val := reflect.ValueOf(f.data)
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Slice:
|
||||
// slice 情况下,对字节数组进行特殊判断
|
||||
var (
|
||||
byteData []byte
|
||||
ok bool
|
||||
err error
|
||||
)
|
||||
if byteData, ok = f.data.([]byte); ok {
|
||||
// 字节数组转map或者slice
|
||||
if err = json.Unmarshal(byteData, &f.data); nil != err {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
case reflect.Map:
|
||||
return true
|
||||
case reflect.Struct:
|
||||
// 结构体转为字符串处理
|
||||
fallthrough
|
||||
case reflect.Ptr:
|
||||
// 指针
|
||||
var err error
|
||||
if f.data, err = util.Struct.ToMap(f.data); nil != err {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
byteData, _ := json.Marshal(f.data)
|
||||
dataRes := gjson.Parse(string(byteData))
|
||||
return dataRes.IsObject() || dataRes.IsArray()
|
||||
}
|
||||
|
461
tool/gabs.go
461
tool/gabs.go
@ -8,19 +8,32 @@
|
||||
package json_tool
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/util"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/Jeffail/gabs"
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
|
||||
const (
|
||||
// virtualRoot 虚拟根节点
|
||||
virtualRoot = "__VIRTUAL_ROOT__"
|
||||
)
|
||||
|
||||
// FilterOption 过滤选项
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:59 2023/9/1
|
||||
type FilterOption struct {
|
||||
DebugModel bool // 调试模式
|
||||
LogInstance io.Writer // 日志实例
|
||||
}
|
||||
|
||||
// FilterDataRule 参数过滤规则
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
@ -38,12 +51,45 @@ type FilterDataRule struct {
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2022/1/22 9:50 PM
|
||||
func NewDataFilter(source string, filterRule []*FilterDataRule) *DataFilter {
|
||||
return &DataFilter{
|
||||
source: source,
|
||||
filterRule: filterRule,
|
||||
hasDealDiffPath: make(map[string]string),
|
||||
func NewDataFilter(source string, filterRule []*FilterDataRule, filterOption *FilterOption) *DataFilter {
|
||||
source = fmt.Sprintf(`{"%v":%v}`, virtualRoot, source)
|
||||
if nil == filterOption {
|
||||
filterOption = &FilterOption{}
|
||||
}
|
||||
if filterOption.DebugModel && nil == filterOption.LogInstance {
|
||||
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 = virtualRoot + "." + strings.TrimRight(item.MapKey, ".[]")
|
||||
item.SourceKey = virtualRoot + "." + 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 df
|
||||
}
|
||||
|
||||
// DataFilter 数据过滤
|
||||
@ -52,10 +98,10 @@ func NewDataFilter(source string, filterRule []*FilterDataRule) *DataFilter {
|
||||
//
|
||||
// Date : 2022/1/22 9:20 PM
|
||||
type DataFilter struct {
|
||||
source string
|
||||
filterRule []*FilterDataRule
|
||||
itemKeyToSlice bool
|
||||
hasDealDiffPath map[string]string
|
||||
source string
|
||||
filterRule []*FilterDataRule
|
||||
rewriteResult string // json数据重写结果
|
||||
filterOption *FilterOption // 过滤选项
|
||||
}
|
||||
|
||||
// Filter 数据过滤
|
||||
@ -64,231 +110,224 @@ type DataFilter struct {
|
||||
//
|
||||
// Date : 2022/1/22 9:36 PM
|
||||
func (df *DataFilter) Filter() (string, error) {
|
||||
df.logPrint(logLevelDebug, "source_data => ", df.source)
|
||||
var (
|
||||
jsonObject *gabs.Container
|
||||
err error
|
||||
err error
|
||||
)
|
||||
// 格式化映射规则
|
||||
df.formatRule()
|
||||
// 记录 obj => slice 的数据类型
|
||||
obg2slice := make(map[string]string)
|
||||
// 创建数据的根结点
|
||||
jsonObject = gabs.New()
|
||||
for _, item := range df.filterRule {
|
||||
// 数据源路径不识数组, 多个key写入到同一个map key, 并且map key 不是以[]结尾, 自动格式化
|
||||
// 目标位置, 是一个数组
|
||||
if df.pathIsArrayValue(item.MapKey) {
|
||||
realMapKey := strings.Trim(item.MapKey, ".[]")
|
||||
if exist := jsonObject.Exists(realMapKey); !exist {
|
||||
if _, err = jsonObject.ArrayP(realMapKey); nil != err {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
valueResult := gjson.Get(df.source, item.SourceKey)
|
||||
dataType := df.getValueType(valueResult)
|
||||
if _, exist := obg2slice[realMapKey]; !exist {
|
||||
obg2slice[realMapKey] = dataType
|
||||
}
|
||||
if dataType != obg2slice[realMapKey] {
|
||||
return "", errors.New(realMapKey + " 预期写入的字段数据类型不一致")
|
||||
}
|
||||
sourcePathArr := strings.Split(item.SourceKey, ".[].")
|
||||
mapPathArr := strings.Split(realMapKey, ".[].")
|
||||
|
||||
result := gabs.New()
|
||||
_, _ = result.ArrayP(mapPathArr[0])
|
||||
df.SetArrayData("{\""+sourcePathArr[0]+"\":"+gjson.Get(df.source, sourcePathArr[0]).String()+"}", result, sourcePathArr, mapPathArr)
|
||||
if err = jsonObject.ArrayAppend(valueResult.Value(), realMapKey); nil != err {
|
||||
for _, itemRule := range df.filterRule {
|
||||
sourceIsArr := df.isArrPath(itemRule.SourceKey)
|
||||
mapIsArr := df.isArrPath(itemRule.MapKey)
|
||||
if !sourceIsArr && !mapIsArr {
|
||||
// 输入输出均不是数组, 最简单的场景
|
||||
if err = df.setKV(itemRule); nil != err {
|
||||
return "", err
|
||||
}
|
||||
continue
|
||||
}
|
||||
sourceSearchResult := gjson.Get(df.source, item.SourceKey)
|
||||
if !sourceSearchResult.Exists() {
|
||||
if item.WithDefault {
|
||||
if _, err = jsonObject.SetP(item.DefaultValue, item.MapKey); nil != err {
|
||||
return "", err
|
||||
}
|
||||
sourcePathArr := df.getArrPathList(itemRule.SourceKey)
|
||||
mapPathArr := df.getArrPathList(itemRule.MapKey)
|
||||
if len(mapPathArr) > len(sourcePathArr) {
|
||||
df.logPrint(logLevelFatal, "映射的层级深度大于数据源深度", "source_path => "+itemRule.SourceKey, "map_path => "+itemRule.MapKey)
|
||||
return "", fmt.Errorf("映射的层级深度大于数据源深度, source_path => %v map_path => %v", itemRule.SourceKey, itemRule.MapKey)
|
||||
}
|
||||
|
||||
// 映射至非数组字段
|
||||
if !mapIsArr {
|
||||
if err = df.setValue(itemRule.MapKey, df.getDataAsSlice(df.source, df.getArrPathList(itemRule.SourceKey))); nil != err {
|
||||
df.logPrint(logLevelFatal, "映射非数组, 数据源为数组, 设置失败", "source_path => "+itemRule.SourceKey, "map_path => "+itemRule.MapKey, " err => "+err.Error())
|
||||
return "", fmt.Errorf("映射的层级深度大于数据源深度, source_path => %v map_path => %v", itemRule.SourceKey, itemRule.MapKey)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if _, err = jsonObject.SetP(sourceSearchResult.Value(), item.MapKey); nil != err {
|
||||
return "", err
|
||||
|
||||
if len(mapPathArr) == len(sourcePathArr) {
|
||||
// 数组深度一致
|
||||
continue
|
||||
}
|
||||
}
|
||||
return jsonObject.String(), nil
|
||||
df.logPrint(logLevelDebug, "过滤结果", df.rewriteResult)
|
||||
return gjson.Get(df.rewriteResult, virtualRoot).String(), nil
|
||||
}
|
||||
|
||||
// UserItemToSlice 支持多个独立的字段合并到slice中
|
||||
// isArrPath 是否为数组路径
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 3:27 PM 2022/1/24
|
||||
func (df *DataFilter) UserItemToSlice() {
|
||||
df.itemKeyToSlice = true
|
||||
}
|
||||
|
||||
// getValueType 获取数据类型
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2022/1/23 12:45 AM
|
||||
func (df *DataFilter) getValueType(valueResult gjson.Result) string {
|
||||
dataTypeVal := reflect.TypeOf(valueResult.Value())
|
||||
if nil == dataTypeVal {
|
||||
return "NIL"
|
||||
}
|
||||
dataType := dataTypeVal.String()
|
||||
if strings.Contains(dataType, "int") {
|
||||
return "int64"
|
||||
}
|
||||
if strings.Contains(dataType, "float") {
|
||||
return "float64"
|
||||
}
|
||||
return dataType
|
||||
}
|
||||
|
||||
// pathIsArrayValue 判断路径是否为数组值
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2022/1/23 12:56 AM
|
||||
func (df *DataFilter) pathIsArrayValue(path string) bool {
|
||||
// Date : 16:00 2023/9/1
|
||||
func (df *DataFilter) isArrPath(path string) bool {
|
||||
return strings.Contains(path, "[]")
|
||||
}
|
||||
|
||||
// formatRule 格式化映射规则
|
||||
// setSameDeepArr 展开同深度数组的
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2:43 PM 2022/1/24
|
||||
func (df *DataFilter) formatRule() {
|
||||
mapKeyCnt := make(map[string]int)
|
||||
for _, item := range df.filterRule {
|
||||
// source 为数组, map 不是
|
||||
if df.pathIsArrayValue(item.SourceKey) {
|
||||
if !df.pathIsArrayValue(item.MapKey) {
|
||||
item.MapKey = item.MapKey + ".[]"
|
||||
} else {
|
||||
// source 是数组, map也是数组, 检测数组层级匹配
|
||||
sourcePathArr := strings.Split(item.SourceKey, ".[].")
|
||||
mapPathArr := strings.Split(item.MapKey, ".[].")
|
||||
if len(sourcePathArr) == len(mapPathArr) {
|
||||
// 数组层级深度相同,无需特殊处理
|
||||
continue
|
||||
}
|
||||
// 数组层级深度不同,重新对对齐数据
|
||||
diffArr := sourcePathArr[0 : len(sourcePathArr)-len(mapPathArr)+1]
|
||||
if newPath := df.dealDiffArr(diffArr); len(newPath) > 0 {
|
||||
sourcePathArr[len(sourcePathArr)-len(mapPathArr)] = newPath
|
||||
item.SourceKey = strings.Join(sourcePathArr[len(sourcePathArr)-len(mapPathArr):], ".[].")
|
||||
}
|
||||
}
|
||||
// Date : 12:19 2023/9/2
|
||||
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)
|
||||
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
|
||||
}
|
||||
// 数组 展开
|
||||
for idx := 0; idx < len(mapPathArr); idx++ {
|
||||
if len(sourceRootPath) > 0 {
|
||||
sourceRootPath = fmt.Sprintf("%v.%v", sourceRootPath, sourcePathArr[idx])
|
||||
} else {
|
||||
if df.pathIsArrayValue(item.MapKey) {
|
||||
continue
|
||||
}
|
||||
// source 不是数组, map 也不是
|
||||
if !df.itemKeyToSlice {
|
||||
continue
|
||||
}
|
||||
mapKeyCnt[item.MapKey]++
|
||||
sourceRootPath = sourcePathArr[idx]
|
||||
}
|
||||
}
|
||||
// 多个source指向一个map,自动转化为list
|
||||
for _, item := range df.filterRule {
|
||||
if mapKeyCnt[item.MapKey] > 1 {
|
||||
item.MapKey = item.MapKey + ".[]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dealDiffArr 提取数据映射关系
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 5:04 下午 2022/1/25
|
||||
func (df *DataFilter) dealDiffArr(diffArr []string) string {
|
||||
if len(diffArr) == 0 {
|
||||
return ""
|
||||
}
|
||||
diffArrStr := strings.Join(diffArr, ".[].")
|
||||
if _, exist := df.hasDealDiffPath[diffArrStr]; exist {
|
||||
// 已经处理过, 不再重复处理
|
||||
return df.hasDealDiffPath[diffArrStr]
|
||||
}
|
||||
|
||||
// 没处理过, 开始处理
|
||||
jsonResultList := df.getArrayData(df.source, diffArr)
|
||||
if len(jsonResultList) == 0 {
|
||||
return ""
|
||||
}
|
||||
newPath := util.String.GenRandom("", 8)
|
||||
var result map[string]interface{}
|
||||
_ = json.Unmarshal([]byte(df.source), &result)
|
||||
JSONObject, _ := gabs.Consume(result)
|
||||
_, _ = JSONObject.ArrayP(newPath)
|
||||
for _, item := range jsonResultList {
|
||||
if err := JSONObject.ArrayAppendP(item.Value(), newPath); nil != err {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
df.source = JSONObject.String()
|
||||
df.hasDealDiffPath[diffArrStr] = newPath
|
||||
return newPath
|
||||
}
|
||||
|
||||
// getArrayData 获取数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2:22 下午 2022/1/26
|
||||
func (df *DataFilter) getArrayData(source string, pathArr []string) []gjson.Result {
|
||||
if len(pathArr) == 1 {
|
||||
return gjson.Get(source, pathArr[0]).Array()
|
||||
}
|
||||
resultList := make([]gjson.Result, 0)
|
||||
dataList := gjson.Get(source, pathArr[0]).Array()
|
||||
for idx := 0; idx < len(dataList); idx++ {
|
||||
resultList = append(resultList, df.getArrayData(dataList[idx].String(), pathArr[1:])...)
|
||||
}
|
||||
return resultList
|
||||
}
|
||||
|
||||
// SetArrayData 设置数组数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 5:05 下午 2022/2/2
|
||||
func (df *DataFilter) SetArrayData(sourceData string, jsonObject *gabs.Container, sourcePathArr []string, mapPathArr []string) *gabs.Container {
|
||||
jsonObject = gabs.New()
|
||||
|
||||
for idx, sourcePath := range sourcePathArr {
|
||||
if idx < len(sourcePathArr)-1 {
|
||||
if !jsonObject.Exists(sourcePath) {
|
||||
_, _ = jsonObject.ArrayP(sourcePath)
|
||||
}
|
||||
}
|
||||
instance, _ := gabs.ParseJSON([]byte(sourceData))
|
||||
if !instance.Exists() {
|
||||
fmt.Println(sourcePathArr[len(sourcePathArr)-1] + " 不存在")
|
||||
if len(mapRootPath) > 0 {
|
||||
mapRootPath = fmt.Sprintf("%v.%v", mapRootPath, mapPathArr[idx])
|
||||
} else {
|
||||
dataList, _ := instance.Children()
|
||||
for _, item := range dataList {
|
||||
cItem := gabs.New()
|
||||
cItem.SetP(gjson.Get(item.String(), sourcePath).String(), mapPathArr[idx])
|
||||
jsonObject.ArrayAppendP(cItem.Data(), mapPathArr[idx])
|
||||
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
|
||||
}
|
||||
//jsonObject.ArrayAppend(jsonObject.Data())
|
||||
// fmt.Println("数据 : ", jsonObject.String())
|
||||
// jsonObject.ArrayAppendP(result.Data(), mapPathArr[idx])
|
||||
result = append(result, r...)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// a.[].b.[].c.[].d
|
||||
// g
|
||||
// getDataAsSlice 抽取制定深度,生成list
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:17 2023/9/2
|
||||
func (df *DataFilter) getDataAsSlice(sourceData string, pathList []string) []interface{} {
|
||||
//fmt.Println(sourceData, pathList)
|
||||
result := make([]interface{}, 0)
|
||||
if len(pathList) == 0 {
|
||||
return result
|
||||
}
|
||||
if len(pathList) == 1 {
|
||||
return []interface{}{gjson.Get(sourceData, pathList[0]).Value()}
|
||||
}
|
||||
for idx, itemPath := range pathList {
|
||||
if len(pathList)-1 == idx {
|
||||
val := gjson.Get(sourceData, itemPath).Value()
|
||||
if nil == val {
|
||||
return result
|
||||
}
|
||||
result = append(result, val)
|
||||
return result
|
||||
}
|
||||
|
||||
df.SetArrayData(gjson.Get(sourceData, sourcePathArr[idx]).String(), jsonObject, sourcePathArr[idx+1:], mapPathArr[idx+1:])
|
||||
// jsonObject.ArrayAppendP(v.Data(), mapPathArr[idx])
|
||||
currentPathVal := gjson.Get(sourceData, itemPath).Array()
|
||||
for _, sonItem := range currentPathVal {
|
||||
result = append(result, df.getDataAsSlice(sonItem.String(), pathList[idx:])...)
|
||||
}
|
||||
}
|
||||
fmt.Println("最终 : ", jsonObject.String())
|
||||
return jsonObject
|
||||
return result
|
||||
}
|
||||
|
||||
// setValue 设置值
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 22:04 2023/9/1
|
||||
func (df *DataFilter) setValue(path string, value interface{}) error {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
df.rewriteResult, err = sjson.Set(df.rewriteResult, path, value)
|
||||
return err
|
||||
}
|
||||
|
||||
// setKV 设置相关值
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:03 2023/9/1
|
||||
func (df *DataFilter) setKV(rule *FilterDataRule) error {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
sourceValue := gjson.Get(df.source, rule.SourceKey)
|
||||
if sourceValue.Exists() {
|
||||
// 原始数据存在对应路径
|
||||
df.rewriteResult, err = sjson.Set(df.rewriteResult, rule.MapKey, sourceValue.Value())
|
||||
return err
|
||||
}
|
||||
if !rule.WithDefault {
|
||||
// 路径不存在, 且禁用默认值
|
||||
return errors.New(rule.SourceKey + " : source path not found, and default value is forbidden")
|
||||
}
|
||||
// 使用默认值填充
|
||||
df.rewriteResult, err = sjson.Set(df.rewriteResult, rule.MapKey, rule.DefaultValue)
|
||||
return err
|
||||
}
|
||||
|
||||
// getArrPathList 获取路径列表
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 21:32 2023/9/1
|
||||
func (df *DataFilter) getArrPathList(inputPath string) []string {
|
||||
pathArr := strings.Split(inputPath, "[]")
|
||||
arr := make([]string, 0)
|
||||
for _, item := range pathArr {
|
||||
arr = append(arr, strings.Trim(item, "."))
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// logPrint 打印日志
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:00 2023/9/1
|
||||
func (df *DataFilter) logPrint(level string, msg string, logAttr ...interface{}) {
|
||||
if !df.filterOption.DebugModel {
|
||||
// 未开启调试模式
|
||||
return
|
||||
}
|
||||
logData := append([]interface{}{level, msg}, logAttr...)
|
||||
log.Println(logData...)
|
||||
}
|
||||
|
||||
// 日志等级定义
|
||||
const (
|
||||
logLevelPanic = "PANIC"
|
||||
logLevelFatal = "FATAL"
|
||||
logLevelWarn = "WARN"
|
||||
logLevelInfo = "INFO"
|
||||
logLevelDebug = "DEBUG"
|
||||
)
|
||||
|
285
tool/gabs_test.go
Normal file
285
tool/gabs_test.go
Normal file
@ -0,0 +1,285 @@
|
||||
// Package json_tool ...
|
||||
//
|
||||
// Description : json_tool ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-09-01 16:07
|
||||
package json_tool
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
)
|
||||
|
||||
// TestDataFilter_FilterNormalData 最基础对象
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:13 2023/9/1
|
||||
func TestDataFilter_FilterNormalData(t *testing.T) {
|
||||
source := map[string]interface{}{
|
||||
"name": "zhangdeman",
|
||||
"extra": map[string]interface{}{
|
||||
"age": 18,
|
||||
"height": 180,
|
||||
"slice": []int{1, 2, 3},
|
||||
},
|
||||
"slice": []int{1, 2, 3},
|
||||
}
|
||||
df := &DataFilter{
|
||||
source: serialize.JSON.MarshalForString(source),
|
||||
filterRule: []*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},
|
||||
},
|
||||
filterOption: &FilterOption{DebugModel: true},
|
||||
}
|
||||
fmt.Println(df.Filter())
|
||||
}
|
||||
|
||||
// TestDataFilter_getDataAsSlice 测试循环读取数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 22:21 2023/9/1
|
||||
func TestDataFilter_getDataAsSlice(t *testing.T) {
|
||||
data := map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "1",
|
||||
"age": "2",
|
||||
"list_test": []interface{}{
|
||||
map[string]interface{}{
|
||||
"a": "a",
|
||||
"b": "b",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "3",
|
||||
"age": "4",
|
||||
"list_test": []interface{}{
|
||||
map[string]interface{}{
|
||||
"a": "a1",
|
||||
"b": "b1",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "5",
|
||||
"age": "6",
|
||||
},
|
||||
},
|
||||
}
|
||||
byteData, _ := json.Marshal(data)
|
||||
df := &DataFilter{}
|
||||
fmt.Println(df.getDataAsSlice(string(byteData), []string{"list", "name"}))
|
||||
fmt.Println(df.getDataAsSlice(string(byteData), []string{"list", "age"}))
|
||||
fmt.Println(df.getDataAsSlice(string(byteData), []string{"list", "age", "list_test", "a"}))
|
||||
fmt.Println(df.getDataAsSlice(string(byteData), []string{"list", "age", "list_test", "b"}))
|
||||
}
|
||||
|
||||
// TestDataFilter_sourceArrAndMapSingle map 非数组,数据源数组
|
||||
//
|
||||
// Author : zhangdeman001@ke.com<张德满>
|
||||
//
|
||||
// Date : 11:24 2023/9/2
|
||||
func TestDataFilter_sourceArrAndMapSingle(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{}{
|
||||
"name": "5",
|
||||
"age": "6",
|
||||
},
|
||||
},
|
||||
}
|
||||
df := &DataFilter{
|
||||
source: serialize.JSON.MarshalForString(source),
|
||||
filterRule: []*FilterDataRule{
|
||||
{SourceKey: "list.[].list_test.[].a", MapKey: "a_list", DefaultValue: "[]", WithDefault: true},
|
||||
{SourceKey: "list.[].list_test.[].b", MapKey: "b_list", DefaultValue: "[]", WithDefault: true},
|
||||
{SourceKey: "list.[].list_test.[].c", MapKey: "c_list", DefaultValue: "[]", WithDefault: true},
|
||||
{SourceKey: "list.[].list_test.[].d", MapKey: "d_list", DefaultValue: "[]", WithDefault: true},
|
||||
},
|
||||
filterOption: &FilterOption{DebugModel: true},
|
||||
}
|
||||
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()
|
||||
}
|
497
tool/gojson/json-to-struct.go
Normal file
497
tool/gojson/json-to-struct.go
Normal file
@ -0,0 +1,497 @@
|
||||
// Package gojson ...
|
||||
//
|
||||
// Description : json_tool ...
|
||||
//
|
||||
// Author : go_developer@163.com<张德满>
|
||||
//
|
||||
// Date : 2022-01-09 10:48 PM
|
||||
package gojson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var ForceFloats bool
|
||||
|
||||
// commonInitialisms is a set of common initialisms.
|
||||
// Only add entries that are highly unlikely to be non-initialisms.
|
||||
// For instance, "ID" is fine (Freudian code is rare), but "AND" is not.
|
||||
var commonInitialisms = map[string]bool{
|
||||
"API": true,
|
||||
"ASCII": true,
|
||||
"CPU": true,
|
||||
"CSS": true,
|
||||
"DNS": true,
|
||||
"EOF": true,
|
||||
"GUID": true,
|
||||
"HTML": true,
|
||||
"HTTP": true,
|
||||
"HTTPS": true,
|
||||
"ID": true,
|
||||
"IP": true,
|
||||
"JSON": true,
|
||||
"LHS": true,
|
||||
"QPS": true,
|
||||
"RAM": true,
|
||||
"RHS": true,
|
||||
"RPC": true,
|
||||
"SLA": true,
|
||||
"SMTP": true,
|
||||
"SSH": true,
|
||||
"TLS": true,
|
||||
"TTL": true,
|
||||
"UI": true,
|
||||
"UID": true,
|
||||
"UUID": true,
|
||||
"URI": true,
|
||||
"URL": true,
|
||||
"UTF8": true,
|
||||
"VM": true,
|
||||
"XML": true,
|
||||
"NTP": true,
|
||||
"DB": true,
|
||||
}
|
||||
|
||||
var intToWordMap = []string{
|
||||
"zero",
|
||||
"one",
|
||||
"two",
|
||||
"three",
|
||||
"four",
|
||||
"five",
|
||||
"six",
|
||||
"seven",
|
||||
"eight",
|
||||
"nine",
|
||||
}
|
||||
|
||||
type Parser func(io.Reader) (interface{}, error)
|
||||
|
||||
func ParseJson(input io.Reader) (interface{}, error) {
|
||||
var result interface{}
|
||||
if err := json.NewDecoder(input).Decode(&result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func ParseYaml(input io.Reader) (interface{}, error) {
|
||||
var result interface{}
|
||||
b, err := readFile(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := yaml.Unmarshal(b, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func readFile(input io.Reader) ([]byte, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
_, err := io.Copy(buf, input)
|
||||
if err != nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Generate a struct definition given a JSON string representation of an object and a name structName.
|
||||
func Generate(input io.Reader, parser Parser, structName, pkgName string, tags []string, subStruct bool, convertFloats bool) ([]byte, error) {
|
||||
var subStructMap map[string]string = nil
|
||||
if subStruct {
|
||||
subStructMap = make(map[string]string)
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
|
||||
iresult, err := parser(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch iresult := iresult.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
result = convertKeysToStrings(iresult)
|
||||
case map[string]interface{}:
|
||||
result = iresult
|
||||
case []interface{}:
|
||||
src := fmt.Sprintf("package %s\n\ntype %s %s\n",
|
||||
pkgName,
|
||||
structName,
|
||||
typeForValue(iresult, structName, tags, subStructMap, convertFloats))
|
||||
formatted, err := format.Source([]byte(src))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error formatting: %s, was formatting\n%s", err, src)
|
||||
}
|
||||
return formatted, err
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected type: %T", iresult)
|
||||
}
|
||||
|
||||
src := fmt.Sprintf("package %s\ntype %s %s}",
|
||||
pkgName,
|
||||
structName,
|
||||
generateTypes(result, structName, tags, 0, subStructMap, convertFloats))
|
||||
|
||||
keys := make([]string, 0, len(subStructMap))
|
||||
for key := range subStructMap {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
src = fmt.Sprintf("%v\n\ntype %v %v", src, subStructMap[k], k)
|
||||
}
|
||||
|
||||
formatted, err := format.Source([]byte(src))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error formatting: %s, was formatting\n%s", err, src)
|
||||
}
|
||||
return formatted, err
|
||||
}
|
||||
|
||||
func convertKeysToStrings(obj map[interface{}]interface{}) map[string]interface{} {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
for k, v := range obj {
|
||||
res[fmt.Sprintf("%v", k)] = v
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Generate go struct entries for a map[string]interface{} structure
|
||||
func generateTypes(obj map[string]interface{}, structName string, tags []string, depth int, subStructMap map[string]string, convertFloats bool) string {
|
||||
structure := "struct {"
|
||||
|
||||
keys := make([]string, 0, len(obj))
|
||||
for key := range obj {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
value := obj[key]
|
||||
valueType := typeForValue(value, structName, tags, subStructMap, convertFloats)
|
||||
|
||||
//value = mergeElements(value)
|
||||
|
||||
//If a nested value, recurse
|
||||
switch value := value.(type) {
|
||||
case []interface{}:
|
||||
if len(value) > 0 {
|
||||
sub := ""
|
||||
if v, ok := value[0].(map[interface{}]interface{}); ok {
|
||||
sub = generateTypes(convertKeysToStrings(v), structName, tags, depth+1, subStructMap, convertFloats) + "}"
|
||||
} else if v, ok := value[0].(map[string]interface{}); ok {
|
||||
sub = generateTypes(v, structName, tags, depth+1, subStructMap, convertFloats) + "}"
|
||||
}
|
||||
|
||||
if sub != "" {
|
||||
subName := sub
|
||||
|
||||
if subStructMap != nil {
|
||||
if val, ok := subStructMap[sub]; ok {
|
||||
subName = val
|
||||
} else {
|
||||
subName = fmt.Sprintf("%v_sub%v", structName, len(subStructMap)+1)
|
||||
|
||||
subStructMap[sub] = subName
|
||||
}
|
||||
}
|
||||
|
||||
valueType = "[]" + subName
|
||||
}
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
sub := generateTypes(convertKeysToStrings(value), structName, tags, depth+1, subStructMap, convertFloats) + "}"
|
||||
subName := sub
|
||||
|
||||
if subStructMap != nil {
|
||||
if val, ok := subStructMap[sub]; ok {
|
||||
subName = val
|
||||
} else {
|
||||
subName = fmt.Sprintf("%v_sub%v", structName, len(subStructMap)+1)
|
||||
|
||||
subStructMap[sub] = subName
|
||||
}
|
||||
}
|
||||
valueType = subName
|
||||
case map[string]interface{}:
|
||||
sub := generateTypes(value, structName, tags, depth+1, subStructMap, convertFloats) + "}"
|
||||
subName := sub
|
||||
|
||||
if subStructMap != nil {
|
||||
if val, ok := subStructMap[sub]; ok {
|
||||
subName = val
|
||||
} else {
|
||||
subName = fmt.Sprintf("%v_sub%v", structName, len(subStructMap)+1)
|
||||
|
||||
subStructMap[sub] = subName
|
||||
}
|
||||
}
|
||||
|
||||
valueType = subName
|
||||
}
|
||||
|
||||
fieldName := FmtFieldName(key)
|
||||
|
||||
tagList := make([]string, 0)
|
||||
for _, t := range tags {
|
||||
tagList = append(tagList, fmt.Sprintf("%s:\"%s\"", t, key))
|
||||
}
|
||||
|
||||
structure += fmt.Sprintf("\n%s %s `%s`",
|
||||
fieldName,
|
||||
valueType,
|
||||
strings.Join(tagList, " "))
|
||||
}
|
||||
return structure
|
||||
}
|
||||
|
||||
// FmtFieldName formats a string as a struct key
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// FmtFieldName("foo_id")
|
||||
//
|
||||
// Output: FooID
|
||||
func FmtFieldName(s string) string {
|
||||
runes := []rune(s)
|
||||
for len(runes) > 0 && !unicode.IsLetter(runes[0]) && !unicode.IsDigit(runes[0]) {
|
||||
runes = runes[1:]
|
||||
}
|
||||
if len(runes) == 0 {
|
||||
return "_"
|
||||
}
|
||||
|
||||
s = stringifyFirstChar(string(runes))
|
||||
name := lintFieldName(s)
|
||||
runes = []rune(name)
|
||||
for i, c := range runes {
|
||||
ok := unicode.IsLetter(c) || unicode.IsDigit(c)
|
||||
if i == 0 {
|
||||
ok = unicode.IsLetter(c)
|
||||
}
|
||||
if !ok {
|
||||
runes[i] = '_'
|
||||
}
|
||||
}
|
||||
s = string(runes)
|
||||
s = strings.Trim(s, "_")
|
||||
if len(s) == 0 {
|
||||
return "_"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func lintFieldName(name string) string {
|
||||
// Fast path for simple cases: "_" and all lowercase.
|
||||
if name == "_" {
|
||||
return name
|
||||
}
|
||||
|
||||
allLower := true
|
||||
for _, r := range name {
|
||||
if !unicode.IsLower(r) {
|
||||
allLower = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allLower {
|
||||
runes := []rune(name)
|
||||
if u := strings.ToUpper(name); commonInitialisms[u] {
|
||||
copy(runes[0:], []rune(u))
|
||||
} else {
|
||||
runes[0] = unicode.ToUpper(runes[0])
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
allUpperWithUnderscore := true
|
||||
for _, r := range name {
|
||||
if !unicode.IsUpper(r) && r != '_' {
|
||||
allUpperWithUnderscore = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allUpperWithUnderscore {
|
||||
name = strings.ToLower(name)
|
||||
}
|
||||
|
||||
// Split camelCase at any lower->upper transition, and split on underscores.
|
||||
// Check each word for common initialisms.
|
||||
runes := []rune(name)
|
||||
w, i := 0, 0 // index of start of word, scan
|
||||
for i+1 <= len(runes) {
|
||||
eow := false // whether we hit the end of a word
|
||||
|
||||
if i+1 == len(runes) {
|
||||
eow = true
|
||||
} else if runes[i+1] == '_' {
|
||||
// underscore; shift the remainder forward over any run of underscores
|
||||
eow = true
|
||||
n := 1
|
||||
for i+n+1 < len(runes) && runes[i+n+1] == '_' {
|
||||
n++
|
||||
}
|
||||
|
||||
// Leave at most one underscore if the underscore is between two digits
|
||||
if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) {
|
||||
n--
|
||||
}
|
||||
|
||||
copy(runes[i+1:], runes[i+n+1:])
|
||||
runes = runes[:len(runes)-n]
|
||||
} else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) {
|
||||
// lower->non-lower
|
||||
eow = true
|
||||
}
|
||||
i++
|
||||
if !eow {
|
||||
continue
|
||||
}
|
||||
|
||||
// [w,i) is a word.
|
||||
word := string(runes[w:i])
|
||||
if u := strings.ToUpper(word); commonInitialisms[u] {
|
||||
// All the common initialisms are ASCII,
|
||||
// so we can replace the bytes exactly.
|
||||
copy(runes[w:], []rune(u))
|
||||
|
||||
} else if strings.ToLower(word) == word {
|
||||
// already all lowercase, and not the first word, so uppercase the first character.
|
||||
runes[w] = unicode.ToUpper(runes[w])
|
||||
}
|
||||
w = i
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// generate an appropriate struct type entry
|
||||
func typeForValue(value interface{}, structName string, tags []string, subStructMap map[string]string, convertFloats bool) string {
|
||||
//Check if this is an array
|
||||
if objects, ok := value.([]interface{}); ok {
|
||||
types := make(map[reflect.Type]bool, 0)
|
||||
for _, o := range objects {
|
||||
types[reflect.TypeOf(o)] = true
|
||||
}
|
||||
if len(types) == 1 {
|
||||
return "[]" + typeForValue(mergeElements(objects).([]interface{})[0], structName, tags, subStructMap, convertFloats)
|
||||
}
|
||||
return "[]interface{}"
|
||||
} else if object, ok := value.(map[interface{}]interface{}); ok {
|
||||
return generateTypes(convertKeysToStrings(object), structName, tags, 0, subStructMap, convertFloats) + "}"
|
||||
} else if object, ok := value.(map[string]interface{}); ok {
|
||||
return generateTypes(object, structName, tags, 0, subStructMap, convertFloats) + "}"
|
||||
} else if reflect.TypeOf(value) == nil {
|
||||
return "interface{}"
|
||||
}
|
||||
v := reflect.TypeOf(value).Name()
|
||||
if v == "float64" && convertFloats {
|
||||
v = disambiguateFloatInt(value)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// All numbers will initially be read as float64
|
||||
// If the number appears to be an integer value, use int instead
|
||||
func disambiguateFloatInt(value interface{}) string {
|
||||
const epsilon = .0001
|
||||
vfloat := value.(float64)
|
||||
if !ForceFloats && math.Abs(vfloat-math.Floor(vfloat+epsilon)) < epsilon {
|
||||
var tmp int64
|
||||
return reflect.TypeOf(tmp).Name()
|
||||
}
|
||||
return reflect.TypeOf(value).Name()
|
||||
}
|
||||
|
||||
// convert first character ints to strings
|
||||
func stringifyFirstChar(str string) string {
|
||||
first := str[:1]
|
||||
|
||||
i, err := strconv.ParseInt(first, 10, 8)
|
||||
|
||||
if err != nil {
|
||||
return str
|
||||
}
|
||||
|
||||
return intToWordMap[i] + "_" + str[1:]
|
||||
}
|
||||
|
||||
func mergeElements(i interface{}) interface{} {
|
||||
switch i := i.(type) {
|
||||
default:
|
||||
return i
|
||||
case []interface{}:
|
||||
l := len(i)
|
||||
if l == 0 {
|
||||
return i
|
||||
}
|
||||
for j := 1; j < l; j++ {
|
||||
i[0] = mergeObjects(i[0], i[j])
|
||||
}
|
||||
return i[0:1]
|
||||
}
|
||||
}
|
||||
|
||||
func mergeObjects(o1, o2 interface{}) interface{} {
|
||||
if o1 == nil {
|
||||
return o2
|
||||
}
|
||||
|
||||
if o2 == nil {
|
||||
return o1
|
||||
}
|
||||
|
||||
if reflect.TypeOf(o1) != reflect.TypeOf(o2) {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch i := o1.(type) {
|
||||
default:
|
||||
return o1
|
||||
case []interface{}:
|
||||
if i2, ok := o2.([]interface{}); ok {
|
||||
i3 := append(i, i2...)
|
||||
return mergeElements(i3)
|
||||
}
|
||||
return mergeElements(i)
|
||||
case map[string]interface{}:
|
||||
if i2, ok := o2.(map[string]interface{}); ok {
|
||||
for k, v := range i2 {
|
||||
if v2, ok := i[k]; ok {
|
||||
i[k] = mergeObjects(v2, v)
|
||||
} else {
|
||||
i[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return i
|
||||
case map[interface{}]interface{}:
|
||||
if i2, ok := o2.(map[interface{}]interface{}); ok {
|
||||
for k, v := range i2 {
|
||||
if v2, ok := i[k]; ok {
|
||||
i[k] = mergeObjects(v2, v)
|
||||
} else {
|
||||
i[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
}
|
@ -42,15 +42,6 @@ func TestJSON(t *testing.T) {
|
||||
fmt.Println(tree.String())
|
||||
}
|
||||
|
||||
// TestType 判断数据类型断言
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:59 下午 2021/3/14
|
||||
func TestType(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
// TestSelect 测试动态选择字段
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
@ -127,151 +118,3 @@ func TestParse(t *testing.T) {
|
||||
byteData, _ := json.Marshal(source)
|
||||
fmt.Println(GetJSONDataStruct(string(byteData)))
|
||||
}
|
||||
|
||||
// TestParseWithType 测试获取JSON数据结构
|
||||
//
|
||||
// Author : go_developer@163.com<张德满>
|
||||
//
|
||||
// Date : 10:59 PM 2022/1/9
|
||||
func TestParseWithType(t *testing.T) {
|
||||
source := map[string]interface{}{
|
||||
"name": "zhangdeman",
|
||||
"extra": map[string]interface{}{
|
||||
"age": 18,
|
||||
"height": 180,
|
||||
"slice": []int{1, 2, 3},
|
||||
"obj": map[string]interface{}{
|
||||
"la": "aaaa",
|
||||
},
|
||||
},
|
||||
"slice": []int{1, 2, 3},
|
||||
"map": map[string]interface{}{"a": 1, "d": 5.5, "e": "qqq"},
|
||||
"empty_obj": map[string]interface{}{},
|
||||
"empty_list": make([]interface{}, 0),
|
||||
"table": []map[string]interface{}{
|
||||
{"name": "alex", "age": 18, "number": 1, "obj": map[string]interface{}{"enen": "en"}},
|
||||
{"name": "bob", "age": 28, "number": 2},
|
||||
},
|
||||
"two_slice": []map[string]interface{}{
|
||||
{
|
||||
"students": []map[string]interface{}{
|
||||
{
|
||||
"name": "enen",
|
||||
"age": 18,
|
||||
"score": []float64{1, 2, 3, 45},
|
||||
},
|
||||
},
|
||||
"other": []interface{}{"others"},
|
||||
"read_only": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
byteData, _ := json.Marshal(source)
|
||||
fmt.Println(GetJSONDataStructWithType(string(byteData)))
|
||||
}
|
||||
|
||||
// TestDataFilter 测试数据过滤
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2022/1/22 10:19 PM
|
||||
func TestDataFilter(t *testing.T) {
|
||||
source := map[string]interface{}{
|
||||
"name": "zhangdeman",
|
||||
"extra": map[string]interface{}{
|
||||
"age": 18,
|
||||
"height": 180,
|
||||
"slice": []int{1, 2, 3},
|
||||
},
|
||||
"slice_data": []int{1, 2, 3},
|
||||
"map": map[string]interface{}{"a": 1, "b": 2, "c": 4},
|
||||
"table": []map[string]interface{}{
|
||||
{"name": "alex", "age": 18, "number": 1},
|
||||
{"name": "bob", "age": 28, "number": 2},
|
||||
{"name": "bob", "age": 28, "number": 2, "list": []int{1, 2, 3}},
|
||||
},
|
||||
}
|
||||
rule := []*FilterDataRule{
|
||||
{SourceKey: "name", MapKey: "user_name", DefaultValue: "用户姓名默认值"},
|
||||
{SourceKey: "name", MapKey: "username", DefaultValue: "用户姓名默认值"},
|
||||
{SourceKey: "name", MapKey: "user.name", DefaultValue: "用户姓名默认值"},
|
||||
{SourceKey: "extra.age", MapKey: "user.age", DefaultValue: "用户年龄默认值"},
|
||||
{SourceKey: "extra.age", MapKey: "user_age", DefaultValue: "用户年龄默认值"},
|
||||
{SourceKey: "extra.height", MapKey: "user.height", DefaultValue: "扩展高度默认值"},
|
||||
{SourceKey: "extra.height", MapKey: "user_height", DefaultValue: "扩展高度默认值"},
|
||||
{SourceKey: "table.[].name", MapKey: "slice.[].name_modify", DefaultValue: "列表姓名默认值"},
|
||||
{SourceKey: "table.[].list", MapKey: "slice.[].data_list", DefaultValue: "[\"567\",\"678\",\"789\"]"},
|
||||
}
|
||||
byteData, _ := json.Marshal(source)
|
||||
filter := NewDataFilter(string(byteData), rule)
|
||||
fmt.Println(filter.Filter())
|
||||
}
|
||||
|
||||
// TestDataFilterForObiToSlice ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2022/1/23 12:06 AM
|
||||
func TestDataFilterForObiToSlice(t *testing.T) {
|
||||
source := map[string]interface{}{
|
||||
"name": "zhangdeman",
|
||||
"age": 18,
|
||||
"height": 180,
|
||||
"extra": map[string]interface{}{
|
||||
"age": 18,
|
||||
"height": 180,
|
||||
"slice": []int{1, 2, 3},
|
||||
},
|
||||
"slice_data": []int{1, 2, 3},
|
||||
"map": map[string]interface{}{"a": 1, "b": 2, "c": 4},
|
||||
"table": []map[string]interface{}{
|
||||
{"name": "alex", "age": 18, "number": 1},
|
||||
{"name": "bob", "age": 28, "number": 2},
|
||||
{"name": "bob", "age": 28, "number": 2, "list": []int{1, 2, 3}},
|
||||
},
|
||||
}
|
||||
rule := []*FilterDataRule{
|
||||
// {SourceKey: "name", MapKey: "slice.[]", DefaultValue: "用户姓名默认值"},
|
||||
{SourceKey: "age", MapKey: "slice", DefaultValue: "用户姓名默认值"},
|
||||
{SourceKey: "height", MapKey: "slice", DefaultValue: "用户姓名默认值"},
|
||||
}
|
||||
byteData, _ := json.Marshal(source)
|
||||
filter := NewDataFilter(string(byteData), rule)
|
||||
filter.UserItemToSlice()
|
||||
fmt.Println(filter.Filter())
|
||||
}
|
||||
|
||||
// TestDataFilterDiffArr ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:27 下午 2022/1/26
|
||||
func TestDataFilterDiffArr(t *testing.T) {
|
||||
source := map[string]interface{}{
|
||||
"name": "zhangdeman",
|
||||
"age": 18,
|
||||
"height": 180,
|
||||
"extra": map[string]interface{}{
|
||||
"age": 18,
|
||||
"height": 180,
|
||||
"slice": []int{1, 2, 3},
|
||||
},
|
||||
"slice_data": []int{1, 2, 3},
|
||||
"map": map[string]interface{}{"a": 1, "b": 2, "c": 4},
|
||||
"table": []map[string]interface{}{
|
||||
{"user_list": []interface{}{map[string]interface{}{"name": "alex", "age": 18, "number": 1}}},
|
||||
{"user_list": []interface{}{map[string]interface{}{"name": "bob", "age": 28, "number": 2}}},
|
||||
{"user_list": []interface{}{map[string]interface{}{"name": "andy", "age": 28, "number": 2}}},
|
||||
},
|
||||
}
|
||||
rule := []*FilterDataRule{
|
||||
// {SourceKey: "name", MapKey: "slice.[]", DefaultValue: "用户姓名默认值"},
|
||||
{SourceKey: "table.[].user_list.[].name", MapKey: "user_list.[].detail.name", DefaultValue: "用户姓名默认值"},
|
||||
{SourceKey: "table.[].user_list.[].age", MapKey: "user_list.[].detail.age", DefaultValue: "用户姓名默认值"},
|
||||
}
|
||||
byteData, _ := json.Marshal(source)
|
||||
filter := NewDataFilter(string(byteData), rule)
|
||||
filter.UserItemToSlice()
|
||||
filter.Filter()
|
||||
//fmt.Println()
|
||||
}
|
||||
|
@ -117,7 +117,11 @@ func GetJSONDataStructWithType(data string) ([]Field, error) {
|
||||
}
|
||||
pathList := make([]Field, 0)
|
||||
r := gjson.Parse(data)
|
||||
inputIsArr := r.IsArray()
|
||||
r.ForEach(func(key, value gjson.Result) bool {
|
||||
if inputIsArr && key.Int() > 0 {
|
||||
return true
|
||||
}
|
||||
if value.Value() == nil {
|
||||
pathList = append(pathList, Field{
|
||||
Path: key.String(),
|
||||
@ -183,6 +187,11 @@ func GetJSONDataStructWithType(data string) ([]Field, error) {
|
||||
|
||||
return true
|
||||
})
|
||||
for idx := 0; idx < len(pathList); idx++ {
|
||||
if inputIsArr && strings.HasPrefix(pathList[idx].Path, "0.") {
|
||||
pathList[idx].Path = strings.Replace(pathList[idx].Path, "0.", "[].", 1)
|
||||
}
|
||||
}
|
||||
return pathList, nil
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ package tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.zhangdeman.cn/zhangdeman/util"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@ -88,7 +88,7 @@ func (g *Generate) init() error {
|
||||
fmt.Println(jsonKey, valueType, jsonValue, startIndex)
|
||||
// 创建节点, 并挂在到树上
|
||||
var newNode *Node
|
||||
if util.Array.In(g.currentNode.ValueType, []string{ValueTypeArray, ValueTypeMap}) >= 0 {
|
||||
if wrapper.ArrayType([]string{ValueTypeArray, ValueTypeMap}).Has(g.currentNode.ValueType) >= 0 {
|
||||
newNode = NewNode(jsonKey, jsonValue, valueType, g.currentNode)
|
||||
g.currentParentNode = g.currentNode
|
||||
g.currentParentNode.SonNodeList = append(g.currentParentNode.SonNodeList, newNode)
|
||||
@ -116,25 +116,26 @@ func (g *Generate) getKey(startIndex int) (string, int, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
if charStr == KeywordDoubleQuote && !hasStart {
|
||||
// 第一次遇见双引号
|
||||
startIndex++
|
||||
hasStart = true
|
||||
continue
|
||||
}
|
||||
if charStr == KeywordDoubleQuote && hasStart {
|
||||
// 第二次遇见双引号,key探寻结束
|
||||
startIndex++
|
||||
break
|
||||
if charStr == KeywordDoubleQuote {
|
||||
if !hasStart {
|
||||
// 第一次遇见双引号
|
||||
startIndex++
|
||||
hasStart = true
|
||||
continue
|
||||
} else {
|
||||
// 第二次遇见双引号,key探寻结束
|
||||
startIndex++
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasStart {
|
||||
if util.Array.In(charStr, []string{
|
||||
if wrapper.ArrayType([]string{
|
||||
KeywordDoubleQuote,
|
||||
KeywordObjectStart,
|
||||
KeywordArrayStart,
|
||||
KeywordComma,
|
||||
}) >= 0 {
|
||||
}).Has(charStr) >= 0 {
|
||||
startIndex++
|
||||
continue
|
||||
}
|
||||
@ -181,21 +182,18 @@ func (g *Generate) getValueType(startIndex int) (string, int, error) {
|
||||
hasFindColon := false
|
||||
for startIndex < len(g.jsonDataByte) {
|
||||
charStr := string(g.jsonDataByte[startIndex])
|
||||
if !hasFindColon {
|
||||
if charStr == KeywordSpace {
|
||||
// 跳过空格
|
||||
startIndex++
|
||||
continue
|
||||
}
|
||||
if charStr != KeywordSpace {
|
||||
// 非空格
|
||||
if charStr != KeywordColon {
|
||||
return "", startIndex, errors.New("value is invalid")
|
||||
}
|
||||
startIndex++
|
||||
hasFindColon = true
|
||||
break
|
||||
if charStr == KeywordSpace {
|
||||
// 跳过空格
|
||||
startIndex++
|
||||
continue
|
||||
} else {
|
||||
// 非空格
|
||||
if charStr != KeywordColon {
|
||||
return "", startIndex, errors.New("value is invalid")
|
||||
}
|
||||
startIndex++
|
||||
hasFindColon = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,13 +262,13 @@ func (g *Generate) getValue(startIndex int) (string, int, error) {
|
||||
continue
|
||||
}
|
||||
if !isStart {
|
||||
if util.Array.In(str, []string{KeywordArrayEnd, KeywordObjectEnd, KeywordComma}) >= 0 {
|
||||
if wrapper.ArrayType([]string{KeywordArrayEnd, KeywordObjectEnd, KeywordComma}).Has(str) >= 0 {
|
||||
startIndex++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if isStart {
|
||||
if util.Array.In(str, []string{KeywordDoubleQuote, KeywordArrayEnd, KeywordObjectEnd, KeywordComma}) >= 0 {
|
||||
if wrapper.ArrayType([]string{KeywordDoubleQuote, KeywordArrayEnd, KeywordObjectEnd, KeywordComma}).Has(str) >= 0 {
|
||||
// 值的拼接已结束
|
||||
startIndex++
|
||||
break
|
||||
|
Reference in New Issue
Block a user