在Golang中解码任意JSON

5

我有一个关于在Go中解码任意JSON对象/消息的问题。比如说,你可能会在http连接上接收到三个非常不同的JSON对象(也可以称之为消息),让我们为了举例而称它们为:

{ home : { some unique set of arrays, objects, fields, and arrays objects } }

并且

{ bike : { some unique set of arrays, objects, fields, and arrays objects } }

并且。
{ soda : { some unique set of arrays, objects, fields, and arrays objects } }

我觉得你可以将这些内容从HTTP连接解码成接口的映射,例如:
func httpServerHandler(w http.ResponseWriter, r *http.Request) {
    message := make(map[string]interface{})
    decoder := json.NewDecoder(r.Body)
    _ = decoder.Decode(&message)

然后进行 if、else if 块来寻找有效的 JSON 消息。
if _, ok := message["home"]; ok {
    // Decode interface{} to appropriate struct
} else if _, ok := message["bike"]; ok {
    // Decode interface{} to appropriate struct
} else {
    // Decode interface{} to appropriate struct
}

现在,在 if 块中,如果我重新解码整个 package,我就可以使它正常工作,但我想这有点浪费,因为我已经部分解码了它,只需要解码 map 的值,即一个 interface{},但是我似乎无法正确地做到这一点。
如果我像下面这样做,其中 homeType 是一个结构体,重新编码整个内容就可以工作:
var homeObject homeType
var bikeObject bikeType
var sodaObject sodaType

然后在 if 块中执行以下操作:

if _, ok := message["home"]; ok {
    err = json.Unmarshal(r.Body, &homeObject)
    if err != nil {
        fmt.Println("Bad Response, unable to decode JSON message contents")
        os.Exit(1)
    }

那么,在不重新解码/取消编组整个内容的情况下,如何使用映射中的 interface{}?

1个回答

2

如果你有一个类似map[string]interface{}的东西,那么你可以使用类型断言来访问值,例如:

home, valid := msg["home"].(string)
if !valid {
    return
}

这对于简单值非常有效。对于更复杂的嵌套结构,您可能会发现使用json.RawMessage进行延迟解码或实现自定义json.Unmarshaler更容易。请参见此处进行详细讨论。
另一个想法是定义一个自定义的Message类型,其中包含指向Home、Bike和Soda结构体的指针。例如:
type Home struct {
    HomeStuff     int
    MoreHomeStuff string
} 

type Bike struct {
    BikeStuff int
}

type Message struct {
    Bike *Bike `json:"Bike,omitempty"`
    Home *Home `json:"Home,omitempty"`
}

如果将它们设置为“如果为nil则省略”,那么反序列化只会填充相关部分。您可以在此处进行尝试: 这里

当我尝试对映射值(也称为interface{})进行取消编组/解码时,我遇到的错误是需要类型断言,但我不确定如何做。如果我知道该值实际上是homeType结构体,我该如何将其从接口中取出,以便我可以将其取消编组为homeType对象? - jordan2175
在那种情况下,我会做类似这样的事情http://play.golang.org/p/hHQlAdcE56。我会更新答案。 - Alfred Rossi
直接回应您的评论,您无法对结构体进行干净的类型断言,因为内部对象被解组为map[string]interface{} -- 因此您必须逐个字段地拆分它。请参见http://play.golang.org/p/WrpLxZH0r-和https://dev59.com/GV8d5IYBdhLWcg3wgya4。 - Alfred Rossi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接