可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
There are a few questions on the topic but none of them seem to cover my case, thus I'm creating a new one.
I have JSON like the following:
{"foo":{ "bar": "1", "baz": "2" }, "more": "text"}
Is there a way to unmarshal the nested bar property and assign it directly to a struct property without creating a nested struct?
The solution I'm adopting right now is the following:
type Foo struct { More String `json:"more"` Foo struct { Bar string `json:"bar"` Baz string `json:"baz"` } `json:"foo"` // FooBar string `json:"foo.bar"` }
This is a simplified version, please ignore the verbosity. As you can see, I'd like to be able to parse and assign the value to
// FooBar string `json:"foo.bar"`
I've seen people using a map, but that's not my case. I basically don't care about the content of foo
(which is a large object), except for a few specific elements.
What is the correct approach in this case? I'm not looking for weird hacks, thus if this is the way to go, I'm fine with that.
回答1:
Is there a way to unmarshal the nested bar property and assign it directly to a struct property without creating a nested struct?
No, encoding/json cannot do the trick with ">some>deep>childnode" like encoding/xml can do. Nested structs is the way to go.
回答2:
Like what Volker mentioned, nested structs is the way to go. But if you really do not want nested structs, you can override the UnmarshalJSON func.
http://play.golang.org/p/T0aZEDL0Nu
type A struct { FooBar string // takes foo.bar FooBaz string // takes foo.baz More string `json:"more"` } 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) return nil }
Please ignore the fact that I'm not returning a proper error. I left that out for simplicity.
回答3:
This is an example of how to unmarshall JSON responses from the Safebrowsing v4 API sbserver proxy server: https://play.golang.org/p/4rGB5da0Lt
// 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\n",res) fmt.Printf("\tThreat Type: %s\n",res.Matches[0].ThreatType) fmt.Printf("\tPlatform Type: %s\n",res.Matches[0].PlatformType) fmt.Printf("\tThreat Entry Type: %s\n",res.Matches[0].ThreatEntryType) fmt.Printf("\tURL: %s\n",res.Matches[0].Threat.URL) }
回答4:
Yes. With gjson all you have to do now is:
bar := gjson.Get(json, "foo.bar")
bar
could be a struct property if you like. Also, no maps.
回答5:
What about anonymous fields? I'm not sure if that will constitute a "nested struct" but it's cleaner than having a nested struct declaration. What if you want to reuse the nested element elsewhere?
type NestedElement struct{ someNumber int `json:"number"` someString string `json:"string"` } type BaseElement struct { NestedElement `json:"bar"` }
回答6:
yes you can assign the values of nested json to struct until you know the underlying type of json keys for example.
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) }