我在解组一些我无法控制的Json时遇到麻烦。在一个字段中,有99%的时间是字符串,但偶尔是数组。
type MyListItem struct { Date string `json:"date"` DisplayName string `json:"display_name"` } type MyListings struct { CLItems []MyListItem `json:"myitems"` } var mylist MyListings err = json.Unmarshal(jsn, &mylist) if err != nil { fmt.Print("JSON:\n%s\n error:%v\n", string(jsn),err) return }
杰森如下:
{ "date": "30 Apr", "display_name": "Mr Smith" }, { "date": "30 Apr", "display_name": ["Mr Smith", "Mr Jones"], }
错误:json:无法将数组解组为字符串类型的Go结构字段MyListItem.display_name
使用json.RawMessage捕获变化的字段。
使用json“-”名称对DisplayName解码器隐藏字段。顶级JSON解码后,应用程序将填充此字段。
DisplayName
type MyListItem struct { Date string `json:"date"` RawDisplayName json.RawMessage `json:"display_name"` DisplayName []string `json:"-"` }
解组顶级JSON:
var li MyListItem if err := json.Unmarshal(data, &li); err != nil { // handle error }
根据原始数据的类型取消对显示名称的编组:
if len(li.RawDisplayName) > 0 { switch li.RawDisplayName[0] { case '"': if err := json.Unmarshal(li.RawDisplayName, &li.DisplayName); err != nil { // handle error } case '[': var s []string if err := json.Unmarshal(li.RawDisplayName, &s); err != nil { // handle error } // Join arrays with "&" per OP's comment on the question. li.DisplayName = strings.Join(s, "&") } }
游乐场的例子
将以上内容合并到for循环中以进行处理MyListings:
MyListings
var listings MyListings if err := json.Unmarshal([]byte(data), &listings); err != nil { // handle error } for i := range listings.CLItems { li := &listings.CLItems[i] if len(li.RawDisplayName) > 0 { switch li.RawDisplayName[0] { case '"': if err := json.Unmarshal(li.RawDisplayName, &li.DisplayName); err != nil { // handle error } case '[': var s []string if err := json.Unmarshal(li.RawDisplayName, &s); err != nil { // handle error } li.DisplayName = strings.Join(s, "&") } } }
如果数据模型中有多个位置,值可以是字符串或[]字符串,则将逻辑封装为类型可能会有所帮助。在json.Unmarshaler接口的实现中解析JSON数据。
type multiString string func (ms *multiString) UnmarshalJSON(data []byte) error { if len(data) > 0 { switch data[0] { case '"': var s string if err := json.Unmarshal(data, &s); err != nil { return err } *ms = multiString(s) case '[': var s []string if err := json.Unmarshal(data, &s); err != nil { return err } *ms = multiString(strings.Join(s, "&")) } } return nil }
像这样使用它:
type MyListItem struct { Date string `json:"date"` DisplayName multiString `json:"display_name"` } type MyListings struct { CLItems []MyListItem `json:"myitems"` } var listings MyListings if err := json.Unmarshal([]byte(data), &listings); err != nil { log.Fatal(err) }
操场上的例子