我有一个使用来自第三方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"`
}
答案 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.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)
}
}
}
答案 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)