解组嵌套的 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 20:11:37  来源:igfitidea点击:

Unmarshaling nested JSON objects

jsongo

提问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

Yes. With gjsonall you have to do now is:

是的。使用gjson,您现在要做的就是:

bar := gjson.Get(json, "foo.bar")

bar := gjson.Get(json, "foo.bar")

barcould be a struct property if you like. Also, no maps.

bar如果你愿意,可以是一个结构属性。另外,没有地图。

回答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表示。