英文:
Golang unmarshal JSON response, then convert the field name into snake_case
问题
我想要获取具有PascalCase格式的源的带有json标签的数据,并将其保存到我的数据库中。但在进入数据库之前,我想将PascalCase格式更改为snake_case格式。
我的问题似乎与此问题相反(https://stackoverflow.com/questions/63248152/golang-unmarshal-an-json-response-then-marshal-with-struct-field-names)。但是,我想在name字段中使用snake_case而不是PascalCase。
以下是我编写的示例代码:
package main
import (
"encoding/json"
"log"
)
// models data to save in DB
type (
Person struct {
FirstName string `json:"FirstName"`
LastName string `json:"LastName"`
Children []ChildData `json:"Children,omitempty"`
}
ChildData struct {
ChildName string `json:"ChildName"`
Age int `json:"Age"`
FavColor string `json:"FavColor"`
}
PersonOut struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Children []ChildData `json:"children,omitempty"`
}
ChildDataOut struct {
ChildName string `json:"child_name"`
Age int `json:"age"`
FavColor string `json:"fav_color"`
}
)
// grisha is data from fetch API
var grisha = map[string]interface{}{
"FirstName": "Grisha",
"LastName": "Jeager",
"Children": []map[string]interface{}{
{
"ChildName": "Zeke",
"Age": 2,
"FavColor": "blue",
}, {
"ChildName": "Eren",
"Age": 3,
"FavColor": "red",
},
},
}
func getJsonfromAPI(data map[string]interface{}) []byte {
grishaJson, _ := json.MarshalIndent(grisha, "", " ")
return grishaJson
}
func parsingJSON(jsonInput []byte) {
var person Person
json.Unmarshal(jsonInput, &person)
out := PersonOut(person)
payload2, err := json.MarshalIndent(out, "", " ")
if err != nil {
panic(err)
}
log.Println(string(payload2))
}
func main() {
data := getJsonfromAPI(grisha)
parsingJSON(data)
}
我想要的结果是:
{
"first_name": "Grisha",
"last_name": "Jeager",
"children": [
{
"child_name": "Zeke",
"age": 2,
"fav_color": "blue"
},
{
"child_name": "Eren",
"age": 3,
"fav_color": "red"
}
]
}
但是结果在嵌套字段中仍然是PascalCase:
{
"first_name": "Grisha",
"last_name": "Jeager",
"children": [
{
"ChildName": "Zeke",
"Age": 2,
"FavColor": "blue"
},
{
"ChildName": "Eren",
"Age": 3,
"FavColor": "red"
}
]
}
我想知道如何将嵌套结构的字段名从解组JSON中转换为snake_case。
英文:
I want to get data with json tag whose source has PascalCase format and save it to my database. But before going into the database, I want to change the PascalCase format to snake_case format.
My question seems to be the opposite of this question (https://stackoverflow.com/questions/63248152/golang-unmarshal-an-json-response-then-marshal-with-struct-field-names). But instead of having PascalCase, I want to have snake_case in the name field
Here is the sample code that i wrote:
package main
import (
"encoding/json"
"log"
)
// models data to save in DB
type (
Person struct {
FirstName string `json:"FirstName"`
LastName string `json:"LastName"`
Children []ChildData `json:"Children,omitempty"`
}
ChildData struct {
ChildName string `json:"ChildName"`
Age int `json:"Age"`
FavColor string `json:"FavColor"`
}
PersonOut struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Children []ChildData `json:"children,omitempty"`
}
ChildDataOut struct {
ChildName string `json:"child_name"`
Age int `json:"age"`
FavColor string `json:"fav_Color"`
}
)
// grisha is data from fetch API
var grisha = map[string]interface{}{
"FirstName": "Grisha",
"LastName": "Jeager",
"Children": []map[string]interface{}{
{
"ChildName": "Zeke",
"Age": 2,
"FavColor": "blue",
}, {
"ChildName": "Eren",
"Age": 3,
"FavColor": "red",
},
},
}
func getJsonfromAPI(data map[string]interface{}) []byte {
grishaJson, _ := json.MarshalIndent(grisha, "", " ")
return grishaJson
}
func parsingJSON(jsonInput []byte) {
var person Person
json.Unmarshal(jsonInput, &person)
out := PersonOut(person)
payload2, err := json.MarshalIndent(out, "", " ")
if err != nil {
panic(err)
}
log.Println(string(payload2))
}
func main() {
data := getJsonfromAPI(grisha)
parsingJSON(data)
}
The result that I want is like
{
"first_name": "Grisha",
"last_name": "Jeager",
"children": [
{
"child_name": "Zeke",
"age": 2,
"fav_color": "blue"
},
{
"child_name": "Eren",
"age": 3,
"fav_color": "red"
}
]
}
but the result is still having PascalCase in the nested field:
{
"first_name": "Grisha",
"last_name": "Jeager",
"children": [
{
"ChildName": "Zeke",
"Age": 2,
"FavColor": "blue"
},
{
"ChildName": "Eren",
"Age": 3,
"FavColor": "red"
}
]
}
I was wondering how to convert field name for the nested structure from unmarshal JSON.
答案1
得分: 4
将一个结构体转换为另一个结构体只有在它们的底层类型(忽略标签)完全相同的情况下才能成功。如果底层类型不相同,则无法进行转换。
以结构体S1
和S2
为例,在下面的代码片段中,它们的底层类型是相同的,因此可以相互转换:
type S1 struct {
Field T1
}
type S2 struct {
Field T1
}
type T1 string
_ = S2(S1{}) // 可以转换
然而,在下面的代码片段中,它们的底层类型不相同,因此无法相互转换:
type S1 struct {
Field T1
}
type S2 struct {
Field T2
}
type T1 string
type T2 string
_ = S2(S1{}) // 无法将类型为S1的值转换为类型S2
要了解更多详细信息,请阅读有关转换的规范:https://go.dev/ref/spec#Conversions
因此,要在两个底层类型不相同的结构体之间进行转换,您必须逐个字段地手动进行转换。但是,在JSON编组的情况下,您可以通过实现json.Marshaler
接口并让各个实例“自行转换”来使代码更加简洁。
type Person struct {
FirstName string `json:"FirstName"`
LastName string `json:"LastName"`
Children []ChildData `json:"Children"`
}
func (p Person) MarshalJSON() ([]byte, error) {
type T struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Children []ChildData `json:"children"`
}
return json.Marshal(T(p))
}
type ChildData struct {
ChildName string `json:"ChildName"`
Age int `json:"Age"`
FavColor string `json:"FavColor"`
}
func (d ChildData) MarshalJSON() ([]byte, error) {
type T struct {
ChildName string `json:"child_name"`
Age int `json:"age"`
FavColor string `json:"fav_color"`
}
return json.Marshal(T(d))
}
https://go.dev/play/p/UGJY5p490Gs
英文:
Converting one struct to another works only if their their underlying types (ignoring tags) are identical. If the underlying types are not identical you cannot do the conversion.
Take for example the structs S1
and S2
, in the following snippet their underlying types are identical and you can convert one to the other:
type S1 struct {
Field T1
}
type S2 struct {
Field T1
}
type T1 string
_ = S2(S1{}) // ok
However, in the next snippet their underlying types are NOT identical and therefore you cannot convert one to the other:
type S1 struct {
Field T1
}
type S2 struct {
Field T2
}
type T1 string
type T2 string
_ = S2(S1{}) // cannot convert S1{} (value of type S1) to type S2
For more details read the spec on conversions here: https://go.dev/ref/spec#Conversions
So to convert between two struct whose underlying types are NOT identical you have to manually do the conversion field by field. However, in the case of JSON marshaling, you can make this a bit nicer by implementing the json.Marshaler
interface and have the individual instances "convert themselves".
type Person struct {
FirstName string `json:"FirstName"`
LastName string `json:"LastName"`
Children []ChildData `json:"Children"`
}
func (p Person) MarshalJSON() ([]byte, error) {
type T struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Children []ChildData `json:"children"`
}
return json.Marshal(T(p))
}
type ChildData struct {
ChildName string `json:"ChildName"`
Age int `json:"Age"`
FavColor string `json:"FavColor"`
}
func (d ChildData) MarshalJSON() ([]byte, error) {
type T struct {
ChildName string `json:"child_name"`
Age int `json:"age"`
FavColor string `json:"fav_color"`
}
return json.Marshal(T(d))
}
答案2
得分: 0
我们需要:
- 将Person映射到PersonOut
- 将ChildData映射到ChildDataOut
func childDataToChildDataOut(childData ChildData) ChildDataOut {
return ChildDataOut{
ChildName: childData.ChildName,
Age: childData.Age,
FavColor: childData.FavColor,
}
}
func personToPersonOut(person Person) PersonOut {
var children []ChildDataOut
for _, childData := range person.Children {
childDataOut := childDataToChildDataOut(childData)
children = append(children, childDataOut)
}
return PersonOut{
FirstName: person.FirstName,
LastName: person.LastName,
Children: children,
}
}
英文:
https://go.dev/play/p/l4O8KBNrm1T
We need to:
- Mapping Person to PersonOut
- Mapping ChildData to ChildDataOut
func childDataToChildDataOut(childData ChildData) ChildDataOut {
return ChildDataOut{
ChildName: childData.ChildName,
Age: childData.Age,
FavColor: childData.FavColor,
}
}
func personToPersonOut(person Person) PersonOut {
var children []ChildDataOut
for _, childData := range person.Children {
childDataOut := childDataToChildDataOut(childData)
children = append(children, childDataOut)
}
return PersonOut{
FirstName: person.FirstName,
LastName: person.LastName,
Children: children,
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论