dtlygweb2017 2018-04-29 16:02
浏览 50
已采纳

如何解组可以是字符串*或*字符串数组的不一致的JSON字段?

I am having trouble Unmarshalling some Json I don't have control over. There is one field that 99% of the time is a string but occasionally is an array.

  1. type MyListItem struct {
  2. Date string `json:"date"`
  3. DisplayName string `json:"display_name"`
  4. }
  5. type MyListings struct {
  6. CLItems []MyListItem `json:"myitems"`
  7. }
  8. var mylist MyListings
  9. err = json.Unmarshal(jsn, &mylist)
  10. if err != nil {
  11. fmt.Print("JSON:
  12. %s
  13. error:%v
  14. ", string(jsn),err)
  15. return
  16. }

Json is as follows:

  1. {
  2. "date": "30 Apr",
  3. "display_name": "Mr Smith"
  4. },
  5. {
  6. "date": "30 Apr",
  7. "display_name": ["Mr Smith", "Mr Jones"],
  8. }

error: json: cannot unmarshal array into Go struct field MyListItem.display_name of type string

  • 写回答

2条回答 默认 最新

  • dongxunhua2054 2018-04-29 16:39
    关注

    Use json.RawMessage to capture the varying field.

    Use the json "-" name to hide the DisplayName field from decoder. The application will fill this field after the top-level JSON is decoded.

    1. type MyListItem struct {
    2. Date string `json:"date"`
    3. RawDisplayName json.RawMessage `json:"display_name"`
    4. DisplayName []string `json:"-"`
    5. }

    Unmarshal the top-level JSON:

    1. var li MyListItem
    2. if err := json.Unmarshal(data, &li); err != nil {
    3. // handle error
    4. }

    Unmarshal the display name depending on the type of the raw data:

    1. if len(li.RawDisplayName) > 0 {
    2. switch li.RawDisplayName[0] {
    3. case '"':
    4. if err := json.Unmarshal(li.RawDisplayName, &li.DisplayName); err != nil {
    5. // handle error
    6. }
    7. case '[':
    8. var s []string
    9. if err := json.Unmarshal(li.RawDisplayName, &s); err != nil {
    10. // handle error
    11. }
    12. // Join arrays with "&" per OP's comment on the question.
    13. li.DisplayName = strings.Join(s, "&")
    14. }
    15. }

    playground example

    Incorporate the above into a for loop to handle MyListings:

    1. var listings MyListings
    2. if err := json.Unmarshal([]byte(data), &listings); err != nil {
    3. // handle error
    4. }
    5. for i := range listings.CLItems {
    6. li := &listings.CLItems[i]
    7. if len(li.RawDisplayName) > 0 {
    8. switch li.RawDisplayName[0] {
    9. case '"':
    10. if err := json.Unmarshal(li.RawDisplayName, &li.DisplayName); err != nil {
    11. // handle error
    12. }
    13. case '[':
    14. var s []string
    15. if err := json.Unmarshal(li.RawDisplayName, &s); err != nil {
    16. // handle error
    17. }
    18. li.DisplayName = strings.Join(s, "&")
    19. }
    20. }
    21. }

    playground example

    If there's more than one place in the data model where a value can be a string or []string, it can be helpful to encapsulate the logic in a type. Parse the JSON data in an implementation of the json.Unmarshaler interface.

    1. type multiString string
    2. func (ms *multiString) UnmarshalJSON(data []byte) error {
    3. if len(data) > 0 {
    4. switch data[0] {
    5. case '"':
    6. var s string
    7. if err := json.Unmarshal(data, &s); err != nil {
    8. return err
    9. }
    10. *ms = multiString(s)
    11. case '[':
    12. var s []string
    13. if err := json.Unmarshal(data, &s); err != nil {
    14. return err
    15. }
    16. *ms = multiString(strings.Join(s, "&"))
    17. }
    18. }
    19. return nil
    20. }

    Use it like this:

    1. type MyListItem struct {
    2. Date string `json:"date"`
    3. DisplayName multiString `json:"display_name"`
    4. }
    5. type MyListings struct {
    6. CLItems []MyListItem `json:"myitems"`
    7. }
    8. var listings MyListings
    9. if err := json.Unmarshal([]byte(data), &listings); err != nil {
    10. log.Fatal(err)
    11. }

    Playground Example

    展开全部

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)
编辑
预览

报告相同问题?

手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部