go中,标准的包编码/ json公开了json.Unmarshal函数来解析JSON。

可以在预定义的struct中解组JSON字符串,或者使用interface{}和迭代结果以获取意外的JSON数据结构。

也就是说,我无法正确解析复杂的JSON。有人可以告诉我如何实现吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 {
    "k1" :"v1",
    "k2" :"v2",
    "k3" : 10,
    "result" : [
                 [
                 ["v4", v5, {"k11" :"v11","k22" :"v22"}]
                 , ... ,
                 ["v4", v5, {"k33" :"v33","k44" :"v44"}
                 ]
                 ],
                "v3"
                ]
}

从JSON和Go引用:

Without knowing this data's structure, we can decode it into an interface{} value with Unmarshal:

1
2
3
4
5
6
7
b := []byte(`{
  "k1" :"v1",
  "k3" : 10,
   result:["v4",12.3,{"k11" :"v11","k22" :"v22"}]
}`)
var f interface{}
err := json.Unmarshal(b, &f)

At this point the Go value in f would be a map whose keys are strings and whose values are themselves stored as empty interface values:

1
2
3
4
5
6
7
8
9
10
11
12
f = map[string]interface{}{
   "k1":"v1",
   "k3":  10,
   "result": []interface{}{
      "v4",
       12.3,
       map[string]interface{}{
          "k11":"v11",
          "k22":"v22",
       },
    },
}

To access this data we can use a type assertion to access f's underlying map[string]interface{}:

1
m := f.(map[string]interface{})

We can then iterate through the map with a range statement and use a type switch to access its values as their concrete types:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for k, v := range m {
    switch vv := v.(type) {
    case string:
        fmt.Println(k,"is string", vv)
    case int:
        fmt.Println(k,"is int", vv)
    case []interface{}:
        fmt.Println(k,"is an array:")
        for i, u := range vv {
            fmt.Println(i, u)
        }
    default:
        fmt.Println(k,"is of a type I don't know how to handle")
    }
}

In this way you can work with unknown JSON data while still enjoying the benefits of type safety.

有关Go和JSON的更多信息可以是在原始文章中找到。我稍微更改了代码片段,使其更类似于问题中的JSON。

  • varholder interface {} \\ json.Unmarshal(message,
  • 只是想提一下,var f interface{}; err := yaml.Unmarshal(b, &f)也可以与github.com/go-yaml/yaml一起使用。
  • 我还收到错误"接口转换:接口{}为nil,而不是map [string]接口{} "。有任何想法吗?
  • interface {}为nil,因为json字符串无效。结果应为"结果"。这是一个上面代码示例的操场(使用json校正):play.golang.org/p/RLodJLwy19

使用标准库encoding/json

我处理过JSON和Go文章,结果发现case int不起作用,现在必须为case float64,并且有很多嵌套在现实世界中的JSON中。

1
2
> go version
go version go1.7.1 darwin/amd64

我也研究了Go中的JSON解码,但是它对我没有太大帮助,因为我需要按程序进行将其转换为一系列调用到mruby绑定,该文章的作者大部分时间都对Go结构感到满意。

我花了一些时间来摆弄这个,最后迭代的转储函数看起来像这样:

其中b是一个字节切片,带有一个JSON表示顶级数组或对象,您可以这样称呼它:

1
2
3
4
5
var f interface{}
if err := json.Unmarshal(b, &f); err != nil {
    panic(err)
}
dumpJSON(f,"root")

希望这会有所帮助,您可以尝试

使用其他软件包

我建议您自己不要这样做,除非您觉得必须学习Go类型的工作方式,并且使用reflect会让您感觉自己像是一个宇宙的大师(个人, reflect令我发疯)。

@changingrainbows指出下面是github.com/tidwall/gjson包,它似乎包装了encoding/json并使用了reflect。我可能与github.com/mitchellh/reflectwalk没什么不同,github.com/mitchellh/reflectwalk很难使用,内部工作也非常复杂。

在我的一个项目中,我已经广泛使用了github.com/buger/jsonparser,而且还有,我尚未尝试过,但它似乎基于github.com/buger/jsonparser,并且似乎公开了enconding/json兼容的接口,并且也具有func Get(data []byte, path ...interface{}) Any。作为记录,Kubernetes项目最近已切换到github.com/json-iterator/go。在我的项目中,我同时使用encoding/jsongithub.com/buger/jsonparser,如果有时间,我可能会切换到github.com/json-iterator/go。我将尝试通过更多发现来更新此帖子。


最近,gjson提供了JSON中的属性选择

1
2
k1 := gjson.Get(json,"k1")
k33 : = gjson.Get(json,"result.#.#.k33")