在 Golang 中解组带有日期的嵌套 JSON 对象
Unmarshalling nested JSON objects with dates in Golang
我是 Golang 的菜鸟。我努力地完成了一些事情。
我正在以嵌套方式处理 JSON 包含日期的文件。
我遇到了一些解决方法,可以将日期从 JSON 数据解组到 time.Time
,但我很难处理嵌套的数据。
以下代码(在 Whosebug 中获得)很容易理解,因为它创建了一个 用户定义的 函数来首先将时间对象解析为 string
然后time.Time
time.Parse
.
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
const dateFormat = "2006-01-02"
const data = `{
"name": "Gopher",
"join_date": "2007-09-20"
}`
type User struct {
Name string `json:"name"`
JoinDate time.Time `json:"join_date"`
}
func (u *User) UnmarshalJSON(p []byte) error {
var aux struct {
Name string `json:"name"`
JoinDate string `json:"join_date"`
}
err := json.Unmarshal(p, &aux)
if err != nil {
return err
}
t, err := time.Parse(dateFormat, aux.JoinDate)
if err != nil {
return err
}
u.Name = aux.Name
u.JoinDate = t
return nil
}
func main() {
var u User
err := json.Unmarshal([]byte(data), &u)
if err != nil {
log.Fatal(err)
}
fmt.Println(u.JoinDate.Format(time.RFC3339))
}
到目前为止,还不错。
现在我想扩展它以处理 JSON 中的嵌套日期字段,如下例所示:
[{
"name": "Gopher",
"join_date": "2007-09-20",
"cashflow": [
{"date": "2021-02-25",
"amount": 100},
{"date": "2021-03-25",
"amount": 105}
]
}]
我想得到的struct
是:
type Record []struct {
Name string `json:"name"`
JoinDate time.Time `json:"join_date"`
Cashflow []struct {
Date time.Time `json:"date"`
Amount int `json:"amount"`
} `json:"cashflow"`
}
感谢您的帮助。
要使用您已有的模式解决此问题,您可以为内部结构编写一个单独的解组函数。您可以通过将内部结构提升到它自己的命名结构,然后编写函数来做到这一点。
type CashflowRec struct {
Date time.Time `json:"date"`
Amount int `json:"amount"`
}
type Record struct {
Name string `json:"name"`
JoinDate time.Time `json:"join_date"`
Cashflow []CashflowRec `json:"cashflow"`
}
您已经展示了如何为 CashflowRec
编写解组函数,它看起来与您的用户函数几乎相同。 Record
的解组函数将在调用
时使用它
func (u *Record) UnmarshalJSON(p []byte) error {
var aux struct {
Name string `json:"name"`
JoinDate string `json:"join_date"`
Cashflow []CashflowRec `json:"cashflow"`
}
err := json.Unmarshal(p, &aux)
工作示例:https://go.dev/play/p/1X7BJ4NETM0
旁白 1 我在看这个的时候学到了一些有趣的东西:因为你已经提供了自己的解组函数,所以你实际上不需要 json
标签你原来的结构。这些是 json 包提供的解组器的提示。您可能仍应保留它们,以防您稍后必须编组该结构。这是没有这些标签的工作方式:https://go.dev/play/p/G2VWopO_A3t
aside 2 您可能会发现不使用 time.Time
更简单,而是创建您自己的新类型,然后为该类型提供自己的解组器。这为您提供了一个有趣的选择,即只编写一个解组器,但这是否成功取决于您稍后对该结构进行的其他操作。仍然使用嵌套匿名结构的工作示例:https://go.dev/play/p/bJUcaw3_r41
type dateType time.Time
type Record struct {
Name string `json:"name"`
JoinDate dateType `json:"join_date"`
Cashflow []struct {
Date dateType `json:"date"`
Amount int `json:"amount"`
} `json:"cashflow"`
}
func (c *dateType) UnmarshalJSON(p []byte) error {
var s string
if err := json.Unmarshal(p, &s); err != nil {
return err
}
t, err := time.Parse(dateFormat, s)
if err != nil {
return err
}
*c = dateType(t)
return nil
}
我是 Golang 的菜鸟。我努力地完成了一些事情。 我正在以嵌套方式处理 JSON 包含日期的文件。
我遇到了一些解决方法,可以将日期从 JSON 数据解组到 time.Time
,但我很难处理嵌套的数据。
以下代码(在 Whosebug 中获得)很容易理解,因为它创建了一个 用户定义的 函数来首先将时间对象解析为 string
然后time.Time
time.Parse
.
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
const dateFormat = "2006-01-02"
const data = `{
"name": "Gopher",
"join_date": "2007-09-20"
}`
type User struct {
Name string `json:"name"`
JoinDate time.Time `json:"join_date"`
}
func (u *User) UnmarshalJSON(p []byte) error {
var aux struct {
Name string `json:"name"`
JoinDate string `json:"join_date"`
}
err := json.Unmarshal(p, &aux)
if err != nil {
return err
}
t, err := time.Parse(dateFormat, aux.JoinDate)
if err != nil {
return err
}
u.Name = aux.Name
u.JoinDate = t
return nil
}
func main() {
var u User
err := json.Unmarshal([]byte(data), &u)
if err != nil {
log.Fatal(err)
}
fmt.Println(u.JoinDate.Format(time.RFC3339))
}
到目前为止,还不错。 现在我想扩展它以处理 JSON 中的嵌套日期字段,如下例所示:
[{
"name": "Gopher",
"join_date": "2007-09-20",
"cashflow": [
{"date": "2021-02-25",
"amount": 100},
{"date": "2021-03-25",
"amount": 105}
]
}]
我想得到的struct
是:
type Record []struct {
Name string `json:"name"`
JoinDate time.Time `json:"join_date"`
Cashflow []struct {
Date time.Time `json:"date"`
Amount int `json:"amount"`
} `json:"cashflow"`
}
感谢您的帮助。
要使用您已有的模式解决此问题,您可以为内部结构编写一个单独的解组函数。您可以通过将内部结构提升到它自己的命名结构,然后编写函数来做到这一点。
type CashflowRec struct {
Date time.Time `json:"date"`
Amount int `json:"amount"`
}
type Record struct {
Name string `json:"name"`
JoinDate time.Time `json:"join_date"`
Cashflow []CashflowRec `json:"cashflow"`
}
您已经展示了如何为 CashflowRec
编写解组函数,它看起来与您的用户函数几乎相同。 Record
的解组函数将在调用
func (u *Record) UnmarshalJSON(p []byte) error {
var aux struct {
Name string `json:"name"`
JoinDate string `json:"join_date"`
Cashflow []CashflowRec `json:"cashflow"`
}
err := json.Unmarshal(p, &aux)
工作示例:https://go.dev/play/p/1X7BJ4NETM0
旁白 1 我在看这个的时候学到了一些有趣的东西:因为你已经提供了自己的解组函数,所以你实际上不需要 json
标签你原来的结构。这些是 json 包提供的解组器的提示。您可能仍应保留它们,以防您稍后必须编组该结构。这是没有这些标签的工作方式:https://go.dev/play/p/G2VWopO_A3t
aside 2 您可能会发现不使用 time.Time
更简单,而是创建您自己的新类型,然后为该类型提供自己的解组器。这为您提供了一个有趣的选择,即只编写一个解组器,但这是否成功取决于您稍后对该结构进行的其他操作。仍然使用嵌套匿名结构的工作示例:https://go.dev/play/p/bJUcaw3_r41
type dateType time.Time
type Record struct {
Name string `json:"name"`
JoinDate dateType `json:"join_date"`
Cashflow []struct {
Date dateType `json:"date"`
Amount int `json:"amount"`
} `json:"cashflow"`
}
func (c *dateType) UnmarshalJSON(p []byte) error {
var s string
if err := json.Unmarshal(p, &s); err != nil {
return err
}
t, err := time.Parse(dateFormat, s)
if err != nil {
return err
}
*c = dateType(t)
return nil
}