【问题标题】:How effectively to change JSON keys如何有效地更改 JSON 键
【发布时间】:2021-06-27 19:26:12
【问题描述】:

在输入时,程序接收一个 JSON。

我需要返回相同的 JSON,但使用 camelCase 键。

是否有任何有效的方法可以将 JSON 中的所有 snake_case 键转换为 Go 中的 camelCase 键?

片段代码

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
    "regexp"
    "strings"
)

type CategoryList struct {
    Id   *string `json:"id"`
    Name *string `json:"name"`
}

type Data struct {
    AccessToken  *string         `json:"access_token"`
    Category     *string         `json:"category"`
    CategoryList []*CategoryList `json:"category_list"`
    Name         *string         `json:"name"`
    Id           *string         `json:"id"`
    Tasks        []*string       `json:"tasks"`
}

type Paging struct {
    Cursors *Cursors `json:"cursors"`
}

type Cursors struct {
    Before *string `json:"before"`
    After  *string `json:"after"`
}

type Categories struct {
    Data   []*Data `json:"data"`
    Paging *Paging `json:"paging"`
}

func main() {
    jsonString := `{"data":[{"access_token":"ABCDEFGHIJKLMNOPQRSTUVWXYZ","category":"First Category","category_list":[{"id":"2301","name":"Finance App"}]},{"access_token":"ZYXWVUTSRQPONMLKJIHGFEDCBA","category":"Second Category","category_list":[{"id":"2302","name":"Medical App"}]}],"paging":{"cursors":{"before":"MTA0MjcxMzIxNjYxNTkz","after":"MTA3MTA5NDcxNDc5MTk3"}}}`

    var categories map[string]interface{}
    if err := json.Unmarshal([]byte(jsonString), &categories); err != nil {
        panic(err)
    }

    modified := fromSnakeCaseToCamelCase(reflect.ValueOf(categories))

    result, err := json.Marshal(modified.Interface().(map[string]interface{}))
    if err != nil {
        panic(err)
    }
    fmt.Println(string(result))
}

func fromSnakeCaseToCamelCase(value reflect.Value) reflect.Value {
    switch value.Kind() {
        case reflect.Array, reflect.Slice:
            for i := 0; i < value.Len(); i++ {
                nestedValue := value.Index(i)

                fromSnakeCaseToCamelCase(nestedValue)
            }
        case reflect.Map:
            for _, keyName := range value.MapKeys() {
                nestedValue := value.MapIndex(keyName)

                newKeyName := reflect.ValueOf(convertToCamelCase(keyName.Interface().(string)))
                value.SetMapIndex(newKeyName, nestedValue)

                oldKeyName := reflect.ValueOf(keyName.Interface().(string))
                value.SetMapIndex(oldKeyName, reflect.Value{})

                fromSnakeCaseToCamelCase(nestedValue)
            }
        default:
            // pass
    }
    return value
}

var link = regexp.MustCompile("(^[A-Za-z]|_[A-Za-z])")

func convertToCamelCase(str string) string {
    return link.ReplaceAllStringFunc(str, func(s string) string {
        r := strings.NewReplacer("_", "")
        return strings.ToUpper(r.Replace(s))
    })
}

【问题讨论】:

  • 你好,@彼得!我在 StackOverflow 上阅读了这篇文章。在这篇文章下,您的答案有两个选项。在我看来,第一个选项增加了我的代码库,因为有很多结构需要复制。如您所见,我有很多嵌套。您建议的第二个选项会将所有内容都转换为大写。
  • 如果您有嵌套的结构类型,则类型转换不起作用。您可以轻松地将链接答案中的 fixKeys 函数替换为转换为驼峰大小写的函数(如答案中所述)。

标签: json go struct marshalling unmarshalling


【解决方案1】:

您可以将 JSON 解组为 interface{},这将为每个 JSON 对象生成一个 map[string]interface{}。递归遍历结构并根据需要替换键,然后再次将其编组回 JSON。

【讨论】:

  • 感谢您的回答!你的想法听起来很棒。我现在正在尝试实施它。你能再看看我的帖子吗?我添加了一个新代码。我设法实现了递归,但它没有按我预期的那样工作。你能指引我正确的方向吗?
【解决方案2】:

您可以为您的结构使用自定义 json 编组函数,该函数可以使用正则表达式将键的蛇大小写替换为骆驼大小写。

否则我认为一个简单的方法是定义两个结构,一个是骆驼,一个是蛇。您可以解组为一个,在两者之间进行音乐会,然后重新编组并作为 json 响应发送。

【讨论】:

  • 感谢您的回复。我喜欢你提出的第一个想法。您能否在我的问题的背景下提供一个小例子?在MarshalJSON 函数中用camelCase 替换snake_caseregex 规则应该是什么样的?我认为第二个想法增加了我的代码库,因为有很多结构需要复制。如您所见,我有很多嵌套。
猜你喜欢
  • 2021-03-07
  • 2019-02-05
  • 2018-04-02
  • 1970-01-01
  • 2021-05-28
  • 2021-08-18
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
相关资源
最近更新 更多