英文:
how to access deeply nested json keys and values
问题
我正在用Go语言编写一个WebSocket客户端。我从服务器接收到以下JSON数据:
{"args":[{"time":"2013-05-21 16:57:17"}],"name":"send:time"}
我试图访问time参数,但是无法理解如何深入到接口类型中:
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 operation: args[0] (index of type interface {})
我找不到一种方法来深入到map中获取嵌套的键和值。
一旦我能够获取动态值,我想声明这些消息。我应该如何编写一个类型结构来表示这样复杂的数据结构?
英文:
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?
答案1
得分: 10
你可以考虑使用包github.com/bitly/go-simplejson
查看文档:http://godoc.org/github.com/bitly/go-simplejson
示例:
time, err := json.Get("args").GetIndex(0).String("time")
if err != nil {
    panic(err)
}
log.Println(time)
英文:
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)
答案2
得分: 8
The interface{} 部分的 map[string]interface{} 你解码成的将会匹配该字段的类型。所以在这个例子中:
args.([]interface{})[0].(map[string]interface{})["time"].(string)
应该返回 2013-05-21 16:56:16
然而,如果你知道 JSON 的结构,你可以尝试定义一个与该结构匹配的结构体,并将其解码为该结构体。例如:
type Time struct {
    Time time.Time      `json:"time"`
    Timezone []TZStruct `json:"tzs"` // 显然,你还需要定义 TZStruct
    Name string         `json:"name"`
}
type TimeResponse struct {
    Args []Time         `json:"args"`
}
var t TimeResponse
json.Unmarshal(msg, &t)
这可能不是完美的,但应该能给你一个思路。
英文:
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
得分: 1
我对Golang非常陌生,之前是用Python的,一直在处理编码/解码JSON方面遇到困难。我在https://github.com/tidwall/gjson找到了gjson,它对我帮助很大:
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"]
此外,我注意到了如何转换为结构体的注释:
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)
}
在Go playground上尝试一下。
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论