为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中使用匿名成员扁平化编组的 JSON 结构

在 Go 中使用匿名成员扁平化编组的 JSON 结构

Go
明月笑刀无情 2021-07-09 10:11:39
鉴于以下代码:package mainimport (    "encoding/json"    "fmt")type User struct {    Id   int    `json:"id"`    Name string `json:"name"`}type Session struct {    Id     int `json:"id"`    UserId int `json:"userId"`}type Anything interface{}type Hateoas struct {    Anything    Links map[string]string `json:"_links"`}func MarshalHateoas(subject interface{}) ([]byte, error) {    h := &Hateoas{subject, make(map[string]string)}    switch s := subject.(type) {    case *User:        h.Links["self"] = fmt.Sprintf("http://user/%d", s.Id)    case *Session:        h.Links["self"] = fmt.Sprintf("http://session/%d", s.Id)    }    return json.MarshalIndent(h, "", "    ")}func main() {    u := &User{123, "James Dean"}    s := &Session{456, 123}    json, err := MarshalHateoas(u)    if err != nil {        panic(err)    } else {        fmt.Println("User JSON:")        fmt.Println(string(json))    }    json, err = MarshalHateoas(s)    if err != nil {        panic(err)    } else {        fmt.Println("Session JSON:")        fmt.Println(string(json))    }}在我的情况下,我试图让渲染的 JSON 看起来正确,这意味着:User JSON:{    "id": 123,    "name": "James Dean",    "_links": {        "self": "http://user/123"    }}Session JSON:{    "id": 456,    "userId": 123,    "_links": {        "self": "http://session/456"    }}文档中没有关于处理 JSON 中匿名成员的明确文档:匿名结构字段通常被编组,就好像它们的内部导出字段是外部结构中的字段一样,受通常的 Go 可见性规则的约束,如下一段所述。在其 JSON 标记中给出名称的匿名结构字段被视为具有该名称,而不是匿名的。匿名结构体字段的处理在 Go 1.1 中是新的。在 Go 1.1 之前,匿名结构体字段被忽略。要强制忽略当前版本和早期版本中的匿名结构字段,请为该字段指定一个 JSON 标记“-”。这并不清楚是否有办法使之变平,或向 Marshaller 暗示我正在尝试做的事情。我确信可能存在,因为存在特殊情况,具有特殊含义的魔术名称可以在 XML 编组器中重命名 XML 文档的根元素。在这种情况下,我也没有以任何方式附加到代码,我的用例是有一个函数来接受interface{}, *http.Request, http.ResponseWriter和写回 HATEOAS 文档,打开传递的类型,以推断要写回的链接进入 JSON。(因此访问请求,请求主机、端口、方案等,以及类型本身以推断 URL 和已知字段等)
查看完整描述

3 回答

?
沧海一幻觉

TA贡献1824条经验 获得超5个赞

我认为您尝试生成的 JSON 不是有效的 JSON 对象,因此这可能是 JsonMarshal 不与您玩游戏的原因。


该对象可能无法通过 JavaScript 使用,因为它包含两个对象,除非您将这些对象包装在一个数组中。


[

    {

        "id": 123,

        "name": "James Dean",

        "_links": {

            "self": "http://user/123"

        }

    },

    {

        "id": 456,

        "userId": 123,

        "_links": {

            "self": "http://session/456"

        }

    }

]

然后你就可以使用这个 JSON,例如:


var user, session;

user = jsonString[0]; 

session = jsonString[1];

考虑给你的对象根名称可能是一个更好的考虑,例如:


{

    "user": {

        "id": 123,

        "name": "James Dean",

        "_links": {

            "self": "http://user/123"

        }

    },

    "session": {

        "id": 456,

        "userId": 123,

        "_links": {

            "self": "http://session/456"

        }

    }

}

并消耗为,例如:


var user, session;

user = jsonString.user;

session = jsonString.session;

我希望这可以帮助你


查看完整回答
反对 回复 2021-07-12
?
大话西游666

TA贡献1817条经验 获得超14个赞

利用omitempty标签和一些逻辑,以便您可以使用单一类型为不同情况生成正确的输出。


诀窍是知道 JSON 编码器何时将值视为空。从 encoding/json 文档:


空值是 false、0、任何 nil 指针或接口值,以及任何长度为零的数组、切片、映射或字符串。


这是您的程序稍作修改以产生您想要的输出。当某些字段的值为“空”时,它会省略某些字段 - 具体而言,JSON 编码器将省略带有“0”作为值的整数并使用零长度映射。


package main


import (

    "encoding/json"

    "fmt"

)


type User struct {

    Id     int               `json:"id"`

    Name   string            `json:"name,omitempty"`

    UserId int               `json:"userId,omitempty"`

    Links  map[string]string `json:"_links,omitempty"`

}


func Marshal(u *User) ([]byte, error) {

    u.Links = make(map[string]string)

    if u.UserId != 0 {

        u.Links["self"] = fmt.Sprintf("http://user/%d", u.UserId)

    } else if u.Id != 0 {

        u.Links["self"] = fmt.Sprintf("http://session/%d", u.Id)

    }

    return json.MarshalIndent(u, "", "    ")

}


func main() {

    u := &User{Id: 123, Name: "James Dean"}

    s := &User{Id: 456, UserId: 123}

    json, err := Marshal(u)

    if err != nil {

        panic(err)

    } else {

        fmt.Println(string(json))

    }

    json, err = Marshal(s)

    if err != nil {

        panic(err)

    } else {

        fmt.Println(string(json))

    }

}


查看完整回答
反对 回复 2021-07-12
  • 3 回答
  • 0 关注
  • 310 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信