支持从json动态生成结构体,并转化为指定格式 #6
| @ -67,8 +67,9 @@ func (b *builderImpl) AddField(name string, pkg string, typ any, tag string, ano | |||||||
| 		tag = cfgTag | 		tag = cfgTag | ||||||
| 	} else { | 	} else { | ||||||
| 		if len(tag) == 0 { | 		if len(tag) == 0 { | ||||||
|  | 			arr := strings.Split(strings.TrimSuffix(name, ".[]"), ".") | ||||||
| 			// 没指定tag, 字段名称作为tag名称 | 			// 没指定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) | 			// tag = fmt.Sprintf(`json:"%s"`, name) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -10,7 +10,7 @@ require ( | |||||||
| require ( | require ( | ||||||
| 	git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250425024726-cc17224cb995 // indirect | 	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/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 | 	git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect | ||||||
| 	github.com/BurntSushi/toml v1.5.0 // indirect | 	github.com/BurntSushi/toml v1.5.0 // indirect | ||||||
| 	github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect | 	github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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-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 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-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 h1:Q973S6CcWr1ICZhFI1STFOJ+KUImCl2BaIXm6YppBqI= | ||||||
| git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI= | 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= | git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 h1:SM4zc54W2wmM72+4pMNQ8iS371H6lj4J8rj8KJKf7pw= | ||||||
|  | |||||||
							
								
								
									
										149
									
								
								wrapper/json.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								wrapper/json.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | |||||||
|  | // Package wrapper ... | ||||||
|  | // | ||||||
|  | // Description : wrapper ... | ||||||
|  | // | ||||||
|  | // Author : go_developer@163.com<白茶清欢> | ||||||
|  | // | ||||||
|  | // Date : 2025-04-28 15:32 | ||||||
|  | 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, o *Option) (*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") | ||||||
|  | 	} | ||||||
|  | 	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 | ||||||
|  | 	} | ||||||
|  | 	return oj, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ownJson struct { | ||||||
|  | 	sourceData    string                 // 数据源 | ||||||
|  | 	gjsonResult   gjson.Result           // 数据源解析为gjson | ||||||
|  | 	structBuilder dynamicstruct.IBuilder // 结构体构造器 | ||||||
|  | 	structRes     any                    // 解析的结构体值 | ||||||
|  | 	o             *Option                // 一些操作选项 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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{}, 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 | ||||||
|  | 	} | ||||||
|  | 	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) | ||||||
|  | 	fmt.Println(structPath) | ||||||
|  | 	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.generateStructField(structPath+".[]", "", arrList[0]) | ||||||
|  | 			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 | ||||||
|  | 	} | ||||||
|  | 	if currentName == "" { | ||||||
|  | 		return root | ||||||
|  | 	} | ||||||
|  | 	return root + "." + currentName | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								wrapper/json_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								wrapper/json_test.go
									
									
									
									
									
										Normal 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","age":20},{"name":"c"}], [{"name":"b"},{"name":"d"}]]}` | ||||||
|  | 	instance, iErr := NewJson(sourceData, &Option{XmlName: "ResponseData"}) | ||||||
|  | 	fmt.Println(iErr) | ||||||
|  | 	res, err := instance.Marshal("xml") | ||||||
|  | 	fmt.Println(err) | ||||||
|  | 	fmt.Println(string(res)) | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								wrapper/option.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								wrapper/option.go
									
									
									
									
									
										Normal file
									
								
							| @ -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作为根节点 | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user