Go:使用一组json标记解码json,并编码为另一组json标记

Go:使用一组json标记解码json,并编码为另一组json标记,json,go,Json,Go,我有一个应用程序,它使用来自第三方api的数据。我需要将json解码为一个结构,这要求该结构具有“传入”json字段的json标记。传出的json字段具有不同的命名约定,因此我需要不同的json标记进行编码 我必须用许多不同的结构来完成这项工作,每个结构可能有许多字段 在不重复大量代码的情况下完成此任务的最佳方法是什么? 示例结构: // incoming "schema" field names type AccountIn struct { OpenDate string `json

我有一个应用程序,它使用来自第三方api的数据。我需要将json解码为一个结构,这要求该结构具有“传入”json字段的json标记。传出的json字段具有不同的命名约定,因此我需要不同的json标记进行编码

我必须用许多不同的结构来完成这项工作,每个结构可能有许多字段

在不重复大量代码的情况下完成此任务的最佳方法是什么?

示例结构:

// incoming "schema" field names
type AccountIn struct {
    OpenDate string `json:"accountStartDate"`
    CloseDate string `json:"cancelDate"`
}


// outgoing "schema" field names
type AccountOut struct {
    OpenDate string `json:"openDate"`
    CloseDate string `json:"closeDate"`
} 

如果可以通过
json.Unmarshal
json.Marshal
进行另一次往返,并且您的各种类型中没有任何不明确的字段名,则可以通过解组将一次过程中的所有json键转换为
json
包使用的通用结构:

// map incoming to outgoing json identifiers
var translation = map[string]string{
    "accountStartDate": "openDate",
    "cancelDate":       "closeDate",
}

func translateJS(js []byte) ([]byte, error) {
    var m map[string]interface{}
    if err := json.Unmarshal(js, &m); err != nil {
        return nil, err
    }

    translateKeys(m)
    return json.MarshalIndent(m, "", "  ")
}

func translateKeys(m map[string]interface{}) {
    for _, v := range m {
        if v, ok := v.(map[string]interface{}); ok {
            translateKeys(v)
        }
    }

    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }

    for _, k := range keys {
        if newKey, ok := translation[k]; ok {
            m[newKey] = m[k]
            delete(m, k)
        }
    }
}

如果您可以通过
json.Unmarshal
json.Marshal
进行另一次往返,并且您的各种类型中没有任何不明确的字段名,那么您可以通过解组将所有json密钥一次性转换为
json
包使用的通用结构:

// map incoming to outgoing json identifiers
var translation = map[string]string{
    "accountStartDate": "openDate",
    "cancelDate":       "closeDate",
}

func translateJS(js []byte) ([]byte, error) {
    var m map[string]interface{}
    if err := json.Unmarshal(js, &m); err != nil {
        return nil, err
    }

    translateKeys(m)
    return json.MarshalIndent(m, "", "  ")
}

func translateKeys(m map[string]interface{}) {
    for _, v := range m {
        if v, ok := v.(map[string]interface{}); ok {
            translateKeys(v)
        }
    }

    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }

    for _, k := range keys {
        if newKey, ok := translation[k]; ok {
            m[newKey] = m[k]
            delete(m, k)
        }
    }
}

一种不常见但可能相当有效的工作方法是使用中间格式,这样您就可以使用不同的读写器,从而使用不同的标记。例如,它允许将嵌套映射结构转换为结构 类型。非常类似于json解组,只是从一个映射

// incoming "schema" field names
type AccountIn struct {
    OpenDate string `mapstructure:"accountStartDate" json:"openDate"`
    CloseDate string `mapstructure:"cancelDate" json:"closeDate"`
}

// from json to map with no name changes
temporaryMap := map[string]interface{}{}
err := json.Unmarshal(jsonBlob, &temporaryMap)

// from map to structs using mapstructure tags
accountIn := &AccountIn{}
mapstructure.Decode(temporaryMap, accountIn)

稍后在编写(或读取)时,您将直接使用json函数,然后使用json标记。

一种不常见但可能相当好的工作方法是使用中间格式,这样您可以使用不同的读写器,从而使用不同的标记。例如,它允许将嵌套映射结构转换为结构 类型。非常类似于json解组,只是从一个映射

// incoming "schema" field names
type AccountIn struct {
    OpenDate string `mapstructure:"accountStartDate" json:"openDate"`
    CloseDate string `mapstructure:"cancelDate" json:"closeDate"`
}

// from json to map with no name changes
temporaryMap := map[string]interface{}{}
err := json.Unmarshal(jsonBlob, &temporaryMap)

// from map to structs using mapstructure tags
accountIn := &AccountIn{}
mapstructure.Decode(temporaryMap, accountIn)

稍后在编写(或阅读)时,u将直接使用json函数,然后再使用json标记。

也许Go 1.8即将进行的更改将对您有所帮助,它将允许“强制转换”类型,即使其json标记定义不同:这在1.8beta上也能正常工作,我想这将简化您当前的解决方案

也许Go 1.8即将进行的更改将对您有所帮助,它将允许“强制转换”类型,即使其JSON标记定义不同:这在1.8beta上的效果与预期一样,我想这将简化您当前的解决方案

这可能是一种幼稚的方法,但很容易实现:-

func ConvertAccountInToAccountOut(AccountIn incoming) (AccountOut outcoming){
    var outcoming AccountOut
    outcoming.OpenDate = incoming.OpenDate
    outcoming.CloseDate = incoming.CloseDate

    return outcoming
}

var IncomingJSONData AccountIn
resp := getJSONDataFromSource()  // Some method that gives you the Input JSON
err1 := json.UnMarshall(resp,&IncomingJSONData)
OutGoingJSONData := ConvertAccountInToAccountOut(IncomingJSONData)

if err1 != nil {
    fmt.Println("Error in UnMarshalling JSON ",err1)
}

fmt.Println("Outgoing JSON Data: ",OutGoingJSONData)

这可能是一种幼稚的方法,但很容易实现:-

func ConvertAccountInToAccountOut(AccountIn incoming) (AccountOut outcoming){
    var outcoming AccountOut
    outcoming.OpenDate = incoming.OpenDate
    outcoming.CloseDate = incoming.CloseDate

    return outcoming
}

var IncomingJSONData AccountIn
resp := getJSONDataFromSource()  // Some method that gives you the Input JSON
err1 := json.UnMarshall(resp,&IncomingJSONData)
OutGoingJSONData := ConvertAccountInToAccountOut(IncomingJSONData)

if err1 != nil {
    fmt.Println("Error in UnMarshalling JSON ",err1)
}

fmt.Println("Outgoing JSON Data: ",OutGoingJSONData)

你有多少事情要重复?如果你没有太多的类型,那么创建多个结构可能会更容易。这太多了。我已经考虑过了,但无法理解那是多么乏味(以及维护噩梦)。因此,我需要比我聪明的人的帮助。计算机擅长繁琐的事情——我可能会为翻译后的类型生成代码。不幸的是,我一时想不出一个干净、通用的解决方案。你要重复多少事情?如果你没有太多的类型,那么创建多个结构可能会更容易。这太多了。我已经考虑过了,但无法理解那是多么乏味(以及维护噩梦)。因此,我需要比我聪明的人的帮助。计算机擅长繁琐的事情——我可能会为翻译后的类型生成代码。不幸的是,我想不出一个干净的、通用的解决方案。这里描述了语言规范的变化,这里描述了语言规范的变化