How to unmarshall a json file with nested objects which can be different from eachother in Golang

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

How to unmarshall a json file with nested objects which can be different from eachother in Golang

问题

以下是翻译好的内容:

type User struct {
   Name string `json:"name"`
   Age int `json:"age"`
   Occupation string `json:"occupation"`
   Social map[string]string `json:"social"`
}

type Social struct {
  Facebook string `json:"facebook"`
  Twitter string `json:"twitter"`
}

这是正确的反序列化 JSON 的方式吗?由于 Social 结构体需要一个用于 Facebook 和一个用于 Twitter 的不同字符串,所以会失败吗?有没有更好的方法来反序列化这样的 JSON?

英文:

With a json file that looks something like this, where someone can only have one social but it could be different depending on the person, how would I unmarshal this into a struct.

[
  {
    "name": "Bob",
    "age": 14,
    "occupation": "Builder",
    "social": {
        "facebook": "Bob_the_builder"
  },
  {
    "name": "Alice",
    "age": 14,
    "occupation": "Builder",
    "social": {
        "twitter": "Alice_the_builder"
  }
]

My current struct variables looks like this.

type User struct {
   Name String 'json:"name"'
   Age int 'json:"age"'
   Occupation String 'json:"occupation"'
   Social Social 'json:"social"'
}

type Social struct {
  Facebook String 'json:"facebook"'
  Twitter String 'json:"twitter"'
}

Is this the correct way to unmarshall the json or will it fail as the 'Social' struct wants two different strings one for Facebook and one for Twitter. Is there a better way to unmarshall a json like this?

答案1

得分: 2

你提供的示例应该可以工作,只是会使其中一个字符串为空。

如果你想用两个不同的结构体替换Social,你可以将Social定义为一个接口,然后让这两个新的结构体都实现该接口。然后使用json.RawMessage来延迟对social中的JSON进行解析。以下是godocs中给出的示例代码:

import (
	"encoding/json"
	"fmt"
	"log"
)

func main() {
	type Color struct {
		Space string
		Point json.RawMessage // 延迟解析,直到我们知道颜色空间
	}
	type RGB struct {
		R uint8
		G uint8
		B uint8
	}
	type YCbCr struct {
		Y  uint8
		Cb int8
		Cr int8
	}

	var j = []byte(`[
	{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
	{"Space": "RGB",   "Point": {"R": 98, "G": 218, "B": 255}}
]`)
	var colors []Color
	err := json.Unmarshal(j, &colors)
	if err != nil {
		log.Fatalln("error:", err)
	}

	for _, c := range colors {
		var dst interface{}
		switch c.Space {
		case "RGB":
			dst = new(RGB)
		case "YCbCr":
			dst = new(YCbCr)
		}
		err := json.Unmarshal(c.Point, dst)
		if err != nil {
			log.Fatalln("error:", err)
		}
		fmt.Println(c.Space, dst)
	}
}

在这个示例中,他们使用一个字符串来指示应该将Point解析为哪个结构体。在你的情况下,你可能需要先将social解析为map[string]interface{},然后根据字段确定应该使用哪种类型。或者在User结构体中添加一个socialType字段。

英文:

The example you provided should work, it will just leave one of your strings empty.

If you want to replace Social with 2 different structs, you can make Social an interface which both new structs implement. Then use json.RawMessage to delay the unmarshalling of the json in social. This is the example given in the godocs:

import (
	"encoding/json"
	"fmt"
	"log"
)

func main() {
	type Color struct {
		Space string
		Point json.RawMessage // delay parsing until we know the color space
	}
	type RGB struct {
		R uint8
		G uint8
		B uint8
	}
	type YCbCr struct {
		Y  uint8
		Cb int8
		Cr int8
	}

	var j = []byte(`[
	{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
	{"Space": "RGB",   "Point": {"R": 98, "G": 218, "B": 255}}
]`)
	var colors []Color
	err := json.Unmarshal(j, &colors)
	if err != nil {
		log.Fatalln("error:", err)
	}

	for _, c := range colors {
		var dst interface{}
		switch c.Space {
		case "RGB":
			dst = new(RGB)
		case "YCbCr":
			dst = new(YCbCr)
		}
		err := json.Unmarshal(c.Point, dst)
		if err != nil {
			log.Fatalln("error:", err)
		}
		fmt.Println(c.Space, dst)
	}
}

In this example they use a string to indicate as which struct to unmarshall Point. In your case you may need to first unmarshall social as map[string]interface{} and determine which type should be used based on the fields. Or add a socialType field to the User struct.

huangapple
  • 本文由 发表于 2021年11月26日 01:23:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/70115158.html
匿名

发表评论

匿名网友

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

确定