Merge pull request '优化自动生成json' (#3) from feature/tree into master

Reviewed-on: #3
This commit is contained in:
白茶清欢 2023-05-05 16:10:38 +08:00
commit a83ef6a1b2
8 changed files with 602 additions and 62 deletions

113
filter.go
View File

@ -10,14 +10,13 @@ package filter
import (
"encoding/json"
"fmt"
"git.zhangdeman.cn/zhangdeman/wrapper"
"strings"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"errors"
"git.zhangdeman.cn/zhangdeman/util"
)
// NewFilter 过滤器实例
@ -64,17 +63,7 @@ func (f *filter) Deal() error {
continue
}
sourceResult := gjson.Get(f.sourceData, rule.SourcePath)
var (
sourceVal string
)
if !sourceResult.Exists() {
// 不存在, 使用默认值
sourceVal = rule.DefaultValue
} else {
sourceVal = sourceResult.String()
}
if formatVal, err = f.getValue(rule.DataType, sourceVal); nil != err {
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 {
@ -183,56 +172,60 @@ func (f *filter) Parse(receiver interface{}) error {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:25 2022/7/4
func (f *filter) getValue(dataType string, defaultValue string) (interface{}, error) {
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 "int8":
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 "int16":
case wrapper.DataTypeFloat:
fallthrough
case "int32":
fallthrough
case "int64":
fallthrough
case "int":
var (
err error
val int64
)
err = util.ConvertAssign(&val, defaultValue)
return val, err
case "uint8":
fallthrough
case "uint16":
fallthrough
case "uint32":
fallthrough
case "uint64":
fallthrough
case "uint":
var (
err error
val uint64
)
err = util.ConvertAssign(&val, defaultValue)
return val, err
case "bool":
var (
err error
val bool
)
err = util.ConvertAssign(&val, defaultValue)
return val, err
case "float32":
fallthrough
case "float64":
var (
err error
val float64
)
err = util.ConvertAssign(&val, defaultValue)
return val, err
case "string":
return defaultValue, nil
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!")
}

7
go.mod
View File

@ -1,10 +1,10 @@
module git.zhangdeman.cn/zhangdeman/json_filter
go 1.17
go 1.18
require (
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20220627070212-c590a0a1c216
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230211164227-256094968151
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230505025924-96532aff0019
github.com/Jeffail/gabs v1.4.0
github.com/pkg/errors v0.9.1
github.com/smartystreets/goconvey v1.7.2
@ -13,12 +13,15 @@ require (
)
require (
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20230505080742-fa2f27724d76 // 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/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/spaolacci/murmur3 v1.1.0 // indirect

16
go.sum
View File

@ -3,6 +3,18 @@ git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20220627070212-c590a0a1c216/go.mod
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=
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
@ -18,6 +30,10 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
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/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=

3
tree/REDME.md Normal file
View File

@ -0,0 +1,3 @@
# 说明
基于JSON数据生成数据树

73
tree/consts.go Normal file
View File

@ -0,0 +1,73 @@
// Package tree ...
//
// Description : tree ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2023-03-28 18:32
package tree
const (
// KeywordObjectStart 对象开始标识
KeywordObjectStart = "{"
// KeywordObjectEnd 对象结束标识
KeywordObjectEnd = "}"
// KeywordArrayStart 数组开始标识
KeywordArrayStart = "["
// KeywordArrayEnd 数组结束标识
KeywordArrayEnd = "]"
// KeywordColon 冒号
KeywordColon = ":"
// KeywordComma 逗号
KeywordComma = ","
// KeywordDot .
KeywordDot = "."
// KeywordDoubleQuote 双引号
KeywordDoubleQuote = `"`
// KeywordEscapeSymbol 转义符号
KeywordEscapeSymbol = `\`
// KeywordSpace 空格
KeywordSpace = " "
// KeywordMinus 负号
KeywordMinus = "-"
// KeywordTrueStart true的起始值
KeywordTrueStart = "t"
// KeywordFalseStart false的起始值
KeywordFalseStart = "f"
KeywordZero = "0"
KeywordOne = "1"
KeywordTwo = "2"
KeywordThree = "3"
KeywordFour = "4"
KeywordFive = "5"
KeywordSix = "6"
KeywordSeven = "7"
KeywordEight = "8"
KeywordNine = "9"
)
const (
// ValueTypeString 字符串类型
ValueTypeString = "string"
// ValueTypeBool bool类型
ValueTypeBool = "bool"
// ValueTypeInteger int类型
ValueTypeInteger = "int64"
// ValueTypeFloat float类型
ValueTypeFloat = "float64"
// ValueTypeNumber 数字
ValueTypeNumber = "number"
// ValueTypeMap map数据
ValueTypeMap = "map"
// ValueTypeArray 数组
ValueTypeArray = "array"
)
// isBaseDataType 是否为基础数据类型
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 23:16 2023/3/28
func isBaseDataType(valueType string) bool {
return valueType != ValueTypeArray && valueType != ValueTypeMap
}

321
tree/generate.go Normal file
View File

@ -0,0 +1,321 @@
// Package tree ...
//
// Description : tree ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2023-03-28 18:42
package tree
import (
"fmt"
"git.zhangdeman.cn/zhangdeman/util"
"strings"
"github.com/pkg/errors"
)
// New 生成一棵JSON树
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:42 2023/3/28
func New(jsonData string) (*Generate, error) {
jsonData = strings.TrimSpace(jsonData)
g := &Generate{
jsonData: jsonData,
jsonDataByte: []byte(jsonData),
}
g.root = NewVirtualNode()
g.currentNode = g.root
g.currentParentNode = g.root
err := g.init()
return g, err
}
// Generate ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 22:46 2023/3/28
type Generate struct {
root *Node // 根节点
currentNode *Node // 当前节点
currentParentNode *Node // 当前节点的父节点
jsonData string
jsonDataByte []byte
}
// init 初始化
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 21:23 2023/3/29
func (g *Generate) init() error {
startIndex := 0
var (
jsonKey string
err error
valueType string
jsonValue string
)
// 获取类型
if valueType, startIndex, err = g.getValueType(startIndex); nil != err {
return err
}
g.root.ValueType = valueType
g.currentNode.ValueType = valueType
for {
if startIndex >= len(g.jsonDataByte) {
break
}
// 获取字段
if jsonKey, startIndex, err = g.getKey(startIndex); nil != err {
return err
}
// 获取类型
if valueType, startIndex, err = g.getValueType(startIndex); nil != err {
return err
}
// 获取值
if jsonValue, startIndex, err = g.getValue(startIndex); nil != err {
return err
}
fmt.Println(jsonKey, valueType, jsonValue, startIndex)
// 创建节点, 并挂在到树上
var newNode *Node
if util.Array.In(g.currentNode.ValueType, []string{ValueTypeArray, ValueTypeMap}) >= 0 {
newNode = NewNode(jsonKey, jsonValue, valueType, g.currentNode)
g.currentParentNode = g.currentNode
g.currentParentNode.SonNodeList = append(g.currentParentNode.SonNodeList, newNode)
} else {
newNode = NewNode(jsonKey, jsonValue, valueType, g.currentParentNode)
}
g.currentNode = newNode
}
return nil
}
// getKey 获取jsonKey TODO : 转义符识别
//
// Author : zhangdeman001@ke.com<张德满>
//
// Date : 11:36 2023/3/29
func (g *Generate) getKey(startIndex int) (string, int, error) {
keyCharList := make([]string, 0)
hasStart := false
for startIndex < len(g.jsonDataByte) {
charStr := string(g.jsonDataByte[startIndex])
if charStr == KeywordSpace && !hasStart {
// 跳过空格
startIndex++
continue
}
if charStr == KeywordDoubleQuote && !hasStart {
// 第一次遇见双引号
startIndex++
hasStart = true
continue
}
if charStr == KeywordDoubleQuote && hasStart {
// 第二次遇见双引号key探寻结束
startIndex++
break
}
if !hasStart {
if util.Array.In(charStr, []string{
KeywordDoubleQuote,
KeywordObjectStart,
KeywordArrayStart,
KeywordComma,
}) >= 0 {
startIndex++
continue
}
return "", startIndex, errors.New("parse key : format is invalid")
}
if charStr == KeywordEscapeSymbol {
// 转义符
startIndex++
if startIndex >= len(g.jsonDataByte) {
// 转义符后面没东西了
return "", startIndex, errors.New("escape symbol without any data")
}
charStr = string(g.jsonDataByte[startIndex])
}
keyCharList = append(keyCharList, charStr)
startIndex++
}
jsonKey := strings.Join(keyCharList, "")
return jsonKey, startIndex, nil
}
// getValueType 获取数据类型
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:37 2023/3/29
func (g *Generate) getValueType(startIndex int) (string, int, error) {
if startIndex == 0 {
// 初始对象特殊处理
if string(g.jsonDataByte[0]) == KeywordArrayStart {
return ValueTypeArray, 1, nil
}
// 初始对象特殊处理
if string(g.jsonDataByte[0]) == KeywordObjectStart {
return ValueTypeMap, 1, nil
}
return "", 0, errors.New("root data parse : value is invalid")
}
// 指针向后, 探寻到冒号之后第一个非空格字符串
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 !hasFindColon {
return "", startIndex, errors.New("check json value type : value is invalid")
}
keyValType := ""
// 冒号后面探寻值的类型
for startIndex < len(g.jsonDataByte) {
charStr := string(g.jsonDataByte[startIndex])
if charStr == KeywordSpace {
// 跳过空格
startIndex++
continue
}
// 非空
switch charStr {
case KeywordMinus:
fallthrough
case KeywordOne:
fallthrough
case KeywordTwo:
fallthrough
case KeywordThree:
fallthrough
case KeywordFour:
fallthrough
case KeywordFive:
fallthrough
case KeywordSix:
fallthrough
case KeywordSeven:
fallthrough
case KeywordEight:
fallthrough
case KeywordNine:
keyValType = ValueTypeNumber
case KeywordDoubleQuote:
keyValType = ValueTypeString
case KeywordArrayStart:
keyValType = ValueTypeArray
case KeywordObjectStart:
keyValType = ValueTypeMap
default:
return "", startIndex, errors.New("validate json value type : value type is invalid")
}
break
}
return keyValType, startIndex, nil
}
// getValue 获取JSON值
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:09 2023/3/30
func (g *Generate) getValue(startIndex int) (string, int, error) {
valArr := make([]string, 0)
isStart := false
for startIndex < len(g.jsonDataByte) {
str := string(g.jsonDataByte[startIndex])
if str == KeywordSpace && !isStart {
startIndex++
continue
}
if !isStart {
if util.Array.In(str, []string{KeywordArrayEnd, KeywordObjectEnd, KeywordComma}) >= 0 {
startIndex++
continue
}
}
if isStart {
if util.Array.In(str, []string{KeywordDoubleQuote, KeywordArrayEnd, KeywordObjectEnd, KeywordComma}) >= 0 {
// 值的拼接已结束
startIndex++
break
}
}
if str == KeywordDoubleQuote {
if isStart {
startIndex++
break
} else {
startIndex++
isStart = true
continue
}
}
isStart = true
if str == KeywordEscapeSymbol {
// 转义符
startIndex++
if startIndex >= len(g.jsonDataByte) {
// 转义符后面没东西了
return "", startIndex, errors.New("escape symbol without any data")
}
str = string(g.jsonDataByte[startIndex])
}
valArr = append(valArr, str)
startIndex++
}
return strings.Join(valArr, ""), startIndex, nil
}
// isObject 整体是否为对象
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 22:51 2023/3/28
func (g *Generate) isObject() bool {
return strings.HasPrefix(g.jsonData, KeywordObjectStart)
}
// isArray 整体是否为数组
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 22:51 2023/3/28
func (g *Generate) isArray() bool {
return strings.HasPrefix(g.jsonData, KeywordArrayStart)
}

23
tree/generate_test.go Normal file
View File

@ -0,0 +1,23 @@
// Package tree ...
//
// Description : tree ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2023-03-29 21:32
package tree
import (
"fmt"
"testing"
)
func TestNew(t *testing.T) {
jsonData := `{"name": "zhang", "age":17}`
g, err := New(jsonData)
if nil != err {
fmt.Println(err.Error())
return
}
fmt.Println(g)
}

108
tree/node.go Normal file
View File

@ -0,0 +1,108 @@
// Package tree ...
//
// Description : tree ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2023-03-28 18:12
package tree
import (
"strings"
"git.zhangdeman.cn/zhangdeman/util"
)
// Node 节点的数据结构
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:12 2023/3/28
type Node struct {
IsVirtual bool // 是否虚拟节点, 主要应对输入的原始数据为list这一场景
Value interface{} // 节点的值
ValueType string // 数据类型 string / int64 / float64 / map / list / nil
Key string // 节点的key名称(输入的原始名称)
Show bool // 节点是否可见
ShowKey string // 重新序列化后, 对外输出的Key
AllowEdit bool // 当前key是否允许编辑
AllowChangeType bool // 在允许编辑的情况下, 是否允许修改数据类型
DefaultValue interface{} // 输入为value为nil时候的默认值
ParentNode *Node // 父节点
PreBrotherNode *Node // 前一个兄弟节点
LastBrotherNode *Node // 下一个兄弟节点
SonNodeList []*Node // 子节点列表
ObjectStack []string // 对象信息堆栈, 利用栈的括号匹配, 判断某一个对象是否扫面完成
}
// NewNode 创建新节点
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 23:02 2023/3/28
func NewNode(key string, value string, valueType string, parentNode *Node) *Node {
n := &Node{
IsVirtual: false,
Value: value,
ValueType: valueType,
Key: key,
Show: false,
ShowKey: "",
AllowEdit: false,
AllowChangeType: false,
DefaultValue: nil,
ParentNode: parentNode,
PreBrotherNode: nil,
LastBrotherNode: nil,
SonNodeList: nil,
ObjectStack: make([]string, 0),
}
switch valueType {
case ValueTypeString:
n.Value = value
case ValueTypeInteger:
var v int64
_ = util.ConvertAssign(&v, value)
n.Value = v
case ValueTypeFloat:
var v float64
_ = util.ConvertAssign(&v, value)
n.Value = v
case ValueTypeBool:
n.Value = strings.ToLower(value) == "true"
case ValueTypeMap:
n.Value = map[string]interface{}{}
n.SonNodeList = make([]*Node, 0)
case ValueTypeArray:
n.Value = []interface{}{}
n.SonNodeList = make([]*Node, 0)
}
// 处理 preBrother 和 lastBrother
if parentNode.ValueType == ValueTypeMap || parentNode.ValueType == ValueTypeArray {
// map 和 array 才有所谓的兄弟节点
if len(parentNode.SonNodeList) > 0 {
// 设置新节点的 pre 节点
n.PreBrotherNode = parentNode.SonNodeList[len(parentNode.SonNodeList)-1]
// 设置当前最后一个节点的 last 节点
parentNode.SonNodeList[len(parentNode.SonNodeList)-1].LastBrotherNode = n
}
// 新节点追加到子节点末尾
parentNode.SonNodeList = append(parentNode.SonNodeList, n)
}
return n
}
// NewVirtualNode 创建一个新的虚拟节点
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 23:08 2023/3/28
func NewVirtualNode() *Node {
return &Node{
IsVirtual: true,
SonNodeList: make([]*Node, 0),
ObjectStack: make([]string, 0),
}
}