gopkg/json/build.go

332 lines
7.4 KiB
Go
Raw Normal View History

2021-03-11 00:05:56 +08:00
// Package json...
//
// Description : 动态构建json
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 00:05:56 +08:00
//
// Date : 2021-03-10 10:26 下午
package json
import (
2021-03-11 17:02:44 +08:00
"fmt"
2021-03-11 22:12:14 +08:00
"regexp"
"strconv"
2021-03-11 00:05:56 +08:00
"strings"
2021-07-25 18:50:56 +08:00
"git.zhangdeman.cn/zhangdeman/gopkg/easylock"
2021-03-11 00:05:56 +08:00
"github.com/pkg/errors"
)
const (
// PathSplit json 路径的分割符
PathSplit = "."
)
// JSONode JSOM节点
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 00:05:56 +08:00
//
// Date : 10:33 下午 2021/3/10
type JSONode struct {
2021-03-11 17:02:44 +08:00
Key string // json key
Value interface{} // 对应的值
Child []*JSONode // 子节点
IsRoot bool // 是否根节点
IsHasLastBrother bool // 在此之后是否有其他兄弟节点
2021-03-11 22:12:14 +08:00
IsSlice bool // 是否是list
2021-03-12 23:08:48 +08:00
IsIndexNode bool // 是否是slice的索引节点
2021-03-11 22:12:14 +08:00
Sort int // 此属性用于 slice解析,保证最终排序是对的
IsComplex bool // 是否为复杂数据类型
IsString bool // 是否为字符串
2021-03-11 00:05:56 +08:00
}
// NewDynamicJSON 获取JSON实例
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 00:05:56 +08:00
//
// Date : 10:36 下午 2021/3/10
func NewDynamicJSON() *DynamicJSON {
2021-03-11 22:12:14 +08:00
exp, _ := regexp.Compile(`\[(\d*?)]`)
2021-03-11 00:05:56 +08:00
return &DynamicJSON{
root: &JSONode{
Key: "",
Value: nil,
Child: nil,
IsRoot: true,
},
2021-03-11 22:12:14 +08:00
nodeCnt: 0,
lock: easylock.NewLock(),
sliceExp: exp,
2021-03-11 00:05:56 +08:00
}
}
// DynamicJSON 动态json
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 00:05:56 +08:00
//
// Date : 11:03 下午 2021/3/10
type DynamicJSON struct {
2021-03-11 22:12:14 +08:00
root *JSONode // 节点数
nodeCnt int // 节点数量
lock easylock.EasyLock // 锁
sliceExp *regexp.Regexp // 抽取slice索引的正则
2021-03-11 00:05:56 +08:00
}
// SetValue 设置节点值,如果节点不存在,创建;如果已存在,更新, 多级key使用, value 必须是基础数据类型, 如果是结构体, 需要继续添加path,多级path使用.分割
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 00:05:56 +08:00
//
// Date : 10:45 下午 2021/3/10
func (dj *DynamicJSON) SetValue(path string, value interface{}, isComplexType bool) {
2021-03-11 00:05:56 +08:00
pathList := strings.Split(path, PathSplit)
searchRoot := dj.root
parent := dj.root
for keyIndex, key := range pathList {
searchRoot = dj.search(searchRoot, key)
if nil != searchRoot {
2021-03-11 17:02:44 +08:00
searchRoot.Value = value // 查询到结果,更新值
2021-03-11 00:05:56 +08:00
parent = searchRoot
} else {
var val interface{}
if keyIndex == len(pathList)-1 {
val = value
}
_ = dj.createNode(parent, key, val, isComplexType)
2021-03-12 23:08:48 +08:00
if len(parent.Child) > 0 {
searchRoot = parent.Child[len(parent.Child)-1]
parent = parent.Child[len(parent.Child)-1]
}
2021-03-11 00:05:56 +08:00
}
}
}
2021-03-11 17:02:44 +08:00
// String 获取字符串的格式JSON
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 17:02:44 +08:00
//
// 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...)
}
// buildTpl 构建json模版与绑定数据
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 17:02:44 +08:00
//
// Date : 4:38 下午 2021/3/11
func (dj *DynamicJSON) buildTpl(root *JSONode, tplList *[]string, valList *[]interface{}) (*[]string, *[]interface{}) {
if nil == root {
return tplList, valList
}
2021-03-13 13:27:30 +08:00
startSymbol := dj.getStartSymbol(root)
endSymbol := dj.getEndSymbol(root)
valFormat := dj.getValFormat(root)
2021-03-13 12:56:55 +08:00
// key := "\"" + root.Key + "\""
2021-03-12 23:08:48 +08:00
if !root.IsIndexNode {
if len(root.Child) > 0 {
2021-03-13 13:27:30 +08:00
*tplList = append(*tplList, startSymbol)
2021-03-11 17:02:44 +08:00
} else {
2021-03-13 13:27:30 +08:00
*tplList = append(*tplList, valFormat)
*valList = append(*valList, root.Value)
2021-03-12 23:08:48 +08:00
return tplList, valList
2021-03-11 17:02:44 +08:00
}
} else {
2021-03-12 23:28:28 +08:00
if len(root.Child) == 0 {
*tplList = append(*tplList, valFormat)
*valList = append(*valList, root.Value)
2021-03-12 23:28:28 +08:00
} else {
2021-03-13 13:27:30 +08:00
*tplList = append(*tplList, startSymbol)
2021-03-12 23:28:28 +08:00
}
2021-03-11 17:02:44 +08:00
}
for _, node := range root.Child {
dj.buildTpl(node, tplList, valList)
}
2021-03-13 13:27:30 +08:00
*tplList = append(*tplList, endSymbol)
2021-03-13 12:37:38 +08:00
return tplList, valList
}
2021-03-13 12:56:55 +08:00
// getValFormat 构建值得占位符
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-13 12:56:55 +08:00
//
// 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 ""
}
2021-03-13 12:56:55 +08:00
if root.IsHasLastBrother {
return key + ":%v,"
}
return key + ":%v"
}
if len(root.Child) > 0 {
// 是list的索引节点,且有子节点
return ""
}
if root.IsHasLastBrother {
return "%v,"
2021-03-13 12:56:55 +08:00
}
return "%v"
2021-03-13 12:56:55 +08:00
}
2021-03-13 12:37:38 +08:00
// getStartSymbol 计算起始的符号
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-13 12:37:38 +08:00
//
// Date : 12:21 下午 2021/3/13
func (dj *DynamicJSON) getStartSymbol(root *JSONode) string {
if nil == root {
return "{"
}
if root.IsRoot {
if root.IsSlice {
return "["
}
2021-03-13 12:37:38 +08:00
return "{"
}
key := fmt.Sprintf("\"%s\"", root.Key)
2021-03-12 23:28:28 +08:00
if !root.IsIndexNode {
2021-03-13 12:37:38 +08:00
if len(root.Child) > 0 {
2021-03-12 23:28:28 +08:00
if root.IsSlice {
2021-03-13 12:37:38 +08:00
return key + ":["
2021-03-12 23:28:28 +08:00
} else {
2021-03-13 12:37:38 +08:00
return key + ":{"
2021-03-12 23:28:28 +08:00
}
2021-03-13 12:37:38 +08:00
2021-03-12 23:28:28 +08:00
}
2021-03-13 12:37:38 +08:00
return ""
}
if len(root.Child) > 0 {
return "{"
}
return ""
}
// getEndSymbol 计算结束的符号
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-13 12:37:38 +08:00
//
// Date : 12:21 下午 2021/3/13
func (dj *DynamicJSON) getEndSymbol(root *JSONode) string {
2021-03-13 13:27:30 +08:00
if nil == root {
return "}"
}
2021-03-13 12:37:38 +08:00
if !root.IsIndexNode {
if root.IsHasLastBrother {
return "},"
2021-03-11 22:12:14 +08:00
}
2021-03-13 12:37:38 +08:00
if root.IsSlice {
return "]"
} else {
return "}"
}
2021-03-11 17:02:44 +08:00
}
2021-03-13 12:37:38 +08:00
if len(root.Child) > 0 {
if root.IsHasLastBrother {
return "},"
}
return "}"
2021-03-12 23:28:28 +08:00
2021-03-13 12:37:38 +08:00
}
return ""
2021-03-11 17:02:44 +08:00
}
2021-03-11 00:05:56 +08:00
// Search 搜索一个key TODO : 优化
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 00:05:56 +08:00
//
// 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 创建新的节点
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 00:05:56 +08:00
//
// Date : 10:57 下午 2021/3/10
func (dj *DynamicJSON) createNode(parent *JSONode, key string, value interface{}, isComplexType bool) error {
2021-03-11 00:05:56 +08:00
if nil == parent {
return errors.New("create node error : parent id nil")
}
2021-04-13 21:53:36 +08:00
_ = dj.lock.Lock()
2021-03-11 00:05:56 +08:00
if parent.Child == nil {
parent.Child = make([]*JSONode, 0)
}
2021-03-11 17:02:44 +08:00
if len(parent.Child) > 0 {
// 存在子节点,设置当前子节点还有其他兄弟节点
parent.Child[len(parent.Child)-1].IsHasLastBrother = true
}
2021-03-12 23:08:48 +08:00
newNode := &JSONode{
2021-03-11 17:02:44 +08:00
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
}
2021-03-12 23:08:48 +08:00
}
parent.IsSlice, newNode.Sort = dj.extraSliceIndex(key)
if parent.IsSlice {
newNode.IsIndexNode = true
}
parent.Child = append(parent.Child, newNode)
2021-03-11 00:05:56 +08:00
dj.nodeCnt++
2021-04-13 21:53:36 +08:00
_ = dj.lock.Unlock()
2021-03-11 00:05:56 +08:00
return nil
}
2021-03-11 22:12:14 +08:00
// extraSliceIndex 抽取slice索引
//
2021-07-25 19:05:59 +08:00
// Author : go_developer@163.com<白茶清欢>
2021-03-11 22:12:14 +08:00
//
// Date : 9:37 下午 2021/3/11
func (dj *DynamicJSON) extraSliceIndex(key string) (bool, int) {
if len(key) < 3 {
// slice 至少是 [1] 格式
return false, 0
}
2021-03-12 13:53:06 +08:00
if !strings.HasPrefix(key, "[") || !strings.HasSuffix(key, "]") {
2021-03-11 22:12:14 +08:00
return false, 0
}
2021-03-12 13:53:06 +08:00
// 不用正则,直接字符串处理
strByte := []byte(key)
2021-03-11 22:12:14 +08:00
index, err := strconv.Atoi(string(strByte[1 : len(strByte)-1]))
if nil != err {
return false, 0
}
return true, index
}