簡體   English   中英

Golang 解組 JSON 響應,然后將字段名稱轉換為 snake_case

[英]Golang unmarshal JSON response, then convert the field name into snake_case

我想獲取帶有 json 標簽的數據,其來源具有 PascalCase 格式並將其保存到我的數據庫中。 但是在進入數據庫之前,我想將 PascalCase 格式更改為 snake_case 格式。

我的問題似乎與這個問題相反( Golang Unmarshal an JSON response, then marshal with Struct field names )。 但是我不想使用 PascalCase,而是希望在名稱字段中使用 snake_case

這是我寫的示例代碼:

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 轉換嵌套結構的字段名稱。

只有當它們的基礎類型(忽略標簽)相同時,將一個結構轉換為另一個結構才有效。 如果基礎類型不相同,則無法進行轉換。

以結構S1S2為例,在下面的代碼片段中,它們的基礎類型是相同的,您可以將一個轉換為另一個:

type S1 struct {
    Field T1
}
type S2 struct {
    Field T1
}
type T1 string

_ = S2(S1{}) // ok

但是,在下一個片段中,它們的基礎類型並不相同,因此您不能將一個轉換為另一個:

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

有關更多詳細信息,請閱讀此處的轉換規范: 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

https://go.dev/play/p/l4O8KBNrm1T

我們需要:

  1. 將 Person 映射到 PersonOut
  2. 將 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,
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM