格式化JSON数据或生成动态结构。

huangapple go评论89阅读模式
英文:

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())
}
英文:
{
  &quot;type&quot;: &quot;object&quot;,
  &quot;properties&quot;: {
    &quot;firstName&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;title&quot;: &quot;First name&quot;,
      &quot;default&quot;: &quot;Chuck&quot;
    },
    &quot;lastName&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;title&quot;: &quot;Last name&quot;
    },
    &quot;telephone&quot;: {
      &quot;type&quot;: &quot;string&quot;,
      &quot;title&quot;: &quot;Telephone&quot;,
      &quot;minLength&quot;: 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, &quot;&quot;, &quot; &quot;)

	res := string(marshal)
	helper.Ok(c, res)
type Resp struct {
	Code    errcode.Code `json:&quot;code&quot; binding:&quot;required&quot;`
	Message string       `json:&quot;message&quot; binding:&quot;required&quot;`
	Data    interface{}  `json:&quot;data&quot; binding:&quot;required&quot;`
}

// Ok
func Ok(c *gin.Context, data interface{}) {
	c.JSON(http.StatusOK, Resp{
		Code: errcode.ErrNone,
		Data: data,
	})
}

But this is my result

{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: &quot;{\n  \&quot;title\&quot;: \&quot;Product Set\&quot;,\n  \&quot;type\&quot;: \&quot;object\&quot;,\n  \&quot;properties\&quot;: {\n      \&quot;id\&quot;: {\n        \&quot;type\&quot;: \&quot;number\&quot;\n      },\n      \&quot;name\&quot;: {\n        \&quot;type\&quot;: \&quot;string\&quot;\n      },\n      \&quot;price\&quot;: {\n        \&quot;type\&quot;: \&quot;number\&quot;\n      },\n      \&quot;dimensions\&quot;: {\n        \&quot;type\&quot;: \&quot;object\&quot;,\n        \&quot;properties\&quot;: {\n          \&quot;length\&quot;: {\n            \&quot;type\&quot;: \&quot;number\&quot;\n          },\n          \&quot;width\&quot;: {\n            \&quot;type\&quot;: \&quot;number\&quot;\n          },\n          \&quot;height\&quot;: {\n            \&quot;type\&quot;: \&quot;number\&quot;\n          }\n        }\n      },\n      \&quot;warehouseLocation\&quot;: {\n        \&quot;type\&quot;: \&quot;object\&quot;,\n        \&quot;properties\&quot;: {\n          \&quot;latitude\&quot;: {\n            \&quot;type\&quot;: \&quot;number\&quot;\n          },\n          \&quot;longitude\&quot;: {\n            \&quot;type\&quot;: \&quot;number\&quot;\n          }\n        }\n      }\n    }\n}\n&quot;
}

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 (
	&quot;errors&quot;
	&quot;reflect&quot;
	&quot;fmt&quot;
)
// 构造器
type Builder struct {
	// 用于存储属性字段
	fileId []reflect.StructField
}

func NewBuilder() *Builder {
	return &amp;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 &lt; stu.NumField(); i++ {
		index[stu.Field(i).Name] = i
	}
	return &amp;Struct{stu,index}
}
func (b *Builder) AddString(name string) *Builder {
	return b.AddField(name, reflect.TypeOf(&quot;&quot;))
}

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[&quot;test&quot;] = &quot;test&quot;
	return b.AddField(name, reflect.TypeOf(tmp))
}

// 实际生成的结构体,基类
// 结构体的类型
type Struct struct {
	typ reflect.Type
	// &lt;fieldName : 索引&gt; // 用于通过字段名称,从Builder的[]reflect.StructField中获取reflect.StructField
	index map[string]int
}

func (s Struct)New() *Instance {
	return &amp;Instance{reflect.New(s.typ).Elem(),s.index}
}
// 结构体的值
type Instance struct {
	instance reflect.Value
	// &lt;fieldName : 索引&gt;
	index map[string]int
}
var (
	FieldNoExist error = errors.New(&quot;field no exist&quot;)
)
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(&quot;test&quot;)
			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(&quot;Name&quot;).
		AddInt64(&quot;Age&quot;).
		AddStruct(&quot;Typet&quot;).
		Build()
	p := pe.New()
	p.SetString(&quot;Name&quot;,&quot;你好&quot;)
	p.SetInt64(&quot;Age&quot;,32)
	fmt.Printf(&quot;%T\n&quot;,p)
	fmt.Printf(&quot;%T\n&quot;,p.Interface())
	fmt.Printf(&quot;%+v\n&quot;,p.Interface())
	fmt.Printf(&quot;%T\n&quot;,p.Addr())
	fmt.Printf(&quot;%+v\n&quot;,p.Addr())




	tmp := make(map[string]string)

	tmp[&quot;type1&quot;] = &quot;object1&quot;
	tmp[&quot;type2&quot;] = &quot;object2&quot;
	tmp[&quot;type3&quot;] = &quot;object3&quot;


	p.SetStruct(&quot;Typet&quot;,tmp)


	fmt.Printf(&quot;%T\n&quot;,p)
	fmt.Printf(&quot;%T\n&quot;,p.Interface())
	fmt.Printf(&quot;%+v\n&quot;,p.Interface())
	fmt.Printf(&quot;%T\n&quot;,p.Addr())
	fmt.Printf(&quot;%+v\n&quot;,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:&quot;type&quot;`
	Properties map[string]RespProp `json:&quot;properties&quot;`
}

type RespProp struct {
	Type      string `json:&quot;type&quot;`
	Title     string `json:&quot;title&quot;`
	Default   string `json:&quot;default,omitempty&quot;`
	MinLength int    `json:&quot;minLength,omitempty&quot;`
}

https://go.dev/play/p/W8mpg7HvCwM

huangapple
  • 本文由 发表于 2022年5月30日 22:17:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/72435807.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定