Go:用一组json标签解码json,并编码到一组不同的json标签

时间:2017-01-09 21:04:41

标签: json go

我有一个使用来自第三方API的数据的应用程序。我需要将json解码为struct,这需要struct具有“传入”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"`
} 

4 个答案:

答案 0 :(得分:2)

有点不常见但可能工作得很好的方法是使用中间格式,这样你就可以使用不同的读者和编写者,从而使用不同的标签。例如https://github.com/mitchellh/mapstructure,它允许将嵌套的地图结构转换为结构 类型。非常类似于json unmarshal,只是来自地图。

// 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标签。

答案 1 :(得分:2)

也许Go 1.8上即将发生的变化会对你有所帮助,它可以让你去投射'#类型即使它的JSON标签定义不同:这个https://play.golang.org/p/Xbsoa8SsEk在1.8beta上按预期工作,我想这会简化你当前的解决方案

答案 2 :(得分:1)

如果通过json.Unmarshaljson.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)
        }
    }
}

https://play.golang.org/p/nXmWlj7qH9

答案 3 :(得分:0)

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

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)