支持从json -> xml的转换

This commit is contained in:
白茶清欢 2025-04-28 17:34:23 +08:00
parent cd85d80da6
commit f9024b9498
5 changed files with 163 additions and 2 deletions

View File

@ -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)
}
}

2
go.mod
View File

@ -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

2
go.sum
View File

@ -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=

136
wrapper/json.go Normal file
View File

@ -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
}

22
wrapper/json_test.go Normal file
View File

@ -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))
}