关于该主题有几个问题,但是似乎没有一个问题可以解决我的问题,因此我正在创建一个新问题。
我有如下JSON:
1  | {"foo":{"bar":"1","baz":"2" },"more":"text"}  | 
有没有办法解组嵌套的bar属性并将其直接分配给struct属性而不创建嵌套的struct?
我现在采用的解决方案如下:
1 2 3 4 5 6 7 8  | type Foo struct { More String `json:"more"` Foo struct { Bar string `json:"bar"` Baz string `json:"baz"` } `json:"foo"` // FooBar string `json:"foo.bar"` }  | 
这是简化版本,请忽略详细信息。 如您所见,我希望能够解析并将其值分配给
1  | //  FooBar  string `json:"foo.bar"`  | 
我见过有人在使用地图,但这不是我的情况。 除了一些特定的元素外,我基本上不关心
在这种情况下正确的方法是什么? 我不是在寻找怪异的技巧,因此,如果这是可行的方式,那么我也很满意。
Is there a way to unmarshal the nested bar property and assign it directly to a struct property without creating a nested struct?
不,encoding / json无法使用"> some> deep> childnode来解决问题",就像encoding / xml可以做到的那样。
嵌套结构是必经之路。
- 为什么这与encoding / xml不同?
 - @CalebThompson即使简单的情况看起来相似,XML和JSON的结构也完全不同。 XML标签的内容有点:(子标签OR文本的有序映射)和属性的无序映射。 JSON更像是Go结构。因此,将JSON映射到结构要简单得多:只需在JSON之后对结构进行建模即可。
 - 在我的情况下,JSON的结构实际上并未确定,因此我可以创建一个结构,当我使用[string] interface {}的映射对其进行解析时,我遇到了嵌套元素的问题。该怎么办?
 
就像Volker提到的那样,嵌套结构是必经之路。但是,如果您确实不希望使用嵌套结构,则可以覆盖UnmarshalJSON函数。
https://play.golang.org/p/dqn5UdqFfJt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22  | type A struct { FooBar string // takes foo.bar FooBaz string // takes foo.baz More string } func (a *A) UnmarshalJSON(b []byte) error { var f interface{} json.Unmarshal(b, &f) m := f.(map[string]interface{}) foomap := m["foo"] v := foomap.(map[string]interface{}) a.FooBar = v["bar"].(string) a.FooBaz = v["baz"].(string) a.More = m["more"].(string) return nil }  | 
请忽略我没有返回正确错误的事实。为了简单起见,我将其省略。
更新:正确检索"更多"的值。
- 我正在&& {FooBar:1 FooBaz:2更多:}。缺少"文字"
 - @GuySegev我继续并更新了我的答案以解决该问题。感谢您指出了这一点。
 
这是一个如何从Safebrowsing v4 API sbserver代理服务器解组JSON响应的示例:https://play.golang.org/p/4rGB5da0Lt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52  | // this example shows how to unmarshall JSON requests from the Safebrowsing v4 sbserver package main import ( "fmt" "log" "encoding/json" ) // response from sbserver POST request type Results struct { Matches []Match } // nested within sbserver response type Match struct { ThreatType string PlatformType string ThreatEntryType string Threat struct { URL string } } func main() { fmt.Println("Hello, playground") // sample POST request // curl -X POST -H 'Content-Type: application/json' // -d '{"threatInfo": {"threatEntries": [{"url":"http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/MALWARE/URL/"}]}}' // http://127.0.0.1:8080/v4/threatMatches:find // sample JSON response jsonResponse := `{"matches":[{"threatType":"MALWARE","platformType":"ANY_PLATFORM","threatEntryType":"URL","threat":{"url":"http://testsafebrowsing.appspot.com/apiv4/ANY_PLATFORM/MALWARE/URL/"}}]}` res := &Results{} err := json.Unmarshal([]byte(jsonResponse), res) if(err!=nil) { log.Fatal(err) } fmt.Printf("%v ",res) fmt.Printf("\tThreat Type: %s ",res.Matches[0].ThreatType) fmt.Printf("\tPlatform Type: %s ",res.Matches[0].PlatformType) fmt.Printf("\tThreat Entry Type: %s ",res.Matches[0].ThreatEntryType) fmt.Printf("\tURL: %s ",res.Matches[0].Threat.URL) }  | 
- 感谢您展示json.Unmarshal可以解组复杂的深层嵌套json数据。我的问题是我正在从文件中读取JSON并以一些零填充结束。很高兴您分享了此信息!
 
是。使用gjson,您现在要做的就是:
如果愿意,
- 
fastjson也允许相同的技巧:
fastjson.GetString(json,"foo","bar")  
那匿名字段呢?我不确定这是否会构成"嵌套结构",但它比嵌套结构声明更干净。如果您想在其他地方重用嵌套元素怎么办?
1 2 3 4 5 6 7 8  | type NestedElement struct{ someNumber int `json:"number"` someString string `json:"string"` } type BaseElement struct { NestedElement `json:"bar"` }  | 
将嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22  | package main import ( "encoding/json" "fmt" ) // Object type Object struct { Foo map[string]map[string]string `json:"foo"` More string `json:"more"` } func main(){ someJSONString := []byte(`{"foo":{"bar":"1","baz":"2" },"more":"text"}`) var obj Object err := json.Unmarshal(someJSONString, &obj) if err != nil{ fmt.Println(err) } fmt.Println("jsonObj", obj) }  | 
我正在做这样的事情。但是仅适用于原型生成的结构。
https://github.com/flowup-labs/grpc-utils
在你的原始
1 2 3 4 5 6 7 8 9 10 11  | message Msg { Firstname string = 1 [(gogoproto.jsontag) ="name.firstname"]; PseudoFirstname string = 2 [(gogoproto.jsontag) ="lastname"]; EmbedMsg = 3 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; Lastname string = 4 [(gogoproto.jsontag) ="name.lastname"]; Inside string = 5 [(gogoproto.jsontag) ="name.inside.a.b.c"]; } message EmbedMsg{ Opt1 string = 1 [(gogoproto.jsontag) ="opt1"]; }  | 
然后您的输出将是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  | { "lastname":"Three", "name": { "firstname":"One", "inside": { "a": { "b": { "c":"goo" } } }, "lastname":"Two" }, "opt1":"var" }  | 
- 添加几行来解释这如何回答问题。如果仓库被删除,答案中将没有任何价值。
 - 我不认为他回来了,伙计们。
 
结合使用map和struct可以取消嵌套动态对象的嵌套JSON对象的编组。
=>地图[字串]
例如:stock.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  | { "MU": { "symbol":"MU", "title":"micro semiconductor", "share": 400, "purchase_price": 60.5, "target_price": 70 }, "LSCC":{ "symbol":"LSCC", "title":"lattice semiconductor", "share": 200, "purchase_price": 20, "target_price": 30 } }  | 
申请
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28  | package main import ( "encoding/json" "fmt" "io/ioutil" "log" "os" ) type Stock struct { Symbol string `json:"symbol"` Title string `json:"title"` Share int `json:"share"` PurchasePrice float64 `json:"purchase_price"` TargetPrice float64 `json:"target_price"` } type Account map[string]Stock func main() { raw, err := ioutil.ReadFile("stock.json") if err != nil { fmt.Println(err.Error()) os.Exit(1) } var account Account log.Println(account) }  | 
哈希中的动态键是处理字符串,而嵌套对象由结构表示。
- 这似乎是不完整的。未使用