支持从json动态生成结构体,并转化为指定格式 #6
| @ -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
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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 | ||||
|  | ||||
							
								
								
									
										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-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= | ||||
|  | ||||
							
								
								
									
										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