Go:使用多种类型解组 JSON
Go: Unmarshalling JSON with multiple types
我在将 JSON 响应解组到结构中时遇到问题。我遇到的问题是邮政编码可以 return 作为字符串或整数。如何编写解组方法来检查 zip 是否为 int 并强制将其存储为字符串?
结构:
type CustomerAddress struct {
Line1 string `json:"line1"`
City string `json:"city"`
State string `json:"state"`
Zip string `json:"zip"`
IsPrimaryAddress string `json:"isPrimaryAddress"`
}
示例Json:
address": [
{
"line1": "555 ADDRESS PLACE",
"city": "DALLAS",
"state": "TX",
"isPrimaryAddress": "Y",
"zip": 55555
}
]
解组后,结果应成功将 zip 转换为字符串:
address": [
{
"line1": "555 ADDRESS PLACE",
"city": "DALLAS",
"state": "TX",
"isPrimaryAddress": "Y",
"zip": "55555"
}
]
作为尝试,我尝试使用 ZipWrapper。
type CustomerAddress struct {
Line1 string `json:"line1"`
City string `json:"city"`
State string `json:"state"`
Zip ZipWrapper `json:"zip"`
IsPrimaryAddress string `json:"isPrimaryAddress"`
}
type ZipWrapper struct {
Zip string
}
func (w *ZipWrapper ) UnmarshalJSON(data []byte) (err error) {
if zip, err := strconv.Atoi(string(data)); err == nil {
w.Zip = strconv.Itoa(zip)
return nil
}
return json.Unmarshal(data, &w.Zip)
}
除了 zip 现在是 CustomerAddress 中的嵌套结构外,这几乎成功了,这不是我想要的:
address": [
{
"line1": "555 ADDRESS PLACE",
"city": "DALLAS",
"state": "TX",
"isPrimaryAddress": "Y",
"zip": {
"Zip": "55555"
}
}
]
有什么想法吗?我觉得这是一个相对容易的任务,但我是一个完全的 Go 菜鸟,还没有完全理解 Unmarshalling 的工作原理。
json
软件包提供 json.Number
类型来执行此操作:
type CustomerAddress struct {
Line1 string `json:"line1"`
City string `json:"city"`
State string `json:"state"`
Zip json.Number `json:"zip"`
IsPrimaryAddress string `json:"isPrimaryAddress"`
}
https://play.golang.org/p/PIKSh2c6Mm
如果您需要自己在没有嵌套结构的情况下执行此操作,您可以使用与 json.Number
相同的方式声明类型,并将 string
作为基础类型
type ZipWrapper string
func (w *ZipWrapper) UnmarshalJSON(data []byte) (err error) {
if len(data) > 1 && data[0] == '"' && data[len(data)-1] == '"' {
data = data[1 : len(data)-1]
}
if _, err := strconv.Atoi(string(data)); err != nil {
return err
}
*w = ZipWrapper(string(data))
return nil
}
Jim 在另一个关于将 ZipWrapper 定义为字符串的回答中所说的是,您可以采用与之前相同的方法,但不使用嵌套结构。
像这样定义字段:
Zip ZipWrapper `json:"zip"`
但是 ZipWrapper
定义如下:
type ZipWrapper string
你的UnmarshalJSON
函数可以是这样的:
func (w *ZipWrapper) UnmarshalJSON(data []byte) (err error) {
if zip, err := strconv.Atoi(string(data)); err == nil {
str := strconv.Itoa(zip)
*w = ZipWrapper(str)
return nil
}
var str string
err = json.Unmarshal(data, &str)
if err != nil {
return err
}
return json.Unmarshal([]byte(str), w)
}
这是一个可用的围棋游乐场:
我在将 JSON 响应解组到结构中时遇到问题。我遇到的问题是邮政编码可以 return 作为字符串或整数。如何编写解组方法来检查 zip 是否为 int 并强制将其存储为字符串?
结构:
type CustomerAddress struct {
Line1 string `json:"line1"`
City string `json:"city"`
State string `json:"state"`
Zip string `json:"zip"`
IsPrimaryAddress string `json:"isPrimaryAddress"`
}
示例Json:
address": [
{
"line1": "555 ADDRESS PLACE",
"city": "DALLAS",
"state": "TX",
"isPrimaryAddress": "Y",
"zip": 55555
}
]
解组后,结果应成功将 zip 转换为字符串:
address": [
{
"line1": "555 ADDRESS PLACE",
"city": "DALLAS",
"state": "TX",
"isPrimaryAddress": "Y",
"zip": "55555"
}
]
作为尝试,我尝试使用 ZipWrapper。
type CustomerAddress struct {
Line1 string `json:"line1"`
City string `json:"city"`
State string `json:"state"`
Zip ZipWrapper `json:"zip"`
IsPrimaryAddress string `json:"isPrimaryAddress"`
}
type ZipWrapper struct {
Zip string
}
func (w *ZipWrapper ) UnmarshalJSON(data []byte) (err error) {
if zip, err := strconv.Atoi(string(data)); err == nil {
w.Zip = strconv.Itoa(zip)
return nil
}
return json.Unmarshal(data, &w.Zip)
}
除了 zip 现在是 CustomerAddress 中的嵌套结构外,这几乎成功了,这不是我想要的:
address": [
{
"line1": "555 ADDRESS PLACE",
"city": "DALLAS",
"state": "TX",
"isPrimaryAddress": "Y",
"zip": {
"Zip": "55555"
}
}
]
有什么想法吗?我觉得这是一个相对容易的任务,但我是一个完全的 Go 菜鸟,还没有完全理解 Unmarshalling 的工作原理。
json
软件包提供 json.Number
类型来执行此操作:
type CustomerAddress struct {
Line1 string `json:"line1"`
City string `json:"city"`
State string `json:"state"`
Zip json.Number `json:"zip"`
IsPrimaryAddress string `json:"isPrimaryAddress"`
}
https://play.golang.org/p/PIKSh2c6Mm
如果您需要自己在没有嵌套结构的情况下执行此操作,您可以使用与 json.Number
相同的方式声明类型,并将 string
作为基础类型
type ZipWrapper string
func (w *ZipWrapper) UnmarshalJSON(data []byte) (err error) {
if len(data) > 1 && data[0] == '"' && data[len(data)-1] == '"' {
data = data[1 : len(data)-1]
}
if _, err := strconv.Atoi(string(data)); err != nil {
return err
}
*w = ZipWrapper(string(data))
return nil
}
Jim 在另一个关于将 ZipWrapper 定义为字符串的回答中所说的是,您可以采用与之前相同的方法,但不使用嵌套结构。
像这样定义字段:
Zip ZipWrapper `json:"zip"`
但是 ZipWrapper
定义如下:
type ZipWrapper string
你的UnmarshalJSON
函数可以是这样的:
func (w *ZipWrapper) UnmarshalJSON(data []byte) (err error) {
if zip, err := strconv.Atoi(string(data)); err == nil {
str := strconv.Itoa(zip)
*w = ZipWrapper(str)
return nil
}
var str string
err = json.Unmarshal(data, &str)
if err != nil {
return err
}
return json.Unmarshal([]byte(str), w)
}
这是一个可用的围棋游乐场: