6

I'm writing a websocket client in Go. I'm receiving the following JSON from the server:

{"args":[{"time":"2013-05-21 16:57:17"}],"name":"send:time"}

I'm trying to access the time parameter, but just can't grasp how to reach deep into an interface type:

 package main;
 import "encoding/json"
 import "log"
 func main() {
    msg := `{"args":[{"time":"2013-05-21 16:56:16", "tzs":[{"name":"GMT"}]}],"name":"send:time"}`
    u := map[string]interface{}{}
    err := json.Unmarshal([]byte(msg), &u)
    if err != nil {
        panic(err)
    }
    args := u["args"]
    log.Println( args[0]["time"] )   // invalid notation...
}

Which obviously errors, since the notation is not right:

   invalid operation: args[0] (index of type interface {})

I just can't find a way to dig into the map to grab deeply nested keys and values.

Once I can get over grabbing dynamic values, I'd like to declare these messages. How would I write a type struct to represent such complex data structs?

3
  • Will the returned JSON always have the same fields? Commented May 21, 2013 at 16:06
  • Yes, basically the same. Commented May 21, 2013 at 16:35
  • Then you should really go with @cthom06 suggested about defining a struct that matches the data. It'll make it much easier in the long run as you'll know what type you're getting for each field. Commented May 21, 2013 at 16:38

3 Answers 3

10

You may like to consider the package github.com/bitly/go-simplejson

See the doc: http://godoc.org/github.com/bitly/go-simplejson

Example:

time, err := json.Get("args").GetIndex(0).String("time")
if err != nil {
    panic(err)
}
log.Println(time)
Sign up to request clarification or add additional context in comments.

1 Comment

Wow, real nice. Just wish I had something as easy as that for working with YAML also, although Gypsy looks promising.
8

The interface{} part of the map[string]interface{} you decode into will match the type of that field. So in this case:

args.([]interface{})[0].(map[string]interface{})["time"].(string)

should return "2013-05-21 16:56:16"

However, if you know the structure of the JSON, you should try defining a struct that matches that structure and unmarshal into that. Ex:

type Time struct {
    Time time.Time      `json:"time"`
    Timezone []TZStruct `json:"tzs"` // obv. you need to define TZStruct as well
    Name string         `json:"name"`
}

type TimeResponse struct {
    Args []Time         `json:"args"`
}

var t TimeResponse
json.Unmarshal(msg, &t)

That may not be perfect, but should give you the idea

3 Comments

That worked, thanks. But how would I turn this into a type struct, then access the data?
The struct is brilliant stuff! I just don't get how the json:"key" string fits into the syntax of a Go type struct, although I understand that it it's telling the json.Unmarshall() func where to fit each key-value pair.
@ojosilva It's honestly a bit of a hack I think. Struct fields can be "tagged" with a string, which can be accessed via reflection. The json package checks those tags for json:options
1

I'm extremely new to Golang coming from Python, and have always struggled with encode/decoding json. I found gjson at https://github.com/tidwall/gjson, and it helped me immensely:

package main
    
import "github.com/tidwall/gjson"

func main() {
    msg := (`{"args":[{"time":"2013-05-21 16:56:16", "tzs":[{"name":"GMT"}]}],"name":"send:time"}`)
    value := gjson.Get(msg, "args.#.time")
    println(value.String())
}
-----------------------
["2013-05-21 16:56:16"]

Additionally, I noticed the comment of how to convert into Struct

package main
    
import (
        "encoding/json"
        "fmt"
    )

type msgFormat struct {
    Time string       `json:"time"`
    Tzs  msgFormatTzs `json:"tzs"`
    Name string       `json:"name"`
}

type msgFormatTzs struct {
    TzsName string `json:"name"`
}


func main() {

    msg := (`{"args":[{"time":"2013-05-21 16:56:16", "tzs":[{"name":"GMT"}]}],"name":"send:time"}`)

    r, err := json.Marshal(msgFormatTzs{msg})

    if err != nil {
        panic(err)
    }

    fmt.Printf("%v", r)
}

Try on Go playground

1 Comment

Your marshaling does not work. Use this

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.