取一个JSONstring,将其解组成一个map interface {},编辑并将其编组成一个字节似乎更复杂,那么它应该是

我正在做非常基本的JSON操作来学习一些Go,它工作,除了一件事情似乎closures,我必须编写.(map[string]interface{}).([]interface{})来访问JSON中的条目,特别是如果他们是儿童的孩子等等

看到这里(也在Go游乐场: https : //play.golang.org/p/Wd-pzHqTsU ):

 package main import ( "fmt" "encoding/json" ) func main() { JSON := []byte(`{"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"c3val1"}}]}`) fmt.Printf("%s\n", JSON) var d map[string]interface{} json.Unmarshal(JSON, &d) fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"]) d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"] = "change1" fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"]) JSON, _ = json.Marshal(d) fmt.Printf("%s\n", JSON) } 

哪个返回:

 {"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"c3val1"}}]} c3val1 change1 {"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"change1"}}]} 

现在在Python中,我直接访问键/值,而不是定义每次访问的types,而不是定义fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"])print d["key3"][0]["c2key1"]["c3key1"]

Python示例:

 import json JSON = '{"key3": [{"c2key1": {"c3key1": "c3val1"}}], "key2": {"c1key1": "c1val1"}, "key1": "val1"}' print JSON d = json.loads(JSON) print d["key3"][0]["c2key1"]["c3key1"] d["key3"][0]["c2key1"]["c3key1"] = "change1" print d["key3"][0]["c2key1"]["c3key1"] JSON = json.dumps(d) print JSON 

那么我在Go上做这个工作吗? 如果是这样,这个devise的原因是什么? 或者,如果不是,我该怎么做?

最简洁的方法是创build为JSONbuild模的预定义types(结构struct ),然后解组为这种types的值,并且可以使用select器 (对于structtypes)和索引expression式 (对于地图和切片)简单地引用元素, 。

但是,如果您的input不是预定义的结构,我build议您以下2个帮助函数: get()set() 。 第一个访问(返回)由任意path( string映射键和/或int切片索引列表)指定的任意元素,第二个更改(设置)由任意path指定的值(这些辅助函数的实现在答案的结尾)。

你只需要在项目/应用程序中包含这两个函数。

而现在使用这些助手,你想要做的任务变得这么简单(就像python解决scheme一样):

 fmt.Println(get(d, "key3", 0, "c2key1", "c3key1")) set("NEWVALUE", d, "key3", 0, "c2key1", "c3key1") fmt.Println(get(d, "key3", 0, "c2key1", "c3key1")) 

输出:

 change1 NEWVALUE 

尝试在Go游乐场上修改的应用程序。

注 – 进一步简化:

您甚至可以将path保存在variables中,并重新使用它来进一步简化上面的代码:

 path := []interface{}{"key3", 0, "c2key1", "c3key1"} fmt.Println(get(d, path...)) set("NEWVALUE", d, path...) fmt.Println(get(d, path...)) 

get()set()在下面。 注意:检查path是否有效被省略。 这个实现使用types开关 :

 func get(m interface{}, path ...interface{}) interface{} { for _, p := range path { switch idx := p.(type) { case string: m = m.(map[string]interface{})[idx] case int: m = m.([]interface{})[idx] } } return m } func set(v interface{}, m interface{}, path ...interface{}) { for i, p := range path { last := i == len(path)-1 switch idx := p.(type) { case string: if last { m.(map[string]interface{})[idx] = v } else { m = m.(map[string]interface{})[idx] } case int: if last { m.([]interface{})[idx] = v } else { m = m.([]interface{})[idx] } } } } 

不,这不是在Go中处理结构化JSON数据的最正确的方法。 相反,最好创build一个“结构层次结构”并将你的JSON解组为结构体。 例如

 type Data struct { Key1 string Key2 struct { C1Key1 string } Key3 []Key3 } type Key3 struct { C2Key1 struct { C3Key1 string } } 

这种方法:

  • 使您可以更好地控制数据如何被编组(通过结构标签和json.Unmarshalerjson.Marshaler接口)
  • 让你摆脱types断言
  • 相反,给你更多的types安全
  • 具有更好的性能,因为与地图访问相比,结构访问基本上是免费的。

游乐场: https : //play.golang.org/p/9XIh8DX1Ms 。