重命名json工具包
This commit is contained in:
378
json_tool/build.go
Normal file
378
json_tool/build.go
Normal file
@ -0,0 +1,378 @@
|
||||
// Package json_tool...
|
||||
//
|
||||
// Description : 动态构建json
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2021-03-10 10:26 下午
|
||||
package json_tool
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/gopkg/easylock"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// PathSplit json_tool 路径的分割符
|
||||
PathSplit = "."
|
||||
)
|
||||
|
||||
// JSONode JSOM节点
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:33 下午 2021/3/10
|
||||
type JSONode struct {
|
||||
Key string // json_tool key
|
||||
Value interface{} // 对应的值
|
||||
Child []*JSONode // 子节点
|
||||
IsRoot bool // 是否根节点
|
||||
IsHasLastBrother bool // 在此之后是否有其他兄弟节点
|
||||
IsSlice bool // 是否是list
|
||||
IsIndexNode bool // 是否是slice的索引节点
|
||||
Sort int // 此属性用于 slice解析,保证最终排序是对的
|
||||
IsComplex bool // 是否为复杂数据类型
|
||||
IsString bool // 是否为字符串
|
||||
}
|
||||
|
||||
// NewDynamicJSON 获取JSON实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:36 下午 2021/3/10
|
||||
func NewDynamicJSON() *DynamicJSON {
|
||||
exp, _ := regexp.Compile(`\[(\d*?)]`)
|
||||
return &DynamicJSON{
|
||||
root: &JSONode{
|
||||
Key: "",
|
||||
Value: nil,
|
||||
Child: nil,
|
||||
IsRoot: true,
|
||||
},
|
||||
nodeCnt: 0,
|
||||
lock: easylock.NewLock(),
|
||||
sliceExp: exp,
|
||||
}
|
||||
}
|
||||
|
||||
// DynamicJSON 动态json
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:03 下午 2021/3/10
|
||||
type DynamicJSON struct {
|
||||
root *JSONode // 节点数
|
||||
nodeCnt int // 节点数量
|
||||
lock easylock.EasyLock // 锁
|
||||
sliceExp *regexp.Regexp // 抽取slice索引的正则
|
||||
}
|
||||
|
||||
// SetValue 设置节点值,如果节点不存在,创建;如果已存在,更新, 多级key使用, value 必须是基础数据类型, 如果是结构体, 需要继续添加path,多级path使用.分割
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:45 下午 2021/3/10
|
||||
func (dj *DynamicJSON) SetValue(path string, value interface{}, isComplexType bool) {
|
||||
pathList := strings.Split(path, PathSplit)
|
||||
searchRoot := dj.root
|
||||
parent := dj.root
|
||||
for keyIndex, key := range pathList {
|
||||
searchRoot = dj.search(searchRoot, key)
|
||||
if nil != searchRoot {
|
||||
// 查询到结果,更新值
|
||||
searchRoot.Value = value
|
||||
parent = searchRoot
|
||||
continue
|
||||
}
|
||||
var val interface{}
|
||||
if keyIndex == len(pathList)-1 {
|
||||
val = value
|
||||
}
|
||||
_ = dj.createNode(parent, key, val, isComplexType)
|
||||
if len(parent.Child) > 0 {
|
||||
searchRoot = parent.Child[len(parent.Child)-1]
|
||||
parent = parent.Child[len(parent.Child)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String 获取字符串的格式JSON
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2:16 下午 2021/3/11
|
||||
func (dj *DynamicJSON) String() string {
|
||||
tplList := make([]string, 0)
|
||||
valList := make([]interface{}, 0)
|
||||
tplListResult, valListResult := dj.buildTpl(dj.root, &tplList, &valList)
|
||||
return fmt.Sprintf(strings.Join(*tplListResult, ""), *valListResult...)
|
||||
}
|
||||
|
||||
// Map 转化为map
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 9:59 上午 2021/9/9
|
||||
func (dj *DynamicJSON) Map() (map[string]interface{}, error) {
|
||||
var res map[string]interface{}
|
||||
err := json.Unmarshal([]byte(dj.String()), &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Slice 转化为slice
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 9:59 上午 2021/9/9
|
||||
func (dj *DynamicJSON) Slice() ([]interface{}, error) {
|
||||
var res []interface{}
|
||||
err := json.Unmarshal([]byte(dj.String()), &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// ParseWithReceiver 使用指定结构解析
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:01 上午 2021/9/9
|
||||
func (dj *DynamicJSON) ParseWithReceiver(receiver interface{}) error {
|
||||
if nil == receiver {
|
||||
return errors.New("receiver is nil")
|
||||
}
|
||||
return json.Unmarshal([]byte(dj.String()), receiver)
|
||||
}
|
||||
|
||||
// buildTpl 构建json模版与绑定数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 4:38 下午 2021/3/11
|
||||
func (dj *DynamicJSON) buildTpl(root *JSONode, tplList *[]string, valList *[]interface{}) (*[]string, *[]interface{}) {
|
||||
if nil == root {
|
||||
return tplList, valList
|
||||
}
|
||||
startSymbol := dj.getStartSymbol(root)
|
||||
endSymbol := dj.getEndSymbol(root)
|
||||
valFormat := dj.getValFormat(root)
|
||||
// key := "\"" + root.Key + "\""
|
||||
if !root.IsIndexNode {
|
||||
if len(root.Child) > 0 {
|
||||
*tplList = append(*tplList, startSymbol)
|
||||
} else {
|
||||
*tplList = append(*tplList, valFormat)
|
||||
*valList = append(*valList, root.Value)
|
||||
return tplList, valList
|
||||
}
|
||||
} else {
|
||||
if len(root.Child) == 0 {
|
||||
*tplList = append(*tplList, valFormat)
|
||||
*valList = append(*valList, root.Value)
|
||||
} else {
|
||||
*tplList = append(*tplList, startSymbol)
|
||||
}
|
||||
}
|
||||
for _, node := range root.Child {
|
||||
dj.buildTpl(node, tplList, valList)
|
||||
}
|
||||
*tplList = append(*tplList, endSymbol)
|
||||
|
||||
return tplList, valList
|
||||
}
|
||||
|
||||
// getValFormat 构建值得占位符
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:49 下午 2021/3/13
|
||||
func (dj *DynamicJSON) getValFormat(root *JSONode) string {
|
||||
key := fmt.Sprintf("\"%s\"", root.Key)
|
||||
if !root.IsIndexNode {
|
||||
if len(root.Child) > 0 {
|
||||
// 还有自节点的情况下,不需要占位符
|
||||
return ""
|
||||
}
|
||||
|
||||
if root.IsHasLastBrother {
|
||||
if root.IsString {
|
||||
return key + ":\"%v\","
|
||||
}
|
||||
return key + ":%v,"
|
||||
}
|
||||
if root.IsString {
|
||||
return key + ":\"%v\""
|
||||
}
|
||||
return key + ":%v"
|
||||
}
|
||||
|
||||
if len(root.Child) > 0 {
|
||||
// 是list的索引节点,且有子节点
|
||||
return ""
|
||||
}
|
||||
if root.IsHasLastBrother {
|
||||
if root.IsString {
|
||||
return "\"%v\","
|
||||
}
|
||||
return "%v,"
|
||||
}
|
||||
if root.IsString {
|
||||
return "\"%v\""
|
||||
}
|
||||
return "%v"
|
||||
}
|
||||
|
||||
// getStartSymbol 计算起始的符号
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:21 下午 2021/3/13
|
||||
func (dj *DynamicJSON) getStartSymbol(root *JSONode) string {
|
||||
if nil == root {
|
||||
return "{"
|
||||
}
|
||||
|
||||
if root.IsRoot {
|
||||
if root.IsSlice {
|
||||
return "["
|
||||
}
|
||||
return "{"
|
||||
}
|
||||
key := fmt.Sprintf("\"%s\"", root.Key)
|
||||
if !root.IsIndexNode {
|
||||
if len(root.Child) > 0 {
|
||||
|
||||
if root.IsSlice {
|
||||
return key + ":["
|
||||
} else {
|
||||
return key + ":{"
|
||||
}
|
||||
|
||||
}
|
||||
return ""
|
||||
}
|
||||
if len(root.Child) > 0 {
|
||||
return "{"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getEndSymbol 计算结束的符号
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:21 下午 2021/3/13
|
||||
func (dj *DynamicJSON) getEndSymbol(root *JSONode) string {
|
||||
if nil == root {
|
||||
return "}"
|
||||
}
|
||||
if !root.IsIndexNode {
|
||||
if root.IsHasLastBrother {
|
||||
return "},"
|
||||
}
|
||||
if root.IsSlice {
|
||||
return "]"
|
||||
} else {
|
||||
return "}"
|
||||
}
|
||||
|
||||
}
|
||||
if len(root.Child) > 0 {
|
||||
if root.IsHasLastBrother {
|
||||
return "},"
|
||||
}
|
||||
return "}"
|
||||
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Search 搜索一个key TODO : 优化
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:19 下午 2021/3/10
|
||||
func (dj *DynamicJSON) search(root *JSONode, key string) *JSONode {
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
for _, node := range root.Child {
|
||||
if node == nil {
|
||||
continue
|
||||
}
|
||||
if node.Key == key {
|
||||
return node
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// createNode 创建新的节点
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:57 下午 2021/3/10
|
||||
func (dj *DynamicJSON) createNode(parent *JSONode, key string, value interface{}, isComplexType bool) error {
|
||||
if nil == parent {
|
||||
return errors.New("create node error : parent id nil")
|
||||
}
|
||||
_ = dj.lock.Lock()
|
||||
if parent.Child == nil {
|
||||
parent.Child = make([]*JSONode, 0)
|
||||
}
|
||||
if len(parent.Child) > 0 {
|
||||
// 存在子节点,设置当前子节点还有其他兄弟节点
|
||||
parent.Child[len(parent.Child)-1].IsHasLastBrother = true
|
||||
}
|
||||
|
||||
newNode := &JSONode{
|
||||
Key: key,
|
||||
Value: value,
|
||||
Child: make([]*JSONode, 0),
|
||||
IsRoot: false,
|
||||
IsHasLastBrother: false,
|
||||
IsComplex: isComplexType,
|
||||
IsString: false,
|
||||
}
|
||||
if !isComplexType {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
newNode.IsString = true
|
||||
}
|
||||
}
|
||||
parent.IsSlice, newNode.Sort = dj.extraSliceIndex(key)
|
||||
if parent.IsSlice {
|
||||
newNode.IsIndexNode = true
|
||||
}
|
||||
parent.Child = append(parent.Child, newNode)
|
||||
dj.nodeCnt++
|
||||
_ = dj.lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// extraSliceIndex 抽取slice索引
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 9:37 下午 2021/3/11
|
||||
func (dj *DynamicJSON) extraSliceIndex(key string) (bool, int) {
|
||||
if len(key) < 3 {
|
||||
// slice 至少是 [1] 格式
|
||||
return false, 0
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(key, "[") || !strings.HasSuffix(key, "]") {
|
||||
return false, 0
|
||||
}
|
||||
// 不用正则,直接字符串处理
|
||||
strByte := []byte(key)
|
||||
index, err := strconv.Atoi(string(strByte[1 : len(strByte)-1]))
|
||||
if nil != err {
|
||||
return false, 0
|
||||
}
|
||||
return true, index
|
||||
}
|
117
json_tool/parse.go
Normal file
117
json_tool/parse.go
Normal file
@ -0,0 +1,117 @@
|
||||
// Package json_tool ...
|
||||
//
|
||||
// Description : 将复杂数据结构转化为 JSONNode 树
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2021-03-14 10:40 下午
|
||||
package json_tool
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/gopkg/util"
|
||||
)
|
||||
|
||||
// NewParseJSONTree 获取解析的实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:43 下午 2021/3/14
|
||||
func NewParseJSONTree(data interface{}) *ParseJSONTree {
|
||||
return &ParseJSONTree{data: data}
|
||||
}
|
||||
|
||||
// ParseJSONTree 解析json树
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:41 下午 2021/3/14
|
||||
type ParseJSONTree struct {
|
||||
data interface{}
|
||||
}
|
||||
|
||||
// Parse 解析数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:44 下午 2021/3/14
|
||||
func (pjt *ParseJSONTree) Parse(pathList []string) (*DynamicJSON, error) {
|
||||
if !pjt.isLegalData() {
|
||||
return nil, errors.New("非法的数据,无法转换成json")
|
||||
}
|
||||
result := NewDynamicJSON()
|
||||
byteData, _ := json.Marshal(pjt.data)
|
||||
source := string(byteData)
|
||||
for _, path := range pathList {
|
||||
// 为数组的处理
|
||||
pathArr := strings.Split(path, ".[].")
|
||||
val := gjson.Get(source, pathArr[0])
|
||||
isComplexType := val.IsArray() || val.IsObject()
|
||||
if len(pathArr) == 1 {
|
||||
result.SetValue(pathArr[0], val.Raw, isComplexType)
|
||||
continue
|
||||
}
|
||||
// 支持list再抽取一层,处于性能考虑,这么限制,不做递归无限深度处理
|
||||
// 还能继续抽取,就认为是 []map[string]interface{}
|
||||
ketList := strings.Split(pathArr[1], "|")
|
||||
for idx, item := range val.Array() {
|
||||
data := item.Map()
|
||||
for _, key := range ketList {
|
||||
if v, exist := data[key]; exist {
|
||||
result.SetValue(fmt.Sprintf(pathArr[0]+".[%d]."+key, idx), data[key].Raw, v.IsObject() || v.IsArray())
|
||||
}
|
||||
// 结果集中不存在对应key,丢弃
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// isLegalData 判断是否能转换成json结构, 只有slice/map/struct/能转换成slice或map的[]byte是合法的
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 10:46 下午 2021/3/14
|
||||
func (pjt *ParseJSONTree) isLegalData() bool {
|
||||
val := reflect.ValueOf(pjt.data)
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Slice:
|
||||
// slice 情况下,对字节数组进行特殊判断
|
||||
var (
|
||||
byteData []byte
|
||||
ok bool
|
||||
err error
|
||||
)
|
||||
if byteData, ok = pjt.data.([]byte); ok {
|
||||
// 字节数组转map或者slice
|
||||
if err = json.Unmarshal(byteData, &pjt.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 pjt.data, err = util.StructToMap(pjt.data); nil != err {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user