在Golang中解码任意JSON

I have a question about decoding arbitrary JSON objects/messages in Go.. Lets say for example you have three wildly different JSON objects (aka messages) that you can receive on an http connection, lets call them for sake of illustration:

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

and

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

and

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

What I am thinking is you could decode these, from an http connection in to a map of interfaces such as:

func httpServerHandler(w http.ResponseWriter, r *http.Request) {
    message := make(map[string]interface{})
    decoder := json.NewDecoder(r.Body)
    _ = decoder.Decode(&message)

Then do an if, else if block to look for valid JSON messages

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
}

Now in the if block I can make it work if I re-decode the entire package, but I was thinking that is kind of a waste since I have already partially decoded it and would only need to decode the value of the map which is an interface{}, but I can not seem to get that to work right.

Redecoding the entire thing works though, if I do something like the following where the homeType for example is a struct:

var homeObject homeType
var bikeObject bikeType
var sodaObject sodaType

Then in the if block do:

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

So without re-decoding / unmarshal-ing the entire thing again, how do you work with the interface{} in a map?

1个回答



如果您有诸如map [string] interface {}之类的内容,则可以使用类型断言来访问值,例如</ p>

  home,有效:= msg [“ home”]。(字符串)
if!valid {
return
}
</ code> </ pre>

这对于简单的值非常有效。 对于更复杂的嵌套结构,您可能会发现使用 json.RawMessage </ code>进行延迟解码或实现自定义 json.Unmarshaler </ code>会更容易。 有关非常详细的讨论,请参见。</ p>

另一个想法可能是定义一个自定义的 Message </ code>类型,该类型由指向Home,Bike和Soda结构的指针组成。 例如</ p>

 类型Home结构{
HomeStuff int
MoreHomeStuff字符串
}

type Bike结构{
BikeStuff int
}

type消息 struct {
Bike 自行车json:“ Bike,omitempty”
主页
首页json:“ Home,omitempty”
}
</ code> </ pre>

如果将这些设置为nil,则将其省略,那么解组应该只填充相关的内容。 您可以在此处使用它。</ p>
</ div>

展开原文

原文

If you have something like a map[string]interface{} then you can access the values using type assertions, e.g.

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

This works nicely for simple values. For more complicated nested structures you might find it easier to do deferred decoding with json.RawMessage or implement a custom json.Unmarshaler. See this for a very detailed discussion.

Another idea might be to define a custom Message type consisting of pointers to Home, Bike, and Soda structs. Such as

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"`
}

If you set these to omit if nil then unmarshalling should only populate the relevant one. You can play with it here.

dqwmhrxt68679
dqwmhrxt68679 为了直接处理您的评论,您将无法在结构上清晰地键入assert,因为内部对象已作为map [string] interface {}进行了编组,因此您必须逐字段进行选择。 参见play.golang.org/p/WrpLxZH0r-和stackoverflow.com/questions/26744873/converting-map-to-struct
5 年多之前 回复
dongpang2483
dongpang2483 在这种情况下,我会做类似play.golang.org/p/hHQlAdcE56的操作。 将更新答案
5 年多之前 回复
dongnuo3749
dongnuo3749 尝试解组/解码映射值(也称为interface {})时遇到的错误是我需要类型断言,而且我不确定该怎么做。 如果我知道该值实际上是一个homeType结构,如何从接口中获取它,以便可以将其解组为homeType对象?
5 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐