在运行时覆盖Go JSON标签值

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

Override Go JSON tag values at runtime

问题

我在我的Web应用程序中使用"encoding/json"有以下的结构体:

type CourseAssignment struct {
    Semester int `json:"semester" xml:"semester"`
    Lecture Lecture `json:"-" xml:"-"`
    Cos Cos `json:"-" xml:"-"`
    Links map[string][]Link `json:"links,omitempty" xml:"links,omitempty"`
}

Lecture和Cos本身是复杂的结构体,我不希望它们被包含在我的序列化JSON中,所以我通过设置json:"-"来指示。

这个方法完美地运行。

在运行时,我如何在需要的时候覆盖这种行为,而不编写自己的序列化代码?

我的解决方案如下:

func (r *CourseAssignment) Expand(depth int) CourseAssignment {
    if depth <= 0 {
        return *r
    }

    tmp := *r
    tmp.LectureEx = tmp.Lecture
    tmp.CosEx = tmp.Cos
    tmp.Links = nil
    return tmp
}

type CourseAssignment struct {
    Semester int `json:"semester" xml:"semester"`
    Lecture *Lecture `json:"-" xml:"-"`
    Cos *Cos `json:"-" xml:"-"`
    Links map[string][]Link `json:"links,omitempty" xml:"links,omitempty"`
    LectureEx *Lecture `json:"lecture,omitempty" xml:"lecture,omitempty"`
    CosEx *Cos `json:"course_of_study,omitempty" xml:"course_of_study,omitempty"`
}

当我想要包含这些字段时,我使用Expand创建对象的副本,该副本填充了包含相同引用但在序列化中显示的字段。

英文:

I have the following struct in in my Web Application using "encoding/json"

type CourseAssignment struct {
    Semester int `json:&quot;semester&quot;  xml:&quot;semester&quot;`
    Lecture Lecture `json:&quot;-&quot;  xml:&quot;-&quot;`
    Cos Cos `json:&quot;-&quot;  xml:&quot;-&quot;`
    Links map[string][]Link `json:&quot;links,omitempty&quot; xml:&quot;links,omitempty&quot;`
}

Lecture and Cos are complex structs themselves that i dont want to be included in my serialized json which i indicate by setting json:"-"

This works perfectly.

How do I override that behavior on demand during runtime, without writing my own Serialization code?

My Own Solution:

func (r *CourseAssignment) Expand(depth int) CourseAssignment {

	if depth &lt;= 0 {
		return *r
	}

	tmp := *r
	tmp.LectureEx = tmp.Lecture
	tmp.CosEx = tmp.Cos
	tmp.Links = nil	
	return tmp
}

type CourseAssignment struct {
	Semester int `json:&quot;semester&quot;  xml:&quot;semester&quot;`
	Lecture *Lecture `json:&quot;-&quot;  xml:&quot;-&quot;`
	Cos *Cos `json:&quot;-&quot;  xml:&quot;-&quot;`
	Links map[string][]Link `json:&quot;links,omitempty&quot; xml:&quot;links,omitempty&quot;`
	LectureEx  *Lecture   `json:&quot;lecture,omitempty&quot;  xml:&quot;lecture,omitempty&quot;`
	CosEx *Cos `json:&quot;course_of_study,omitempty&quot; xml:&quot;course_of_study,omitempty&quot;`	
}

When I want to include the fields, I create a Copy of the Object using Expand that fills fields that contain the same references but show up in the serialization.

答案1

得分: 4

你可以使用reflect包中的StructTag读取/获取结构体标签的值:

package main

import (
	"fmt"
	"reflect"
)

type CourseAssignment struct {
	Semester int `json:"semester"  xml:"semester"`
}

func main() {
	ca := CourseAssignment{}
	st := reflect.TypeOf(ca)
	field := st.Field(0)
	fmt.Println(field.Tag.Get("json"))
}

标准库中没有提供直接修改结构体标签字段的方法。

然而,有一些开源库可以实现这一功能,比如Retag

英文:

You can read/get struct tag values using StructTag from reflect package:

package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
)

type CourseAssignment struct {
	Semester int `json:&quot;semester&quot;  xml:&quot;semester&quot;`
}

func main() {
	ca := CourseAssignment{}
	st := reflect.TypeOf(ca)
	field := st.Field(0)
	fmt.Println(field.Tag.Get(&quot;json&quot;))
}

There is no method to change a struct tag field in the standard library.

However, there are open-source libraries that do exactly that, like Retag.

答案2

得分: 0

在类似情况下,我通常会将这些字段设置为omitempty,然后在不希望它们包含在JSON中的情况下将其置为空:

type CourseAssignment struct {
    Semester int `json:"semester" xml:"semester"`
    Lecture *Lecture `json:"lecture,omitempty" xml:"-"`
    Cos *Cos `json:"cos,omitempty" xml:"-"`
    Links map[string][]Link `json:"links,omitempty" xml:"links,omitempty"`
}

// 不包含Lecture/Cos进行序列化:
aCourseAssignment.Lecture = nil
aCourseAssignment.Cos = nil
thing, err := json.Marshal(aCourseAssignment)

以上是代码的翻译部分。

英文:

What I've done in similar cases is to set these kinds of fields to omitempty, and then empty them before serializing in the cases where I don't want them included in JSON:

type CourseAssignment struct {
    Semester int `json:&quot;semester&quot;  xml:&quot;semester&quot;`
    Lecture *Lecture `json:&quot;lecture,omitempty&quot;  xml:&quot;-&quot;`
    Cos *Cos `json:&quot;cos,omitempty&quot;  xml:&quot;-&quot;`
    Links map[string][]Link `json:&quot;links,omitempty&quot; xml:&quot;links,omitempty&quot;`
}

// Want to serialize without including Lecture/Cos:
aCourseAssignment.Lecture = nil
aCourseAssignment.Cos = nil
thing,err := json.Marshal(aCourseAssignment)

huangapple
  • 本文由 发表于 2017年7月11日 18:53:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/45032514.html
匿名

发表评论

匿名网友

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

确定