英文:
How to umarshall plain JSON with nested struct
问题
GO新手问题。我这里有一个简单的JSON负载,我试图使用嵌套结构进行解组:
负载:
{
"name": "foo-bar",
"profileName": "my-profile-name"
}
和结构体:
type Project struct {
Name string `json:"name"`
Profile *Profile `json:"profileName,omitempty"`
}
type Profile struct {
// Name is the name of the namespace created for the project
Name string `json:"profileName"`
}
经过多次尝试和错误,我找到了一个可行的解决方案
package main
import (
"encoding/json"
"fmt"
)
type Project struct {
Name string `json:"name"`
Profile *Profile `json:"profileName,omitempty"`
}
type Profile struct {
// Name is the name of the namespace created for the project
Name string `json:"profileName"`
}
func (p *Profile) UnmarshalJSON(data []byte) error {
// 首先尝试解组为字符串
var s string
err := json.Unmarshal(data, &s)
if err == nil {
p.Name = s
return nil
}
// 否则解组为结构体
type Alias Profile
aux := &struct {
*Alias
}{
Alias: (*Alias)(p),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
*p = *(*Profile)(aux.Alias)
return nil
}
func main() {
payload := []byte(`{
"name": "foo-bar",
"profileName": "my-profile-name"
}`)
project := Project{
Profile: &Profile{},
}
err := json.Unmarshal(payload, &project)
if err != nil {
panic(err)
}
fmt.Printf("Name: %s\nProfile Name: %s", project.Name, project.Profile.Name)
}
但是这看起来有点繁琐和冗长。有没有更好的方法来做到这一点?谢谢
英文:
GO newbie question. I have a simple JSON payload here, which I'm trying to unmarshall with a nested struct:
The payload:
{
"name": "foo-bar",
"profileName": "my-profile-name"
}
and the structs:
type Project struct {
Name string `json:"name"`
Profile *Profile `json:"profileName,omitempty"`
}
type Profile struct {
// Name is the name of the namespace created for the project
Name string `json:"profileName"`
}
After a lot of trials and errors I landed on the solution that works
package main
import (
"encoding/json"
"fmt"
)
type Project struct {
Name string `json:"name"`
Profile *Profile `json:"profileName,omitempty"`
}
type Profile struct {
// Name is the name of the namespace created for the project
Name string `json:"profileName"`
}
func (p *Profile) UnmarshalJSON(data []byte) error {
// try to unmarshal as a string first
var s string
err := json.Unmarshal(data, &s)
if err == nil {
p.Name = s
return nil
}
// otherwise unmarshal as a struct
type Alias Profile
aux := &struct {
*Alias
}{
Alias: (*Alias)(p),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
*p = *(*Profile)(aux.Alias)
return nil
}
func main() {
payload := []byte(`{
"name": "foo-bar",
"profileName": "my-profile-name"
}`)
project := Project{
Profile: &Profile{},
}
err := json.Unmarshal(payload, &project)
if err != nil {
panic(err)
}
fmt.Printf("Name: %s\nProfile Name: %s", project.Name, project.Profile.Name)
}
but this just looks a little too cumbersome and verbose. Is there a better way to do this? Thanks
答案1
得分: 1
你可以按照以下方式进行操作:
type Profile struct {
Name string `json:"profileName"`
}
func (p *Profile) UnmarshalJSON(data []byte) error {
if len(data) == 4 && string(data) == "null" { // null?
return nil
} else if data[0] == '"' { // string?
return json.Unmarshal(data, &p.Name)
} else if data[0] == '{' { // object?
type P Profile
return json.Unmarshal(data, (*P)(p))
}
return nil // 或者返回错误
}
https://go.dev/play/p/-rOhbmWvmWs
英文:
You can do the following:
type Profile struct {
Name string `json:"profileName"`
}
func (p *Profile) UnmarshalJSON(data []byte) error {
if len(data) == 4 && string(data) == "null" { // null?
return nil
} else if data[0] == '"' { // string?
return json.Unmarshal(data, &p.Name)
} else if data[0] == '{' { // object?
type P Profile
return json.Unmarshal(data, (*P)(p))
}
return nil // or return error
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论