diff --git a/define.go b/define.go index 877b057..a80d083 100644 --- a/define.go +++ b/define.go @@ -7,63 +7,15 @@ // Date : 2022-07-04 18:02 package filter -import ( - "fmt" - - "git.zhangdeman.cn/zhangdeman/util" -) - -// jsonNode json语法树节点定义 +// MapRule 映射规则 // // Author : go_developer@163.com<白茶清欢> // -// Date : 18:06 2022/7/4 -type jsonNode struct { - Name string // 节点名称 - Parent *jsonNode // 父节点 - Son *jsonNode // 子节点 - PreBrother *jsonNode // 前一个兄弟节点 - NextBrother *jsonNode // 下一个兄弟节点 - Val interface{} // 节点的值 - Type string // 数据类型 +// 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 } - -// lexicalNode 词法分析的节点 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 18:02 2022/7/4 -type lexicalNode struct { - Val interface{} // 词法分析出来的词 - Type string // 值得类型 - Show bool // 这个值是否对外呈现 - IsToken bool // 是否为关键字 - OutputFormat string // 对外输出的格式 -} - -// ValStr 值转为字符串 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:10 2022/7/5 -func (l *lexicalNode) ValStr() string { - if l.Type == "number" { - var str string - _ = util.ConvertAssign(&str, l.Val) - return str - } - return fmt.Sprintf("%v", l.Val) -} - -const ( - // NodeTypeNumber 数据类型 - NodeTypeNumber = "number" - // NodeTypeBool bool 类型 - NodeTypeBool = "bool" - // NodeTypeString 字符串类型 - NodeTypeString = "string" - // NodeTypeObject kv 对象类型 - NodeTypeObject = "object" - // NodeTypeList list类型 - NodeTypeList = "list" -) diff --git a/filter.go b/filter.go index 3cfcd26..6c39c0f 100644 --- a/filter.go +++ b/filter.go @@ -8,28 +8,18 @@ package filter import ( + "encoding/json" "fmt" "strings" + "github.com/tidwall/sjson" + + "errors" + "git.zhangdeman.cn/zhangdeman/util" - "github.com/Jeffail/gabs" - "github.com/pkg/errors" "github.com/tidwall/gjson" ) -// 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 -} - // NewFilter 过滤器实例 // // Author : go_developer@163.com<白茶清欢> @@ -38,8 +28,8 @@ type MapRule struct { func NewFilter(sourceData string, filterRuleList []MapRule) *filter { return &filter{ sourceData: sourceData, + formatResult: "{}", filterRuleList: filterRuleList, - jsonObj: &gabs.Container{}, } } @@ -50,8 +40,8 @@ func NewFilter(sourceData string, filterRuleList []MapRule) *filter { // Date : 11:58 2022/7/4 type filter struct { sourceData string + formatResult string filterRuleList []MapRule - jsonObj *gabs.Container // 生成的json对象实例 } // Deal ... @@ -59,27 +49,133 @@ type filter struct { // Author : go_developer@163.com<白茶清欢> // // Date : 11:59 2022/7/4 -func (f *filter) Deal() ([]byte, error) { +func (f *filter) Deal() error { + var ( + err error + formatVal interface{} + ) + for _, rule := range f.filterRuleList { - if strings.Contains(rule.SourcePath, "[]") { + if f.IsArray(rule) { // 对于list的处理 + if err = f.handleArray(rule); nil != err { + return err + } continue } sourceResult := gjson.Get(f.sourceData, rule.SourcePath) - sourceVal := sourceResult.String() + var ( + sourceVal string + ) + if !sourceResult.Exists() { // 不存在, 使用默认值 sourceVal = rule.DefaultValue + } else { + sourceVal = sourceResult.String() } - formatVal, err := f.getValue(rule.DataType, sourceVal) - if nil != err { - return nil, fmt.Errorf("%s = %v can not convert to %s : %s", rule.SourcePath, sourceResult.Value(), rule.DataType, err.Error()) + if formatVal, err = f.getValue(rule.DataType, sourceVal); nil != err { + return fmt.Errorf("%s = %v can not convert to %s : %s", rule.SourcePath, sourceResult.Value(), rule.DataType, err.Error()) } - if _, err := f.jsonObj.SetP(formatVal, rule.MapPath); nil != err { - return nil, fmt.Errorf("%s set val = %v fail : %s", rule.MapPath, formatVal, err.Error()) + if f.formatResult, err = sjson.Set(f.formatResult, rule.MapPath, formatVal); nil != err { + return err } } - return f.jsonObj.EncodeJSON(), nil + return nil +} + +// IsArray 判断是否为数组 +// +// Author : zhangdeman001@ke.com<张德满> +// +// Date : 17:48 2023/1/1 +func (f *filter) IsArray(rule MapRule) bool { + return strings.Contains(rule.SourcePath, "[]") +} + +// handleArray 处理数组(最复杂的场景) +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 17:41 2023/1/1 +func (f *filter) handleArray(rule MapRule) error { + var ( + err error + ) + + sourcePathArray := strings.Split(rule.SourcePath, "[]") + for idx, item := range sourcePathArray { + sourcePathArray[idx] = strings.Trim(item, ".") + } + mapPathArray := strings.Split(strings.TrimRight(rule.MapPath, ".[]"), "[]") + for idx, item := range mapPathArray { + mapPathArray[idx] = strings.Trim(item, ".") + } + 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 { + return err + } + return nil + } + return nil +} + +// extraFinalResult 提取全部最底层结果 +// +// Author : zhangdeman001@ke.com<张德满> +// +// Date : 14:00 2023/1/2 +func (f *filter) getAllFinalData(res *[]string, resultList []gjson.Result, pathArr []string) { + if len(pathArr) == 1 { + for _, item := range resultList { + *res = append(*res, item.Get(pathArr[0]).String()) + } + return + } + for _, item := range resultList { + f.getAllFinalData(res, item.Array(), pathArr[1:]) + } + return +} + +// String 获取格式化之后的字符串 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 21:18 2022/12/31 +func (f *filter) String() string { + return f.formatResult +} + +// Byte 获取格式化之后的字节数组 +// +// Author : zhangdeman001@ke.com<张德满> +// +// Date : 21:18 2022/12/31 +func (f *filter) Byte() []byte { + return []byte(f.String()) +} + +// Parse 解析返回结果 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 21:20 2022/12/31 +func (f *filter) Parse(receiver interface{}) error { + if nil == receiver { + return errors.New("receiver is nil") + } + return json.Unmarshal(f.Byte(), receiver) } // getValue 获取值 @@ -141,4 +237,3 @@ func (f *filter) getValue(dataType string, defaultValue string) (interface{}, er return nil, errors.New(dataType + " is not support!") } } - diff --git a/filter_test.go b/filter_test.go new file mode 100644 index 0000000..ae15bf8 --- /dev/null +++ b/filter_test.go @@ -0,0 +1,160 @@ +// Package filter ... +// +// Description : filter ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2023-01-01 17:00 +package filter + +import ( + "fmt" + "testing" + + "github.com/smartystreets/goconvey/convey" +) + +// TestNewFilter ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 17:00 2023/1/1 +func TestNewFilter(t *testing.T) { + var ( + err error + ) + testData := `{ + "base":{ + "name":"go_developer", + "age":18, + "height":180 + }, + "company":{ + "name":"wajijiwa", + "start":"2023-01-01" + } +}` + filterRuleList := []MapRule{ + { + SourcePath: "base.name", + MapPath: "user_name", + Required: true, + DataType: "string", + DefaultValue: "", + }, + { + SourcePath: "base.age", + MapPath: "user_age", + Required: true, + DataType: "int", + DefaultValue: "", + }, + { + SourcePath: "base.height", + MapPath: "user_height", + Required: true, + DataType: "string", + DefaultValue: "", + }, + { + SourcePath: "company.name", + MapPath: "company_name", + Required: true, + DataType: "string", + DefaultValue: "", + }, + { + SourcePath: "company.start", + MapPath: "company_start", + Required: true, + DataType: "string", + DefaultValue: "", + }, + } + f := NewFilter(testData, filterRuleList) + convey.Convey("基础对象重写", t, func() { + err = f.Deal() + convey.So(err, convey.ShouldEqual, nil) + fmt.Println(f.String()) + }) +} + +// TestNewFilterForArrayOne ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 21:43 2023/1/2 +func TestNewFilterForArrayOne(t *testing.T) { + var ( + err error + ) + testData := `[ + { + "name":"zhangdeman" + }, + { + "name":"zhang" + }, + { + "name":"de" + }, + { + "name":"man" + } +]` + filterRuleList := []MapRule{ + { + SourcePath: "[].name", + MapPath: "user_name.[]", + Required: true, + DataType: "string", + DefaultValue: "", + }, + } + f := NewFilter(testData, filterRuleList) + convey.Convey("提取列表字段,构成新的列表", t, func() { + err = f.Deal() + convey.So(err, convey.ShouldEqual, nil) + fmt.Println(f.String()) + }) +} + +// TestNewFilterForArrayTwo ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 22:22 2023/1/2 +func TestNewFilterForArrayTwo(t *testing.T) { + var ( + err error + ) + testData := `{"user_list":[ + { + "name":"zhangdeman1" + }, + { + "name":"zhang1" + }, + { + "name":"de1" + }, + { + "name":"man1" + } +]}` + filterRuleList := []MapRule{ + { + SourcePath: "user_list.[].name", + MapPath: "user.name_list.[]", + Required: true, + DataType: "string", + DefaultValue: "", + }, + } + f := NewFilter(testData, filterRuleList) + convey.Convey("提取列表字段,构成新的列表", t, func() { + err = f.Deal() + convey.So(err, convey.ShouldEqual, nil) + fmt.Println(f.String()) + }) +} diff --git a/go.mod b/go.mod index b94c429..f4d46cc 100644 --- a/go.mod +++ b/go.mod @@ -3,19 +3,24 @@ module git.zhangdeman.cn/zhangdeman/filter go 1.17 require ( - git.zhangdeman.cn/zhangdeman/util v0.0.0-20221021061434-e68b22a6e106 - github.com/Jeffail/gabs v1.4.0 + git.zhangdeman.cn/zhangdeman/util v0.0.0-20230113095943-b4b3e261e0c4 github.com/pkg/errors v0.9.1 + github.com/smartystreets/goconvey v1.7.2 github.com/tidwall/gjson v1.14.4 + github.com/tidwall/sjson v1.2.5 ) require ( + github.com/Jeffail/gabs v1.4.0 // indirect github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect + github.com/davecgh/go-spew v1.1.1 // 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/pmezard/go-difflib v1.0.0 // indirect + github.com/smartystreets/assertions v1.2.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/stretchr/testify v1.8.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect - github.com/tidwall/sjson v1.2.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 0df3337..3ae0db9 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -git.zhangdeman.cn/zhangdeman/util v0.0.0-20220704053716-ec9271c0f350 h1:y54/TJ7SCSG1LlKrX7QebDBdv+JoEl8JVs2kEqFoEXs= -git.zhangdeman.cn/zhangdeman/util v0.0.0-20220704053716-ec9271c0f350/go.mod h1:aAIhnUdQewLipl4bddewAsAeSLST9SRvgTcPN5ITkAQ= git.zhangdeman.cn/zhangdeman/util v0.0.0-20221021061434-e68b22a6e106 h1:xiiN+rLtBbDGRUbipVuwI1j2iRhuL3ejSm+EnDxzVMk= git.zhangdeman.cn/zhangdeman/util v0.0.0-20221021061434-e68b22a6e106/go.mod h1:zTir/0IWdK3E7n0GiaogyWHADAQnBtTdl2I6Z2/OPqw= +git.zhangdeman.cn/zhangdeman/util v0.0.0-20230113095943-b4b3e261e0c4 h1:1WclY9P8l8o/NZ3ZR/mupm8LtowjQ/Q4UNGXR32f0OQ= +git.zhangdeman.cn/zhangdeman/util v0.0.0-20230113095943-b4b3e261e0c4/go.mod h1:zTir/0IWdK3E7n0GiaogyWHADAQnBtTdl2I6Z2/OPqw= 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= @@ -9,14 +9,21 @@ github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIg 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/go-ini/ini v1.66.6 h1:h6k2Bb0HWS/BXXHCXj4QHjxPmlIU4NK+7MuLp9SD+4k= github.com/go-ini/ini v1.66.6/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 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/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/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/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= @@ -24,19 +31,22 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS 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/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 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/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 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 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= diff --git a/lexical.go b/lexical.go deleted file mode 100644 index d52be1a..0000000 --- a/lexical.go +++ /dev/null @@ -1,304 +0,0 @@ -// Package filter ... -// -// Description : JSON 词法分析 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 2022-07-04 17:52 -package filter - -import ( - "git.zhangdeman.cn/zhangdeman/util" - - "github.com/pkg/errors" -) - -// NewLexical 获取实例 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 20:52 2022/7/4 -func NewLexical(jsonData string) *lexical { - return &lexical{ - jsonData: jsonData, - lexicalResult: make([]*lexicalNode, 0), - } -} - -// lexical 词法解析 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 20:42 2022/7/4 -type lexical struct { - jsonData string - keyLeftRightTokenCnt int - lexicalResult []*lexicalNode -} - -// Parse 解析词法 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 18:11 2022/7/4 -func (l *lexical) Parse() error { - // mt.Println(jsonData) - if len(l.jsonData) < 2 { - return errors.New("input data is not json") - } - tmpStr := "" - for _, itemChar := range l.jsonData { - currentChar := string(itemChar) - tmpRealVal, tmpStrType := l.getTmpStrType(tmpStr) - if l.inputCharIsToken(currentChar, tmpStr, tmpStrType) { - if currentChar == keyLeftRightToken { - // 双引号计数 - l.keyLeftRightTokenCnt++ - } - // 是关键词 - if len(tmpStr) > 0 { - l.lexicalResult = append(l.lexicalResult, &lexicalNode{ - Val: tmpRealVal, - IsToken: false, - Type: tmpStrType, - }) - } - l.lexicalResult = append(l.lexicalResult, &lexicalNode{ - Val: currentChar, - IsToken: true, - Type: "string", - }) - tmpStr = "" - } else { - // 不是关键词, 继续向后走 - if currentChar == " " && l.keyLeftRightTokenCnt%2 == 0 { - // 当前字符是空格, 只有在 "" 之间方才有效 , 关键字之间的空格, 忽略即可 - continue - } - if (currentChar == "\n" || currentChar == "\t") && (l.keyLeftRightTokenCnt%2 == 0 || tmpStrType == "number" || tmpStrType == "bool") { - // 数字或者 bool 之后的 \n \t 无意义 , 不在 "" 之间也无意义 - continue - } - tmpStr = tmpStr + currentChar - } - } - - if len(tmpStr) > 0 { - l.lexicalResult = append(l.lexicalResult, &lexicalNode{ - Val: tmpStr, - IsToken: false, - Type: NodeTypeString, - }) - } - - return nil -} - -// inputCharIsToken 输入字符是否为关键字 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 18:15 2022/7/4 -func (l *lexical) inputCharIsToken(inputChar string, tmpStr string, tmpStrType string) bool { - tokenList := []string{ - // list 类型起始 - listLeftToken, - // listRight list 类型结束 - listRightToken, - // 对象起始 - objectLeftToken, - // 对象结束 - objectRightToken, - // key 值的起始 - keyLeftRightToken, - // 转义符 - // escapeCharacterToken, - // 冒号 - colonToken, - // 逗号 - commaToken, - } - preCheck := false - for _, item := range tokenList { - if item == inputChar { - preCheck = true - break - } - } - - if !preCheck { - // 输入一定不是关键字 - return false - } - - if len(tmpStr) == 0 && inputChar == keyLeftRightToken { - // 双引号关键字 - return true - } - tmpStrByte := []byte(tmpStr) - if len(tmpStrByte) > 0 { - // 字符串拼接过程中, 只有 " 可能是关键字 - // 判断转义符个数 - escapeCharacterTokenCnt := 0 - for i := len(tmpStrByte) - 1; i >= 0; i-- { - if string(tmpStrByte[i]) == escapeCharacterToken { - // 前一个是转义符 - escapeCharacterTokenCnt++ - continue - } - // 非连续的转义符不计数 - break - } - // 0 个 或者 偶数个转义符, " 是关键字 - if inputChar == keyLeftRightToken && escapeCharacterTokenCnt%2 == 0 { - return true - } - } - - var preNode *lexicalNode - if len(l.lexicalResult) > 0 { - preNode = l.lexicalResult[len(l.lexicalResult)-1] - } - - if inputChar == colonToken && nil != preNode && preNode.ValStr() == keyLeftRightToken && l.keyLeftRightTokenCnt > 0 && l.keyLeftRightTokenCnt%2 == 0 { - // : 必须出现在偶数 " 之后才是关键字 - return true - } - - // , 是关键字的场景 - // {"name":"zhangsan", "age":"18"} - // [{"name":"zhangsan", "age":"18"}, {"name":"zhangsan", "age":"18"}] - // [[],[]] - // [1,2,3] - // [true,false,true] - if inputChar == commaToken && ( - // 对应 {"name":"zhangsan", "age":"18"} - (nil != preNode && preNode.ValStr() == keyLeftRightToken) || - // 对应[{"name":"zhangsan", "age":"18"}, {"name":"zhangsan", "age":"18"}] - (nil != preNode && preNode.ValStr() == objectRightToken) || - // 对应[[],[]] - (nil != preNode && preNode.ValStr() == listRightToken) || - // 对应 [true,false,true] / [1,2,3] / [1,true,2,false] - (nil != preNode && (preNode.ValStr() == colonToken || preNode.ValStr() == listLeftToken || preNode.ValStr() == commaToken) && (tmpStrType == "number" || tmpStrType == "bool"))) { // 对应 - return true - } - - // { 可能出现的情况 - // {} - // [{}] [{}, {}] - // {"person": {}} - if inputChar == objectLeftToken && len(tmpStr) == 0 && - (nil == preNode || // 对应 {} - (nil != preNode && preNode.ValStr() == listLeftToken) || // 对应 [{}] - (nil != preNode && preNode.ValStr() == colonToken) || // 对应 {"person": {}} - (nil != preNode && preNode.ValStr() == commaToken)) { // 对应 [{}, {}] - // { 是关键字 - return true - } - - // } 可能出出现的情况 - // {} - // [{}] - // {"name":"zhangsan"} - // {"person": {"name":"zhangsan"}} - // {"person": {"name":"zhangsan", "age": 18}} - // {"person": {"work":true}} - // {"person": {"like":1}} - // {"person_list": [{"like":1}]} - if inputChar == objectRightToken && len(tmpStr) == 0 && ( - // 对应 {}, [{}] - (nil != preNode && preNode.ValStr() == objectLeftToken) || - // 对应 {"name":"zhangsan"} - (nil != preNode && preNode.ValStr() == keyLeftRightToken) || - // 对应 {"person": {"name":"zhangsan"}} - (nil != preNode && preNode.ValStr() == objectRightToken)) || - // 对应 {"person": {"work":true}} / {"person": {"like":1}} - (nil != preNode && preNode.ValStr() == colonToken && (tmpStr == "number" || tmpStr == "bool")) || - // 对应 {"person_list": [{"like":1}]} - (nil != preNode && preNode.ValStr() == listRightToken) { - // } 是关键字 - return true - } - - // [ 可能出现的场景 - // [] - // [[],[]] - // "a": [] - if inputChar == listLeftToken && len(tmpStr) == 0 && (nil == preNode || // 对应 [] - (nil != preNode && preNode.ValStr() == listLeftToken) || // 对应 [[],[]] - (nil != preNode && preNode.ValStr() == colonToken)) { // 对应 "a": [] - // [ 是关键字 - return true - } - - // ] 可能出现的场景 - // [] - // [[],[]] - // [{}, {}] - // [1,2,3] - // [true, false] - // ["", "" ] - if inputChar == listRightToken && len(tmpStr) == 0 && ( - //对应 [] - (nil != preNode && preNode.ValStr() == listLeftToken) || - // 对应 [[],[]] - (nil != preNode && preNode.ValStr() == listRightToken) || - // [true, false] / - (nil != preNode && preNode.ValStr() == objectRightToken) || - // 对应 [{}, {}] / [1,2,3] - (nil != preNode && (tmpStrType == "number" || tmpStrType == "bool")) || - // 对应 ["", "" ] - (nil != preNode && preNode.ValStr() == keyLeftRightToken)) { - return true - } - return false -} - -func (l *lexical) getTmpStrType(tmpStr string) (interface{}, string) { - var preNode *lexicalNode - if len(l.lexicalResult) > 0 { - preNode = l.lexicalResult[len(l.lexicalResult)-1] - } - - // 数字只有一个场景 {"age": 18},多以若是数字, 则 前一次解析必为关键字 : - if nil != preNode && preNode.ValStr() == colonToken { - // 判断是否可转数字 - var floatVal float64 - if err := util.ConvertAssign(&floatVal, tmpStr); nil == err { - return floatVal, "number" - } - } - - // 判断是否为 bool - // bool 只有一个场景 {"work": true/false},多以若是数字, 则 前一次解析必为关键字 : - if nil != preNode && preNode.ValStr() == colonToken { - // 判断是否可转数字 - var boolVal bool - if err := util.ConvertAssign(&boolVal, tmpStr); nil == err { - return boolVal, "bool" - } - } - return tmpStr, "string" -} - -// String 将解析后的词法, 转换为字符串 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:34 2022/7/5 -func (l *lexical) String() string { - str := "" - for _, item := range l.lexicalResult { - str = str + item.ValStr() - } - return str -} - -// Result 词法分析的结果 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:55 2022/7/5 -func (l *lexical) Result() []*lexicalNode { - return l.lexicalResult -} diff --git a/lexical_test.go b/lexical_test.go deleted file mode 100644 index e475662..0000000 --- a/lexical_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Package filter ... -// -// Description : filter ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 2022-07-04 18:13 -package filter - -import ( - "fmt" - "testing" -) - -func Test_parseLexical(t *testing.T) { - jsonData := `{ - "start" : 123456, - "name" : "zhangsan", - "age":"18", - "extension":{ - "sex":"man", - "height":"180" - }, - "teacher_list":[ - { - "name":"t1", - "age":"11" - }, - { - "name":"t2", - "age":"12" - } - ] -}` - //jsonData = `{"name":"zhangsan","age":"18","extension":{"sex":"man","height":"180"},"teacher_list":[{"name":"t1","age":"11"},{"name":"t2","age":"12"}]}` - - instance := NewLexical(jsonData) - _ = instance.Parse() - fmt.Println(instance.String()) -} diff --git a/syntax.go b/syntax.go deleted file mode 100644 index b238cbc..0000000 --- a/syntax.go +++ /dev/null @@ -1,153 +0,0 @@ -// Package filter ... -// -// Description : 语法分析 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 2022-07-04 17:53 -package filter - -import ( - "github.com/pkg/errors" -) - -// NewSyntax 构建JSON语法树 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 14:33 2022/7/5 -func NewSyntax(jsonData string) *syntax { - return &syntax{ - lexicalInstance: NewLexical(jsonData), - syntaxResult: nil, - } -} - -type syntax struct { - // 词法分析实例 - lexicalInstance *lexical - // 词法分析结果 - lexicalResult []*lexicalNode - // 语法分析结果 - syntaxResult *jsonNode -} - -// Parse 构建语法树 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:35 2022/7/5 -func (s *syntax) Parse() error { - if err := s.lexicalInstance.Parse(); nil != err { - // 词法解析失败 - return err - } - s.lexicalResult = s.lexicalInstance.Result() - if len(s.lexicalResult) == 0 { - return errors.New("词法解析无任何结果") - } - // TODO : 循环处理 - generateNode, lastIdx, err := s.generateJSONNode(0) - if nil != err { - return err - } - if lastIdx >= len(s.lexicalResult) { - // 词法处理完成 - return nil - } - if nil == s.syntaxResult { - s.syntaxResult = generateNode - } - return nil -} - -// generateJSONNode 构建 JSONNode, 参数 : 从那个索引开始处理 返回值 : 当前 json 节点, 下次从那个索引开始处理, 异常 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 16:58 2022/7/5 -func (s *syntax) generateJSONNode(currentLexicalIdx int) (*jsonNode, int, error) { - generateJSONNode := &jsonNode{ - Name: "", - Parent: nil, - Son: nil, - PreBrother: nil, - NextBrother: nil, - Val: nil, - Type: "", - } - if s.lexicalResult[currentLexicalIdx].ValStr() == objectLeftToken { - // 对象的起始, 类型一定为对象 - generateJSONNode.Type = NodeTypeObject - - // 下一个必定为 " (原因: 词法分析时, 已经过滤掉无用的空格换行符等, JSON数据已压缩成单行字符串) - currentLexicalIdx++ - if s.lexicalResult[currentLexicalIdx].ValStr() != keyLeftRightToken { - // 不是 " 号, 说明数据格式非法 - return nil, currentLexicalIdx, errors.New("JSON格式非法") - } - - // 在下一个必定是 json 的 key - currentLexicalIdx++ - generateJSONNode.Name = s.lexicalResult[currentLexicalIdx].ValStr() - - // 在下一个必定是 " - currentLexicalIdx++ - if s.lexicalResult[currentLexicalIdx].ValStr() != keyLeftRightToken { - // 不是 " 号, 说明数据格式非法 - return nil, currentLexicalIdx, errors.New("JSON格式非法") - } - - // 在下一个必定是 : - currentLexicalIdx++ - if s.lexicalResult[currentLexicalIdx].ValStr() != colonToken { - // 不是 : 号, 说明数据格式非法 - return nil, currentLexicalIdx, errors.New("JSON格式非法") - } - - // 到了取值部分, 具体分析是简单 k -> v or k -> object or k -> list - currentLexicalIdx++ - if s.lexicalResult[currentLexicalIdx].IsToken && - s.lexicalResult[currentLexicalIdx].ValStr() != keyLeftRightToken { - // TODO : 是关键字, 且不是 " 号 , 说明不是简单KV, 后续具体处理 - return generateJSONNode, currentLexicalIdx, nil - } - // 简单KV, 下一个必定是取值 - if s.lexicalResult[currentLexicalIdx].ValStr() == keyLeftRightToken { - // 双引号 - currentLexicalIdx++ - generateJSONNode.Val = s.lexicalResult[currentLexicalIdx].ValStr() - // 跳过字符串闭合的 " 号 - currentLexicalIdx = currentLexicalIdx + 2 - // 判断 闭合 " 之后 是不是 , / ] / } - if s.lexicalResult[currentLexicalIdx].ValStr() == commaToken { - // 跳过 分割的 , - currentLexicalIdx++ - } else { - if s.lexicalResult[currentLexicalIdx].ValStr() == objectRightToken || - s.lexicalResult[currentLexicalIdx].ValStr() == listRightToken { - // 跳过整体对象的闭合标签 - currentLexicalIdx++ - } - if s.lexicalResult[currentLexicalIdx].ValStr() == commaToken { - // 还是 , - currentLexicalIdx++ - } - } - } else { - generateJSONNode.Val = s.lexicalResult[currentLexicalIdx].Val - generateJSONNode.Type = s.lexicalResult[currentLexicalIdx].Type - currentLexicalIdx++ - if s.lexicalResult[currentLexicalIdx].ValStr() == objectRightToken || - s.lexicalResult[currentLexicalIdx].ValStr() == listRightToken { - // 跳过整体对象的闭合标签 - currentLexicalIdx++ - } - if s.lexicalResult[currentLexicalIdx].ValStr() == commaToken { - // 还是 , - currentLexicalIdx++ - } - } - } - return generateJSONNode, currentLexicalIdx, nil -} diff --git a/syntax_test.go b/syntax_test.go deleted file mode 100644 index 2d25f30..0000000 --- a/syntax_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Package filter ... -// -// Description : filter ... -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 2022-07-05 17:43 -package filter - -import ( - "testing" -) - -func Test_syntax_Parse(t *testing.T) { - jsonData := `{ - "start" : 123456, - "name" : "zhangsan", - "age":"18", - "extension":{ - "sex":"man", - "height":"180" - }, - "teacher_list":[ - { - "name":"t1", - "age":"11" - }, - { - "name":"t2", - "age":"12" - } - ] -}` - //jsonData = `{"name":"zhangsan","age":"18","extension":{"sex":"man","height":"180"},"teacher_list":[{"name":"t1","age":"11"},{"name":"t2","age":"12"}]}` - - instance := NewSyntax(jsonData) - _ = instance.Parse() -} diff --git a/token.go b/token.go deleted file mode 100644 index 5e08207..0000000 --- a/token.go +++ /dev/null @@ -1,27 +0,0 @@ -// Package filter ... -// -// Description : 关键词定义 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 2022-07-04 17:53 -package filter - -const ( - // list 类型起始 - listLeftToken = "[" - // listRight list 类型结束 - listRightToken = "]" - // 对象起始 - objectLeftToken = "{" - // 对象结束 - objectRightToken = "}" - // key 值的起始 - keyLeftRightToken = "\"" - // 转义符 - escapeCharacterToken = "\\" - // 冒号 - colonToken = ":" - // 逗号 - commaToken = "," -)