取一个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器 (对于struct
types)和索引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.Unmarshaler
和json.Marshaler
接口) - 让你摆脱types断言
- 相反,给你更多的types安全
- 具有更好的性能,因为与地图访问相比,结构访问基本上是免费的。
游乐场: https : //play.golang.org/p/9XIh8DX1Ms 。