解组嵌套的 JSON 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21268000/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unmarshaling nested JSON objects
提问by Simone Carletti
There are afewquestionson the topicbut none of them seem to cover my case, thus I'm creating a new one.
有一个小问题上的话题,但他们都不来覆盖我的情况,因此我创建一个新的。
I have JSON like the following:
我有如下 JSON:
{"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?
有没有办法解组嵌套的 bar 属性并将其直接分配给结构属性而不创建嵌套结构?
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.
我见过有人使用地图,但这不是我的情况。我基本上不关心foo(这是一个大对象)的内容,除了一些特定的元素。
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.
在这种情况下,正确的方法是什么?我不是在寻找奇怪的黑客,因此如果这是要走的路,我很好。
采纳答案by Volker
Is there a way to unmarshal the nested bar property and assign it directly to a struct property without creating a nested struct?
有没有办法解组嵌套的 bar 属性并将其直接分配给结构属性而不创建嵌套结构?
No, encoding/json cannot do the trick with ">some>deep>childnode" like encoding/xml can do. Nested structs is the way to go.
不, encoding/json 不能像 encoding/xml 那样使用“>some>deep>childnode”来解决这个问题。嵌套结构是要走的路。
回答by rexposadas
Like what Volker mentioned, nested structs is the way to go. But if you reallydo not want nested structs, you can override the UnmarshalJSON func.
就像 Volker 提到的那样,嵌套结构是要走的路。但是如果你真的不想要嵌套结构,你可以覆盖 UnmarshalJSON 函数。
https://play.golang.org/p/dqn5UdqFfJt
https://play.golang.org/p/dqn5UdqFfJt
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
}
Please ignore the fact that I'm not returning a proper error. I left that out for simplicity.
请忽略我没有返回正确错误的事实。为简单起见,我省略了这一点。
UPDATE: Correctly retrieving "more" value.
更新:正确检索“更多”值。
回答by Franke
This is an example of how to unmarshall JSON responses from the Safebrowsing v4 API sbserver proxy server: https://play.golang.org/p/4rGB5da0Lt
这是如何解组来自 Safebrowsing v4 API sbserver 代理服务器的 JSON 响应的示例: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)
}
回答by changingrainbows
回答by Rixarn
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"`
}
回答by Himanshu
Assign the values of nested jsonto struct until you know the underlying type of json keys:-
将嵌套的值分配json给结构,直到您知道 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)
}
回答by Vladan Ry?avy
I was working on something like this. But is working only with structures generated from proto. https://github.com/flowup-labs/grpc-utils
我正在做这样的事情。但仅适用于从 proto 生成的结构。 https://github.com/flowup-labs/grpc-utils
in your proto
在你的原型中
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"];
}
Then your output will be
那么你的输出将是
{
"lastname": "Three",
"name": {
"firstname": "One",
"inside": {
"a": {
"b": {
"c": "goo"
}
}
},
"lastname": "Two"
},
"opt1": "var"
}
回答by jvmvik
Combining map and struct allow unmarshaling nested JSON objects where the key is dynamic. => map[string]
结合 map 和 struct 允许解组键是动态的嵌套 JSON 对象。=> 地图[字符串]
For example: stock.json
例如:stock.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)
}
The dynamic key in the hash is handle a string, and the nested object is represented by a struct.
hash中的动态key是handle一个字符串,嵌套对象用struct表示。

