Go unmarshal json with a field that is an array of objects or strings

huangapple go评论94阅读模式
英文:

Go unmarshal json with a field that is an array of objects or strings

问题

在Go语言中,你可以将JSON解组成一个结构体。问题是,我有一个API,它可能会在每个请求中更改键的值的类型。

例如,可能会有这样的内联对象:

{
  "mykey": [
    {obj1},
    {obj2}
  ]
}

但也可能通过键指向对象,像这样:

{
  "mykey": [
    "/obj1/is/at/this/path",
    "/obj2/is/at/this/other/path"
  ]
}

有些对象可以内联,但其他对象可能会在多个位置引用。

在JavaScript或Python中,这不是问题。只需检查类型即可。

在Go中,解组和解析这两个对象的惯用方式是什么?是反射(Reflect)是唯一的方式吗?

英文:

In go you unmarshal json into a struct. The problem is that I have an api that might change the type of the value of a key from request to request.

For example objects that might be inlined objects like this:

{
  "mykey": [
    {obj1}, 
    {obj2}
  ]
}

but also point to objects by keys, like this:

{
  "mykey": [
    "/obj1/is/at/this/path", 
    "/obj2/is/at/this/other/path"
  ]
}

Some objects can be inlined, but others are referenced from multiple locations.

In javascript or python this wouldn't be a problem. Just check the type.

What's the go-idiomatic way to unmarshal and parse these two objects? Is Reflect the only way?

答案1

得分: 4

你可以将这个JSON解析为以下结构的形式:

type Data struct {
    MyKey []interface{} `json:"mykey"`
}

如果JSON包含字符串,它们将被解码为数组中的字符串。如果JSON包含对象,它们将被解码为map[string]interface{}值。你可以使用type switch来区分这两种情况。类似这样:

for i, v := range data.MyKey {
    switch x := v.(type) {
    case string:
        fmt.Println("得到一个字符串:", x)
    case map[string]interface{}:
        fmt.Printf("得到一个对象:%#v\n", x)
    }
}

你可以在这里尝试这个示例:http://play.golang.org/p/PzwFI2FSav

英文:

You could unmarshal this JSON to a structure like the following:

type Data struct {
    MyKey []interface{} `json:"mykey"`
}

If the JSON includes strings, they will be decoded as strings in the array. If the JSON includes objects, they will be decoded as map[string]interface{} values. You can distinguish between the two using a type switch. Something like this:

for i, v := range data.MyKey {
    switch x := v.(type) {
    case string:
        fmt.Println("Got a string: ", x)
    case map[string]interface{}:
        fmt.Printf("Got an object: %#v\n", x)
    }
}

You can play around with this example here: http://play.golang.org/p/PzwFI2FSav

huangapple
  • 本文由 发表于 2014年11月10日 01:41:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/26831151.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定