From f9024b9498347bffba70505cd6b20525230c4255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Mon, 28 Apr 2025 17:34:23 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BB=8Ejson=20->=20xml?= =?UTF-8?q?=E7=9A=84=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- builder.go | 3 +- go.mod | 2 +- go.sum | 2 + wrapper/json.go | 136 +++++++++++++++++++++++++++++++++++++++++++ wrapper/json_test.go | 22 +++++++ 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 wrapper/json.go create mode 100644 wrapper/json_test.go diff --git a/builder.go b/builder.go index 8ca20a4..ad64070 100644 --- a/builder.go +++ b/builder.go @@ -67,8 +67,9 @@ func (b *builderImpl) AddField(name string, pkg string, typ any, tag string, ano tag = cfgTag } else { if len(tag) == 0 { + arr := strings.Split(strings.TrimSuffix(name, ".[]"), ".") // 没指定tag, 字段名称作为tag名称 - tag = strings.ReplaceAll(`json:"{TAG_NAME}" xml:"{TAG_NAME}" toml:"{TAG_NAME}" yaml:"{TAG_NAME}" ini:"{TAG_NAME}"`, "{TAG_NAME}", name) + tag = strings.ReplaceAll(`json:"{TAG_NAME}" xml:"{TAG_NAME}" toml:"{TAG_NAME}" yaml:"{TAG_NAME}" ini:"{TAG_NAME}"`, "{TAG_NAME}", arr[len(arr)-1]) // tag = fmt.Sprintf(`json:"%s"`, name) } } diff --git a/go.mod b/go.mod index 8504734..e685e2f 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( require ( git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250425024726-cc17224cb995 // indirect git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect - git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250426132259-73cf1be49c7f // indirect + git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250428041157-135850ee8a58 // indirect git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect diff --git a/go.sum b/go.sum index 201c497..2b84ee9 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd h1:q7G git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd/go.mod h1:+D6uPSljwHywjVY5WSBY4TRVMj26TN5f5cFGEYMldjs= git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250426132259-73cf1be49c7f h1:7QgAcGnmVEVyIPeWH0ZkQN/jpzklYXsKCenTR2GpxbE= git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250426132259-73cf1be49c7f/go.mod h1:Ig3GZC2hJDkQp7F8Tm53GvMWLh9bdbbauow/vxGO4YA= +git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250428041157-135850ee8a58 h1:fTkmucGaUoKocoX+ASM4AnwsAVJOtOOLUFSqA+uwVzg= +git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20250428041157-135850ee8a58/go.mod h1:Ig3GZC2hJDkQp7F8Tm53GvMWLh9bdbbauow/vxGO4YA= 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-20250302133417-c1588abcb436 h1:SM4zc54W2wmM72+4pMNQ8iS371H6lj4J8rj8KJKf7pw= diff --git a/wrapper/json.go b/wrapper/json.go new file mode 100644 index 0000000..0a6dd8f --- /dev/null +++ b/wrapper/json.go @@ -0,0 +1,136 @@ +// Package wrapper ... +// +// Description : wrapper ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-04-28 15:32 +package wrapper + +import ( + "encoding/xml" + "errors" + dynamicstruct "git.zhangdeman.cn/zhangdeman/dynamic-struct" + "git.zhangdeman.cn/zhangdeman/serialize" + "github.com/tidwall/gjson" +) + +func NewJson(sourceData string) (*ownJson, error) { + gjsonRes := gjson.Parse(sourceData) + if gjsonRes.Value() == nil { + return nil, errors.New("source data parse result is nil") + } + // 仅支持map + if !gjsonRes.IsObject() { + return nil, errors.New("source result is not map or struct Marshal string") + } + oj := &ownJson{ + sourceData: sourceData, + gjsonResult: gjsonRes, + structBuilder: dynamicstruct.NewStruct(nil), + } + if err := oj.GenerateStruct(); nil != err { + return nil, err + } + return oj, nil +} + +type ownJson struct { + sourceData string // 数据源 + gjsonResult gjson.Result // 数据源解析为gjson + structBuilder dynamicstruct.IBuilder // 结构体构造器 + structRes any // 解析的结构体值 +} + +// GenerateStruct 生成结构体字段列表 +func (oj *ownJson) GenerateStruct() error { + oj.gjsonResult.ForEach(func(fieldName, fieldValue gjson.Result) bool { + oj.generateStructField("", fieldName.String(), fieldValue) + return true + }) + // 追加xml的标签 + oj.structBuilder.AddField("XMLName", "", xml.Name{}, `json:"-" xml:"XmlData"`, false) + val := oj.structBuilder.Build().New() + if err := serialize.JSON.UnmarshalWithNumber([]byte(oj.sourceData), &val); nil != err { + return err + } + oj.structRes = val + return nil +} + +// Marshal 结果序列化 +func (oj *ownJson) Marshal(marshalType string) ([]byte, error) { + return serialize.Wrapper.Marshal(marshalType, oj.structRes) +} + +// generateStructField 递归解析 +func (oj *ownJson) generateStructField(rootPath string, currentName string, currentResult gjson.Result) { + structPath := oj.getPath(rootPath, currentName) + if currentResult.IsBool() { + // bool类型 + oj.structBuilder.AddField(structPath, "", true, "", false) + return + } + if currentResult.Type == gjson.Number { + // 数字类型, 统一用float64 + oj.structBuilder.AddField(structPath, "", float64(0), "", false) + return + } + if currentResult.Value() == nil { + // 空值, any类型 + oj.structBuilder.AddField(structPath, "", (*any)(nil), "", false) + return + } + if currentResult.Type == gjson.String { + // 字符串类型 + oj.structBuilder.AddField(structPath, "", "", "", false) + return + } + if currentResult.IsObject() { + // 还是一个嵌套对象, 递归处理 + currentResult.ForEach(func(key, value gjson.Result) bool { + oj.generateStructField(structPath, key.String(), value) + return true + }) + return + } + if currentResult.IsArray() { + // 数组, 递归处理 + arrList := currentResult.Array() + if arrList[0].Type == gjson.True || arrList[0].Type == gjson.False { + oj.structBuilder.AddField(structPath, "", []bool{}, "", false) + return + } + if arrList[0].Type == gjson.Number { + oj.structBuilder.AddField(structPath, "", []float64{}, "", false) + return + } + if arrList[0].Type == gjson.String { + oj.structBuilder.AddField(structPath, "", []string{}, "", false) + return + } + if arrList[0].Type == gjson.Null { + oj.structBuilder.AddField(structPath, "", []any{}, "", false) + return + } + if arrList[0].IsArray() { + // 数组就不递归处理了, 支持到二维 + oj.structBuilder.AddField(structPath, "", [][]any{}, "", false) + return + } + // 对象结构,递归处理 + arrList[0].ForEach(func(key, value gjson.Result) bool { + oj.generateStructField(structPath+".[]", key.String(), value) + return true + }) + return + } +} + +// getPath 获取路径 +func (oj *ownJson) getPath(root string, currentName string) string { + if root == "" { + return currentName + } + return root + "." + currentName +} diff --git a/wrapper/json_test.go b/wrapper/json_test.go new file mode 100644 index 0000000..6d676bf --- /dev/null +++ b/wrapper/json_test.go @@ -0,0 +1,22 @@ +// Package wrapper ... +// +// Description : wrapper ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-04-28 16:59 +package wrapper + +import ( + "fmt" + "testing" +) + +func TestNewJson(t *testing.T) { + sourceData := `{"name": "test", "age":18,"company":{"address": "Beijing", "name":"lala"},"index":[1,2,3,4], "deep":[{"name":"a"}]}` + instance, iErr := NewJson(sourceData) + fmt.Println(iErr) + res, err := instance.Marshal("xml") + fmt.Println(err) + fmt.Println(string(res)) +} -- 2.36.6 From b4932bf7cd2e181ab32ba4e1d9496e9c2a8400f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Mon, 28 Apr 2025 17:40:40 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E4=BC=A0=E5=85=A5XmlName,=20=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=80=BC=20XmlData?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wrapper/json.go | 13 +++++++++++-- wrapper/json_test.go | 2 +- wrapper/option.go | 13 +++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 wrapper/option.go diff --git a/wrapper/json.go b/wrapper/json.go index 0a6dd8f..d44aa20 100644 --- a/wrapper/json.go +++ b/wrapper/json.go @@ -10,12 +10,13 @@ package wrapper import ( "encoding/xml" "errors" + "fmt" dynamicstruct "git.zhangdeman.cn/zhangdeman/dynamic-struct" "git.zhangdeman.cn/zhangdeman/serialize" "github.com/tidwall/gjson" ) -func NewJson(sourceData string) (*ownJson, error) { +func NewJson(sourceData string, o *Option) (*ownJson, error) { gjsonRes := gjson.Parse(sourceData) if gjsonRes.Value() == nil { return nil, errors.New("source data parse result is nil") @@ -24,10 +25,17 @@ func NewJson(sourceData string) (*ownJson, error) { if !gjsonRes.IsObject() { return nil, errors.New("source result is not map or struct Marshal string") } + if nil == o { + o = &Option{} + } + if o.XmlName == "" { + o.XmlName = "XmlData" + } oj := &ownJson{ sourceData: sourceData, gjsonResult: gjsonRes, structBuilder: dynamicstruct.NewStruct(nil), + o: o, } if err := oj.GenerateStruct(); nil != err { return nil, err @@ -40,6 +48,7 @@ type ownJson struct { gjsonResult gjson.Result // 数据源解析为gjson structBuilder dynamicstruct.IBuilder // 结构体构造器 structRes any // 解析的结构体值 + o *Option // 一些操作选项 } // GenerateStruct 生成结构体字段列表 @@ -49,7 +58,7 @@ func (oj *ownJson) GenerateStruct() error { return true }) // 追加xml的标签 - oj.structBuilder.AddField("XMLName", "", xml.Name{}, `json:"-" xml:"XmlData"`, false) + oj.structBuilder.AddField("XMLName", "", xml.Name{}, fmt.Sprintf(`json:"-" toml:"-" yml:"-" init:"-" xml:"%v"`, oj.o.XmlName), false) val := oj.structBuilder.Build().New() if err := serialize.JSON.UnmarshalWithNumber([]byte(oj.sourceData), &val); nil != err { return err diff --git a/wrapper/json_test.go b/wrapper/json_test.go index 6d676bf..9625a8a 100644 --- a/wrapper/json_test.go +++ b/wrapper/json_test.go @@ -14,7 +14,7 @@ import ( func TestNewJson(t *testing.T) { sourceData := `{"name": "test", "age":18,"company":{"address": "Beijing", "name":"lala"},"index":[1,2,3,4], "deep":[{"name":"a"}]}` - instance, iErr := NewJson(sourceData) + instance, iErr := NewJson(sourceData, &Option{XmlName: "ResponseData"}) fmt.Println(iErr) res, err := instance.Marshal("xml") fmt.Println(err) diff --git a/wrapper/option.go b/wrapper/option.go new file mode 100644 index 0000000..48c057c --- /dev/null +++ b/wrapper/option.go @@ -0,0 +1,13 @@ +// Package wrapper ... +// +// Description : wrapper ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2025-04-28 17:35 +package wrapper + +// Option 生成结构体之后的可用选项 +type Option struct { + XmlName string `json:"xml_name"` // 如果目标格式是 xml, 必须指定xmlName作为根节点 +} -- 2.36.6 From e4c0f9abf344c8886072e8d1cf4aa46718ef4df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Mon, 28 Apr 2025 18:18:04 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=95=B0=E7=BB=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=80=92=E5=BD=92=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wrapper/json.go | 8 ++++++-- wrapper/json_test.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/wrapper/json.go b/wrapper/json.go index d44aa20..cf93259 100644 --- a/wrapper/json.go +++ b/wrapper/json.go @@ -75,6 +75,7 @@ func (oj *ownJson) Marshal(marshalType string) ([]byte, error) { // generateStructField 递归解析 func (oj *ownJson) generateStructField(rootPath string, currentName string, currentResult gjson.Result) { structPath := oj.getPath(rootPath, currentName) + fmt.Println(structPath) if currentResult.IsBool() { // bool类型 oj.structBuilder.AddField(structPath, "", true, "", false) @@ -123,8 +124,8 @@ func (oj *ownJson) generateStructField(rootPath string, currentName string, curr return } if arrList[0].IsArray() { - // 数组就不递归处理了, 支持到二维 - oj.structBuilder.AddField(structPath, "", [][]any{}, "", false) + // 数组递归处理 + oj.generateStructField(structPath+".[]", "", arrList[0]) return } // 对象结构,递归处理 @@ -141,5 +142,8 @@ func (oj *ownJson) getPath(root string, currentName string) string { if root == "" { return currentName } + if currentName == "" { + return root + } return root + "." + currentName } diff --git a/wrapper/json_test.go b/wrapper/json_test.go index 9625a8a..c20de06 100644 --- a/wrapper/json_test.go +++ b/wrapper/json_test.go @@ -13,7 +13,7 @@ import ( ) func TestNewJson(t *testing.T) { - sourceData := `{"name": "test", "age":18,"company":{"address": "Beijing", "name":"lala"},"index":[1,2,3,4], "deep":[{"name":"a"}]}` + sourceData := `{"name": "test", "age":18,"company":{"address": "Beijing", "name":"lala"},"index":[1,2,3,4], "deep":[[{"name":"a","age":20},{"name":"c"}], [{"name":"b"},{"name":"d"}]]}` instance, iErr := NewJson(sourceData, &Option{XmlName: "ResponseData"}) fmt.Println(iErr) res, err := instance.Marshal("xml") -- 2.36.6