【问题标题】:How to Marshall json from one struct to another with different json tags in Go?如何在 Go 中使用不同的 json 标签将 json 从一个结构编组到另一个结构?
【发布时间】:2020-01-12 19:25:41
【问题描述】:

我正在创建一个 Go 应用程序,它使用来自多个来源的数据,这些来源都具有相似的数据,但其数据/响应的结构不同。这些响应需要编组到一个公共结构中,然后发送到另一个服务。

通用结构:

type common struct {
   ID         string `json:id`
   GivenName  string `json:given_name`
   FamilyName string `json:family_name`
   Email:     string `json:email`
}

一个回应:

{
   "id": "123",
   "first_name": "john",
   "last_name": "smith",
   "email": "js@mail.com"
}

另一个回应:

{
   "id": "456",
   "first": "larry",
   "last": "smith",
   "email": {
      "primary": "larry@mail.com"
   }
}

如何将具有一种结构的 json 响应编组为具有不同结构的结构?

【问题讨论】:

  • 如果不是该电子邮件字段,您可以创建两个具有不同 json 标签的相同结构,并简单地说 v1=v2 其中 v1 是一个结构,v2 是另一个。但是通过电子邮件翻译这是不可能的。您仍然可以做两个结构,并逐个字段地从一个结构复制到另一个。
  • 您不能将 encoding/json 与一个结构和不同的名称一起使用。死的简单。您要么必须具有具有不同标签的不同结构,要么使用例如一个 map[string]interface{} 作为序列化的源。在任何情况下,您都必须复制。或者您自己编写 JSON 序列化。

标签: json go struct marshalling


【解决方案1】:

我认为你可以根据不同的来源定义不同的结构。然后,将其转换为通用结构。

此方法灵活、易读且在添加新源时易于实现。

示例代码如下:

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID         string `json:id`
    GiveName   string `json:given_name`
    FamilyName string `json:family_name`
    Email      string `json:email`
}

type UserFromMySQL struct {
    ID        string `json:"id"`
    FirstName string `json:"first_name"`
    LastName  string `json:"last_name"`
    Email     string `json:"email"`
}

func (u *UserFromMySQL) GetUser() *User {
    return &User{
        ID:         u.ID,
        GiveName:   u.FirstName,
        FamilyName: u.LastName,
        Email:      u.Email,
    }
}

func main() {
    um := new(UserFromMySQL)

    b := []byte(`{
   "id": "123",
   "first_name": "john",
   "last_name": "smith",
   "email": "js@mail.com"
}`)
    err := json.Unmarshal(b, um)
    if err != nil {
        panic(err)
    }

    fmt.Printf("%+v\n", um)
    fmt.Printf("%+v\n", um.GetUser())
}

当然,你可以通过添加冗余字段来做到这一点,定义user如下:

type Email {
    Primary string `json:"primary"`
}

type User struct {
    ID           string `json:"id"`
    GiveName     string `json:"given_name"`
    FamilyName   string `json:"family_name"`
    FirstName    string `json:"last_name"`
    LastName     string `json:"last_name"`
    Email        string `json:"email"`
}

选择适合您的方式。我更喜欢第一个。

【讨论】:

  • @ polo xue 你的第一个例子正是我想要的。谢谢!
【解决方案2】:

我建议您为您拥有的每个数据分离结构。

Golang 是一种强类型语言,因此每个结构应该只表示一种数据类型。这不仅消除了关岛代码,还减少了其他开发人员需要跟踪数据类型的时间,这有时会在 Python 等非强类型语言中发生。

无论如何,如果您真的需要在同一个结构中表示这些数据,您可以编写如下。

type User struct {
   ID         string `json:"id,omitempty"`
   GivenName  string `json:"given_name,omitempty"`
   FamilyName string `json:"family_name,omitempty"`
   FirstName  string `json:"first,omitempty"`
   LastName   string `json:"last,omitempty"`
   PlainEmail string `json:"plain_email,omitempty"`
   Email struct{
    Primary string `json:"primary"`
   } `json:"email,omitempty"`
}

在 JSON 标记中添加 omitempty,因此如果使用用户类型 A 创建结构,则类型 B 字段将不会在 JSON 中表示。但是,我不推荐这种方法,但如果你需要,这就是方法。

无论如何,EmailPlainEmail JSON标签需要分开,否则编译器会混淆。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 2020-11-17
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    相关资源
    最近更新 更多