我有以下内容:
package main
import (
"encoding/json"
"fmt"
"os"
"reflect"
)
type User struct {
ID int64 `json:"id"`
Name string `json:"first"` // want to change this to `json:"name"`
tag string `json:"-"`
Another
}
type Another struct {
Address string `json:"address"`
}
func (u *User) MarshalJSON() ([]byte, error) {
value := reflect.ValueOf(*u)
for i := 0; i < value.NumField(); i++ {
tag := value.Type().Field(i).Tag.Get("json")
field := value.Field(i)
fmt.Println(tag, field)
}
return json.Marshal(u)
}
func main() {
anoth := Another{"123 Jennings Street"}
_ = json.NewEncoder(os.Stdout).Encode(
&User{1, "Ken Jennings", "name",
anoth},
)
}
我正在尝试对结构进行json编码,但在此之前我需要更改json键...例如,最终的json应该如下所示:
{"id": 1, "name": "Ken Jennings", "address": "123 Jennings Street"}
我注意到value.Type()。Field(i).Tag.Get(“json”)的方法,但是没有setter方法。为什么?以及如何获得所需的json输出。
另外,如何遍历所有字段,包括嵌入式结构另一个?
答案 0 :(得分:9)
在Go 1.8中,您可以使用更简单的解决方案。这段代码:
func main() {
anoth := Another{"123 Jennings Street"}
_ = json.NewEncoder(os.Stdout).Encode(
&User{1, "Ken Jennings", "name",
anoth},
)
}
type User struct {
ID int64 `json:"id"`
Name string `json:"first"` // want to change this to `json:"name"`
tag string `json:"-"`
Another
}
type Another struct {
Address string `json:"address"`
}
func (u *User) MarshalJSON() ([]byte, error) {
type alias struct {
ID int64 `json:"id"`
Name string `json:"name"`
tag string `json:"-"`
Another
}
var a alias = alias(*u)
return json.Marshal(&a)
}
会给我们:
{"id":1,"name":"Ken Jennings","address":"123 Jennings Street"}
这个解决方案可以通过以下事实实现:在Go 1.8中,您可以为结构分配相同但结构不同的结构。如您所见,类型alias
与User
类型的字段相同,但标记不同。
答案 1 :(得分:5)
这很糟糕,但是如果你可以将结构包装在另一个结构中,并使用新结构进行编码,那么你可以:
interface{}
以获取地图因此:
type MyUser struct {
U User
}
func (u MyUser) MarshalJSON() ([]byte, error) {
// encode the original
m, _ := json.Marshal(u.U)
// decode it back to get a map
var a interface{}
json.Unmarshal(m, &a)
b := a.(map[string]interface{})
// Replace the map key
b["name"] = b["first"]
delete(b, "first")
// Return encoding of the map
return json.Marshal(b)
}
答案 2 :(得分:1)
您可以使用 reflect.StructOf 和 reflect.Value.Convert 函数
来创建带有新标签名称的结构副本。
https://play.golang.org/p/zJ2GLreYpl0
func (u *User) MarshalJSON() ([]byte, error) {
value := reflect.ValueOf(*u)
t := value.Type()
sf := make([]reflect.StructField, 0)
for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Tag)
sf = append(sf, t.Field(i))
if t.Field(i).Name == "Name" {
sf[i].Tag = `json:"name"`
}
}
newType := reflect.StructOf(sf)
newValue := value.Convert(newType)
return json.Marshal(newValue.Interface())
}
答案 3 :(得分:0)
问题中似乎类型为 User 的 tag 属性旨在用于为 Name 属性重命名JSON字段名。
具有一点反射的MarshalJSON实现可以完成这项工作,而无需附加的 tag 属性,也无需附加的包装器结构(如已接受的答案所建议),如下所示:
package main
import (
"encoding/json"
"os"
"reflect"
)
type User struct {
ID int64 `json:"id"`
Name string `json:"first"` // want to change this to `json:"name"`
Another
}
type Another struct {
Address string `json:"address"`
}
// define the naming strategy
func (User) SetJSONname(jsonTag string) string {
if jsonTag == "first"{
return "name"
}
return jsonTag
}
// implement MarshalJSON for type User
func (u User) MarshalJSON() ([]byte, error) {
// specify the naming strategy here
return marshalJSON("SetJSONname", u)
}
// implement a general marshaler that takes a naming strategy
func marshalJSON(namingStrategy string, that interface{}) ([]byte, error) {
out := map[string]interface{}{}
t := reflect.TypeOf(that)
v := reflect.ValueOf(that)
fnctn := v.MethodByName(namingStrategy)
fname := func(params ...interface{}) string {
in := make([]reflect.Value, len(params))
for k, param := range params {
in[k] = reflect.ValueOf(param)
}
return fnctn.Call(in)[0].String()
}
outName := ""
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
switch n := f.Tag.Get("json"); n {
case "":
outName = f.Name
case "-":
outName = ""
default:
outName = fname(n)
}
if outName != "" {
out[outName] = v.Field(i).Interface()
}
}
return json.Marshal(out)
}
func main() {
anoth := Another{"123 Jennings Street"}
u := User{1, "Ken Jennings", anoth,}
e := json.NewEncoder(os.Stdout)
e.Encode(u)
}
这将打印:
{"Another":{"address":"123 Jennings Street"},"id":1,"name":"Ken Jennings"}
但是,请注意,MarshalJSON始终对JSON标签进行排序,而标准编码器保留了结构字段的顺序。