Unmarshaling вложенные объекты JSON в Golang
здесь aнескольковопросы на темы но ни один из них, похоже, не покрывает мое дело, поэтому я создаю новый.
у меня есть JSON, как следующее:
{"foo":{ "bar": "1", "baz": "2" }, "more": "text"}
есть ли способ отключить свойство вложенного бара и назначить его непосредственно свойству структуры без создания вложенной структуры?
решение, которое я принимаю прямо сейчас, заключается в следующем:
type Foo struct {
More String `json:"more"`
Foo struct {
Bar string `json:"bar"`
Baz string `json:"baz"`
} `json:"foo"`
// FooBar string `json:"foo.bar"`
}
этот это упрощенная версия, Пожалуйста, игнорируйте многословие. Как вы можете видеть, я хотел бы иметь возможность анализировать и присваивать значение
// FooBar string `json:"foo.bar"`
Я видел людей, используя карту, но это не мой случай. Я в принципе не забочусь о содержании foo (который является большим объектом), за исключением некоторых элементов.
каков правильный подход в данном случае? Я не ищу странные хаки, поэтому, если это путь, я в порядке с этим.
8 ответов:
есть ли способ отключить свойство вложенного бара и назначить его непосредственно свойству структуры без создания вложенной структуры?
нет, кодировка/формат JSON не может сделать трюк с ">Некоторые>глубокий>childnode" кодирование/XML может сделать. Вложенные структуры-это путь.
Как и то, что упоминал Волкер, вложенные структуры-это путь. Но если вы действительно не хотите вложенных структур, вы можете переопределить функцию UnmarshalJSON.
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 }Пожалуйста, игнорируйте тот факт, что я не возвращаю правильную ошибку. Я оставил это для простоты.
Это пример того, как отключить ответы JSON от прокси-сервера Safebrowsing V4 API sbserver: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) }
да. С gjson все, что вам нужно сделать сейчас, это:
bar := gjson.Get(json, "foo.bar")
barможет быть свойство структуры, если вам нравится. Кроме того, нет карт.
Как насчет анонимных полей? Я не уверен, что это будет представлять собой "вложенную структуру", но это чище, чем объявление вложенной структуры. Что если вы хотите использовать вложенный элемент в другом месте?
type NestedElement struct{ someNumber int `json:"number"` someString string `json:"string"` } type BaseElement struct { NestedElement `json:"bar"` }
да вы можете назначить значения вложенных json в struct, пока не узнаете базовый тип ключей json, например.
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) }
Я работал над чем-то вроде этого. Но работает только со структурами, сгенерированными из proto. https://github.com/flowup-labs/grpc-utils
в прото
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"]; }тогда ваш выход будет
{ "lastname": "Three", "name": { "firstname": "One", "inside": { "a": { "b": { "c": "goo" } } }, "lastname": "Two" }, "opt1": "var" }
объединение map и struct позволяет размечать вложенные объекты JSON, где ключ является динамическим. = > map[string]
например: акции.json
{ "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 } }Go application
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) }динамический ключ в хэше обрабатывает строку, а вложенный объект представлен структурой.
Comments