OhadBasan
OhadBasan

Reputation: 807

Unmarshaling a stringified json

I am trying to unmarshal a json with a nested json.

I am using this struct

type atomRequest struct {
    Stream string                 `json:"stream"`
    Data   map[string]interface{} `json:"data"`
}

if the nested json is stringified, the Unmasrhaling fails and the value is nil

if the byte array that i am marshalling is with a non escape "data" The "Data" map is being populated correctly.

if the nested json is stringified, I get an empty Data map.

I am looking for a solution to unmarshal the nested data, whether its stringified or not.

The example: this input works:

{"stream":"foobar","data":{"errorID":112,"timestamp":1524737466}}

This input does not work:

{
    "stream": "foo",
    "data": "{\"cd3\":\"514\",\"cd8\":\"none\"}"
}

can you help?

thanks

Upvotes: 2

Views: 1082

Answers (1)

Thundercat
Thundercat

Reputation: 121129

Use json.RawMessage to capture the varying field:

type atomRequest struct {
    Stream  string                 `json:"stream"`
    RawData json.RawMessage        `json:"data"`
    Data    map[string]interface{} `json:"-"`
}

Unmarshal the top-level JSON:

var req atomRequest
if err := json.Unmarshal(data, &req); err != nil {
    // handle error
}

If data is a string, unmarshal to remove the extra level of encoding:

if len(req.RawData) > 0 && req.RawData[0] == '"' {
    var s string
    if err := json.Unmarshal(req.RawData, &s); err != nil {
        // handle error
    }
    req.RawData = json.RawMessage(s)
}

Finally, unmarshal to the map[string]interface{}:

if err := json.Unmarshal(req.RawData, &req.Data); err != nil {
    // handle error
}

playground example

Upvotes: 4

Related Questions