dou8mwz5079
2018-12-08 12:26
浏览 63

有没有一种方法可以在Go中使用转换类型来解码JSON?

I'm working with an API which can return one value as int if it's zero and as string if it's not zero and I want a decoder which will decode these two JSONs correctly into struct

{
  "id": 1,
  "rating": 0
}
{
  "id": 2,
  "rating": "2"
}
type User struct {
  Id int64 `json:"id"`
  Rating int64 `json:"rating,string"`
}

So it should try to convert any JSON type (int, float, string) to type specified in struct and raise error only if it isn't possible. Standard json.Decoder doesn't do that.

Or maybe there is some more customizable json parsing library?

图片转代码服务由CSDN问答提供 功能建议

我正在使用一个API,该API可以将一个值(如果为零)返回为int,如果不为零则返回为字符串 并且我想要一个能够将这两个JSON正确解码为struct

  {
“ id”:1,
“ rating”:0 
} 
 {  
“ id”:2,
“ rating”:“ 2” 
} 
type用户结构{
 ID int64`json:“ id”`
 Rating int64`json:“ rating,string”`\  n} 
   
 
 

因此它应尝试将任何JSON类型(int,float,string)转换为struct中指定的类型,并仅在不可能的情况下引发错误 。 标准json.Decoder不会这样做。

或者也许还有更多可定制的json解析库?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • drh19790711 2018-12-08 14:08
    已采纳

    Solved like this:

    type Int64 struct {
            Value int64
    }
    
    func (this *Int64) UnmarshalJSON(bytesValue []byte) error {
            stringValue := string(bytesValue)
    
            if len(stringValue) > 2 {
                    if stringValue[0] == '"' && stringValue[len(stringValue)-1] == '"' {
                            stringValue = stringValue[1 : len(stringValue)-1]
                    }
            }
    
            var err error
            this.Value, err = strconv.ParseInt(stringValue, 10, 64)
            return err
    }
    
    func (this *Int64) MarshalJSON() ([]byte, error) {
            return []byte(fmt.Sprintf("%v", this.Value)), nil
    }
    
    点赞 评论
  • doupiao9318 2018-12-08 12:54

    I recommend you to change the api, if thats not possible then you can use the interface type for the rating and manually check for the type during parsing (ints will return as float64):

    package main
    
    import (
        "fmt"
        "encoding/json"
    )
    
    type User struct {
        Id int `json:"id"`
        Rating interface{} `json:"rating"`
    }
    
    func main() {
        usersJson := `[{"id": 1, "rating": 0}, {"id": 2,"rating": "2"}]`
    
        var users []User
    
        err := json.Unmarshal([]byte(usersJson), &users)
        if err != nil {
            fmt.Println("err: ",err)
            return
        }
    
        for _, u := range users {
            switch u.Rating.(type) {
            case float64:
                fmt.Println("its an float64", u.Rating.(float64))
            case string:
                fmt.Println("its an string", u.Rating.(string))
            }
        }
    }
    
    点赞 评论
  • douxianliu6756 2018-12-08 12:57

    You are trying to parse an int64 from a JSON string. You can do this using custom types that implement the JSON Unmarshaler interface.

    e.g.

    type User struct {
        Id     int64       `json:"id"`
        Rating Int64String `json:"rating"`
    }
    
    type Int64String int64
    
    func (i Int64String) MarshalJSON() ([]byte, error) {
        return json.Marshal(strconv.FormatInt(int64(i), 10))
    }
    
    func (i *Int64String) UnmarshalJSON(data []byte) error {
        var jstring string
        err := json.Unmarshal(data, &jstring)
        if err != nil {
            return err
        }
        *(*int64)(i), err = strconv.ParseInt(jstring, 0, 64)
        return err
    }
    

    Playground

    点赞 评论

相关推荐 更多相似问题