在go
中,标准包encoding/json公开了json.Unmarshal
函数来解析JSON。
可以在预定义的struct
中解组JSON字符串,或者使用interface{}
并迭代结果以获得意外的JSON数据结构。
那就是说,我无法正确解析复杂的JSON。有人能告诉我如何实现这个目标吗?
{
"k1" : "v1",
"k2" : "v2",
"k3" : 10,
"result" : [
[
["v4", v5, {"k11" : "v11", "k22" : "v22"}]
, ... ,
["v4", v5, {"k33" : "v33", "k44" : "v44"}
]
],
"v3"
]
}
答案 0 :(得分:34)
引自JSON and Go:
在不知道这些数据的结构的情况下,我们可以使用Unmarshal将其解码为接口{}值:
b := []byte(`{
"k1" : "v1",
"k3" : 10,
result:["v4",12.3,{"k11" : "v11", "k22" : "v22"}]
}`)
var f interface{}
err := json.Unmarshal(b, &f)
此时,f中的Go值将是一个映射,其键是字符串,其值本身存储为空接口值:
f = map[string]interface{}{
"k1": "v1",
"k3": 10,
"result": []interface{}{
"v4",
12.3,
map[string]interface{}{
"k11":"v11",
"k22":"v22",
},
},
}
要访问此数据,我们可以使用类型断言来访问
f
底层地图[string] interface {}:
m := f.(map[string]interface{})
然后我们可以使用范围语句迭代映射,并使用类型开关来访问其值作为其具体类型:
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")
}
}
通过这种方式,您可以使用未知的JSON数据,同时仍然可以享受类型安全带来的好处。
有关Go和JSON的更多信息,请参阅原始文章。我稍微更改了代码片段,使其与问题中的JSON更相似。
答案 1 :(得分:4)
最近,gjson提供了JSON中的属性选择
k1 := gjson.Get(json, "k1")
k33 : = gjson.Get(json, "result.#.#.k33")
答案 2 :(得分:3)
encoding/json
包我曾经使用JSON and Go文章,结果发现case int
不起作用,现在需要case float64
,并且实际上有很多嵌套世界JSON。
> go version
go version go1.7.1 darwin/amd64
我也看过JSON decoding in Go,但它对我没有多大帮助,因为我需要将其程序化地转换为一系列对mruby绑定的调用,并且该文章的作者很满意大部分都是结构。
我花了一点时间摆弄这个,最后的迭代翻斗功能看起来像这样:
func dumpJSON(v interface{}, kn string) {
iterMap := func(x map[string]interface{}, root string) {
var knf string
if root == "root" {
knf = "%q:%q"
} else {
knf = "%s:%q"
}
for k, v := range x {
dumpJSON(v, fmt.Sprintf(knf, root, k))
}
}
iterSlice := func(x []interface{}, root string) {
var knf string
if root == "root" {
knf = "%q:[%d]"
} else {
knf = "%s:[%d]"
}
for k, v := range x {
dumpJSON(v, fmt.Sprintf(knf, root, k))
}
}
switch vv := v.(type) {
case string:
fmt.Printf("%s => (string) %q\n", kn, vv)
case bool:
fmt.Printf("%s => (bool) %v\n", kn, vv)
case float64:
fmt.Printf("%s => (float64) %f\n", kn, vv)
case map[string]interface{}:
fmt.Printf("%s => (map[string]interface{}) ...\n", kn)
iterMap(vv, kn)
case []interface{}:
fmt.Printf("%s => ([]interface{}) ...\n", kn)
iterSlice(vv, kn)
default:
fmt.Printf("%s => (unknown?) ...\n", kn)
}
}
b
是一个字节切片,其中JSON表示顶层的数组或对象,您可以这样调用它:
var f interface{}
if err := json.Unmarshal(b, &f); err != nil {
panic(err)
}
dumpJSON(f, "root")
Hope this helps, you try the comple program here
我建议不要自己动手,除非你觉得你必须学习Go类型是如何工作的,并且使用reflect
让你感觉自己是宇宙大师(个人,reflect
让我发疯)
作为@changingrainbows pointed out below,有github.com/tidwall/gjson
个包,它似乎包裹encoding/json
并使用reflect
。我可能与github.com/mitchellh/reflectwalk
没有什么不同,github.com/buger/jsonparser
很难使用,而且内部工作非常复杂。
我在我的一个项目中使用了github.com/buger/jsonparser
,还有github.com/json-iterator/go
,我还没有尝试过,但它似乎是基于enconding/json
和似乎公开了github.com/json-iterator/go
兼容的界面,并且还有func Get(data []byte, path ...interface{}) Any
。为了记录,Kubernetes项目最近已切换到encoding/json
。
在我的项目中,我使用github.com/buger/jsonparser
以及github.com/json-iterator/go
,当我有时间时,我可能会切换到$budgetService = $user->GetService('BudgetService', ADWORDS_VERSION);
$bm = new Money('10000000');
$campaign->budget->amount = $bm;
$boperation = new BudgetOperation();
$boperation->operand = $campaign->budget;
$boperation->operator = 'SET';
$budgetService->mutate($boperation);
。我会尝试用更多的发现来更新这篇文章。