英文:
Format json data or generate dynamic struct
问题
{
"type": "object",
"properties": {
"firstName": {
"type": "string",
"title": "名字",
"default": "Chuck"
},
"lastName": {
"type": "string",
"title": "姓氏"
},
"telephone": {
"type": "string",
"title": "电话号码",
"minLength": 10
}
}
}
我想构建上面图中显示的数据,并将其发送到前端进行渲染。它必须包含类型和属性字段。属性中的字段是核心数据。
// testMap 是一个映射。键是变量名,值是值
testMap := DrawValueNameFromPareSelfFile(testPath)
marshal, _ := json.MarshalIndent(testMap, "", " ")
res := string(marshal)
helper.Ok(c, res)
type Resp struct {
Code errcode.Code `json:"code" binding:"required"`
Message string `json:"message" binding:"required"`
Data interface{} `json:"data" binding:"required"`
}
// Ok
func Ok(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, Resp{
Code: errcode.ErrNone,
Data: data,
})
}
但这是我的结果
{
"code": 0,
"message": "",
"data": "{\n \"title\": \"Product Set\",\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"number\"\n },\n \"name\": {\n \"type\": \"string\"\n },\n \"price\": {\n \"type\": \"number\"\n },\n \"dimensions\": {\n \"type\": \"object\",\n \"properties\": {\n \"length\": {\n \"type\": \"number\"\n },\n \"width\": {\n \"type\": \"number\"\n },\n \"height\": {\n \"type\": \"number\"\n }\n }\n },\n \"warehouseLocation\": {\n \"type\": \"object\",\n \"properties\": {\n \"latitude\": {\n \"type\": \"number\"\n },\n \"longitude\": {\n \"type\": \"number\"\n }\n }\n }\n }\n}\n"
}
有换行和转义字符。
我尝试使用映射构建结构体,但是大小写转换和嵌套结构体让我很烦恼。
这是我目前使用的方法。但是,在解析 JSON 时,它不能转换为小写字母。前端需要小写字母。
package main
import (
"errors"
"reflect"
"fmt"
)
// 构造器
type Builder struct {
// 用于存储属性字段
fileId []reflect.StructField
}
func NewBuilder() *Builder {
return &Builder{}
}
// 添加字段
func (b *Builder)AddField(field string,typ reflect.Type) *Builder {
b.fileId = append(b.fileId,reflect.StructField{Name: field,Type: typ})
return b
}
// 根据预先添加的字段构建出结构体
func (b *Builder)Build() *Struct {
stu := reflect.StructOf(b.fileId)
index := make(map[string]int)
for i := 0; i < stu.NumField(); i++ {
index[stu.Field(i).Name] = i
}
return &Struct{stu,index}
}
func (b *Builder) AddString(name string) *Builder {
return b.AddField(name, reflect.TypeOf(""))
}
func (b *Builder) AddBool(name string) *Builder {
return b.AddField(name, reflect.TypeOf(true))
}
func (b *Builder) AddInt64(name string) *Builder {
return b.AddField(name, reflect.TypeOf(int64(0)))
}
func (b *Builder) AddFloat64(name string) *Builder {
return b.AddField(name, reflect.TypeOf(float64(1.2)))
}
func (b *Builder) AddStruct(name string) *Builder {
// type T struct { a, b int }
tmp := make(map[string]string)
tmp["test"] = "test"
return b.AddField(name, reflect.TypeOf(tmp))
}
// 实际生成的结构体,基类
// 结构体的类型
type Struct struct {
typ reflect.Type
// <fieldName : 索引> // 用于通过字段名称,从Builder的[]reflect.StructField中获取reflect.StructField
index map[string]int
}
func (s Struct)New() *Instance {
return &Instance{reflect.New(s.typ).Elem(),s.index}
}
// 结构体的值
type Instance struct {
instance reflect.Value
// <fieldName : 索引>
index map[string]int
}
var (
FieldNoExist error = errors.New("field no exist")
)
func (in Instance)Field(name string) (reflect.Value,error) {
if i,ok := in.index[name];ok{
return in.instance.Field(i),nil
}else {
return reflect.Value{},FieldNoExist
}
}
func (in *Instance) SetStruct(name string, resp map[string]string) {
if i,ok := in.index[name];ok{
for k ,v := range resp {
// value, _ :=v.(string)
fmt.Println(reflect.ValueOf(k))
fmt.Println(reflect.ValueOf(v))
// in.instance.Field(i).SetString("test")
in.instance.Field(i).Set(reflect.ValueOf(resp))
}
}
}
func (in *Instance) SetString(name, value string) {
if i,ok := in.index[name];ok{
in.instance.Field(i).SetString(value)
}
}
func (in *Instance) SetBool(name string, value bool) {
if i,ok := in.index[name];ok{
in.instance.Field(i).SetBool(value)
}
}
func (in *Instance) SetInt64(name string, value int64) {
if i,ok := in.index[name];ok{
in.instance.Field(i).SetInt(value)
}
}
func (in *Instance) SetFloat64(name string, value float64) {
if i,ok := in.index[name];ok{
in.instance.Field(i).SetFloat(value)
}
}
func (i *Instance) Interface() interface{} {
return i.instance.Interface()
}
func (i *Instance) Addr() interface{} {
return i.instance.Addr().Interface()
}
func main() {
pe := NewBuilder().
AddString("Name").
AddInt64("Age").
AddStruct("Typet").
Build()
p := pe.New()
p.SetString("Name","你好")
p.SetInt64("Age",32)
fmt.Printf("%T\n",p)
fmt.Printf("%T\n",p.Interface())
fmt.Printf("%+v\n",p.Interface())
fmt.Printf("%T\n",p.Addr())
fmt.Printf("%+v\n",p.Addr())
tmp := make(map[string]string)
tmp["type1"] = "object1"
tmp["type2"] = "object2"
tmp["type3"] = "object3"
p.SetStruct("Typet",tmp)
fmt.Printf("%T\n",p)
fmt.Printf("%T\n",p.Interface())
fmt.Printf("%+v\n",p.Interface())
fmt.Printf("%T\n",p.Addr())
fmt.Printf("%+v\n",p.Addr())
}
英文:
{
"type": "object",
"properties": {
"firstName": {
"type": "string",
"title": "First name",
"default": "Chuck"
},
"lastName": {
"type": "string",
"title": "Last name"
},
"telephone": {
"type": "string",
"title": "Telephone",
"minLength": 10
}
}
}
I want to construct the data shown in the above figure and send it to the front end for rendering. It must contain the type and properties fields. The fields in properties are core data.
//testMap is a map. key is variable name , value is value
testMap := DrawValueNameFromPareSelfFile(testPath)
marshal, _ := json.MarshalIndent(testMap, "", " ")
res := string(marshal)
helper.Ok(c, res)
type Resp struct {
Code errcode.Code `json:"code" binding:"required"`
Message string `json:"message" binding:"required"`
Data interface{} `json:"data" binding:"required"`
}
// Ok
func Ok(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, Resp{
Code: errcode.ErrNone,
Data: data,
})
}
But this is my result
{
"code": 0,
"message": "",
"data": "{\n \"title\": \"Product Set\",\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"number\"\n },\n \"name\": {\n \"type\": \"string\"\n },\n \"price\": {\n \"type\": \"number\"\n },\n \"dimensions\": {\n \"type\": \"object\",\n \"properties\": {\n \"length\": {\n \"type\": \"number\"\n },\n \"width\": {\n \"type\": \"number\"\n },\n \"height\": {\n \"type\": \"number\"\n }\n }\n },\n \"warehouseLocation\": {\n \"type\": \"object\",\n \"properties\": {\n \"latitude\": {\n \"type\": \"number\"\n },\n \"longitude\": {\n \"type\": \"number\"\n }\n }\n }\n }\n}\n"
}
There are line breaks and escape characters。
I tried to build structs with map, but I was annoyed by case conversion and nested structs
This is the method I currently use. However, when parsing JSON, it cannot be changed into lowercase letters. The front end needs lowercase letters
package main
import (
"errors"
"reflect"
"fmt"
)
// 构造器
type Builder struct {
// 用于存储属性字段
fileId []reflect.StructField
}
func NewBuilder() *Builder {
return &Builder{}
}
// 添加字段
func (b *Builder)AddField(field string,typ reflect.Type) *Builder {
b.fileId = append(b.fileId,reflect.StructField{Name: field,Type: typ})
return b
}
// 根据预先添加的字段构建出结构体
func (b *Builder)Build() *Struct {
stu := reflect.StructOf(b.fileId)
index := make(map[string]int)
for i := 0; i < stu.NumField(); i++ {
index[stu.Field(i).Name] = i
}
return &Struct{stu,index}
}
func (b *Builder) AddString(name string) *Builder {
return b.AddField(name, reflect.TypeOf(""))
}
func (b *Builder) AddBool(name string) *Builder {
return b.AddField(name, reflect.TypeOf(true))
}
func (b *Builder) AddInt64(name string) *Builder {
return b.AddField(name, reflect.TypeOf(int64(0)))
}
func (b *Builder) AddFloat64(name string) *Builder {
return b.AddField(name, reflect.TypeOf(float64(1.2)))
}
func (b *Builder) AddStruct(name string) *Builder {
// type T struct { a, b int }
tmp := make(map[string]string)
tmp["test"] = "test"
return b.AddField(name, reflect.TypeOf(tmp))
}
// 实际生成的结构体,基类
// 结构体的类型
type Struct struct {
typ reflect.Type
// <fieldName : 索引> // 用于通过字段名称,从Builder的[]reflect.StructField中获取reflect.StructField
index map[string]int
}
func (s Struct)New() *Instance {
return &Instance{reflect.New(s.typ).Elem(),s.index}
}
// 结构体的值
type Instance struct {
instance reflect.Value
// <fieldName : 索引>
index map[string]int
}
var (
FieldNoExist error = errors.New("field no exist")
)
func (in Instance)Field(name string) (reflect.Value,error) {
if i,ok := in.index[name];ok{
return in.instance.Field(i),nil
}else {
return reflect.Value{},FieldNoExist
}
}
func (in *Instance) SetStruct(name string, resp map[string]string) {
if i,ok := in.index[name];ok{
for k ,v := range resp {
// value, _ :=v.(string)
fmt.Println(reflect.ValueOf(k))
fmt.Println(reflect.ValueOf(v))
// in.instance.Field(i).SetString("test")
in.instance.Field(i).Set(reflect.ValueOf(resp))
}
}
}
func (in *Instance) SetString(name, value string) {
if i,ok := in.index[name];ok{
in.instance.Field(i).SetString(value)
}
}
func (in *Instance) SetBool(name string, value bool) {
if i,ok := in.index[name];ok{
in.instance.Field(i).SetBool(value)
}
}
func (in *Instance) SetInt64(name string, value int64) {
if i,ok := in.index[name];ok{
in.instance.Field(i).SetInt(value)
}
}
func (in *Instance) SetFloat64(name string, value float64) {
if i,ok := in.index[name];ok{
in.instance.Field(i).SetFloat(value)
}
}
func (i *Instance) Interface() interface{} {
return i.instance.Interface()
}
func (i *Instance) Addr() interface{} {
return i.instance.Addr().Interface()
}
func main() {
pe := NewBuilder().
AddString("Name").
AddInt64("Age").
AddStruct("Typet").
Build()
p := pe.New()
p.SetString("Name","你好")
p.SetInt64("Age",32)
fmt.Printf("%T\n",p)
fmt.Printf("%T\n",p.Interface())
fmt.Printf("%+v\n",p.Interface())
fmt.Printf("%T\n",p.Addr())
fmt.Printf("%+v\n",p.Addr())
tmp := make(map[string]string)
tmp["type1"] = "object1"
tmp["type2"] = "object2"
tmp["type3"] = "object3"
p.SetStruct("Typet",tmp)
fmt.Printf("%T\n",p)
fmt.Printf("%T\n",p.Interface())
fmt.Printf("%+v\n",p.Interface())
fmt.Printf("%T\n",p.Addr())
fmt.Printf("%+v\n",p.Addr())
}
答案1
得分: 0
你需要使用map
来处理动态字段。
真正的动态数据可以存储在map[string]interface{}
中。
对于有限数量的字段,你可以使用强类型:
type Response struct {
Type string `json:"type"`
Properties map[string]RespProp `json:"properties"`
}
type RespProp struct {
Type string `json:"type"`
Title string `json:"title"`
Default string `json:"default,omitempty"`
MinLength int `json:"minLength,omitempty"`
}
https://go.dev/play/p/W8mpg7HvCwM
英文:
You need to use map
for dynamic fields.
Really dynamic data can be stored in map[string]interface{}
For limited number of fields, you can use strong type:
type Response struct {
Type string `json:"type"`
Properties map[string]RespProp `json:"properties"`
}
type RespProp struct {
Type string `json:"type"`
Title string `json:"title"`
Default string `json:"default,omitempty"`
MinLength int `json:"minLength,omitempty"`
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论