dtlygweb2017 2018-04-30 00: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.

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:
%s
 error:%v
", string(jsn),err)
    return
}

Json is as follows:

{       
    "date": "30 Apr",
    "display_name": "Mr Smith"
},
{
    "date": "30 Apr",
    "display_name": ["Mr Smith", "Mr Jones"],
}

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

  • 写回答

2条回答 默认 最新

  • dongxunhua2054 2018-04-30 00: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.

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

    Unmarshal the top-level JSON:

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

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

    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, "&")
        }
    }
    

    playground example

    Incorporate the above into a for loop to handle 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, "&")
            }
        }
    }
    

    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.

    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
    }
    

    Use it like this:

    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)
    }
    

    Playground Example

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

报告相同问题?

悬赏问题

  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?