unmarshal json field is int or string

时间:2019-05-31 11:41:59

标签: go

I have an app where the type is

type Person struct {
  Name string `json:"name"`
  Age  int    `json:"age"`
}

But we have legacy clients that send the Age field as either a string or an integer, so...

{
  "name": "Joe",
  "age": "42"
}

OR

{
  "name": "Joe",
  "age": 42
}

I know I can annotate the "age" field with ",string" if it's a string that I want coerced into an integer, but what if the field could be either one?

2 个答案:

答案 0 :(得分:0)

Check out "json - raw Message" in the docs, from there on out you can try to parse it however you want. Example below and on GoPlayground

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strconv"
    "unicode/utf8"
)

type Person struct {
    Name string          `json:"name"`
    Age  json.RawMessage `json:"age"`
}

func main() {
    var j = []byte(`{"name": "Joe","age": "42"}`)
    var j2 = []byte(`{"name": "Joe","age": 42}`)
    stringOrInt(j)
    stringOrInt(j2)
}

func stringOrInt(bytes []byte) {
    var p Person
    err := json.Unmarshal(bytes, &p)
    if err != nil {
        log.Fatal(err)
    }

    if utf8.Valid(p.Age) {
        i, err := strconv.Atoi(string(p.Age))
        if err != nil {
            fmt.Println("got int " + strconv.Itoa(i))
        } else {
            fmt.Println("got string")
        }
    } else {
        fmt.Println("whoops")
    }
}

答案 1 :(得分:0)

package main

import (
    "encoding/json"
    "fmt"
    "strconv"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func (p *Person) UnmarshalJSON(b []byte) error {
    var objMap map[string]*json.RawMessage
    err := json.Unmarshal(b, &objMap)
    if err != nil {
        return err
    }

    var name string
    err = json.Unmarshal(*objMap["name"], &name)
    if err != nil {
        return err
    }

    var ageInt int
    err = json.Unmarshal(*objMap["age"], &ageInt)
    if err != nil {
        // age  is string
        var ageString string
        err = json.Unmarshal(*objMap["age"], &ageString)
        if err != nil {
            return err
        }
        aI, err := strconv.Atoi(ageString)
        if err != nil {
            return err
        }
        p.Age = aI

    } else {
        p.Age = ageInt
    }

    p.Name = name

    fmt.Printf("%+v", *p)

    return nil
}

func main() {
    p := `{"name": "John", "age": "10"}`
    //  p := `{"name": "John", "age": 10}`


    newP := Person{}
    err := newP.UnmarshalJSON([]byte(p))
    if err != nil {
        fmt.Printf("Error %+v", err)
    }

}

https://play.golang.org/p/AK8H_wdNqmt

您可以尝试类似的方法。尝试读取并解析为int,如果无法检查字符串值,则将其解析为int,然后将int值分配给person struct