Unmarshaling nested JSON objects

后端 未结 8 1705
轻奢々
轻奢々 2020-11-27 11:37

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\"         


        
相关标签:
8条回答
  • 2020-11-27 11:43

    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)
    }
    
    0 讨论(0)
  • 2020-11-27 11:46

    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"`
    }
    
    0 讨论(0)
  • 2020-11-27 11:46

    Combining map and struct allow unmarshaling nested JSON objects where the key is dynamic. => map[string]

    For example: 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.

    0 讨论(0)
  • 2020-11-27 11:47

    Assign the values of nested json to struct until you know the underlying type of json keys:-

    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)
    }
    
    0 讨论(0)
  • 2020-11-27 11:50

    I was working on something like this. But is working only with structures generated from 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"
    }
    
    0 讨论(0)
  • 2020-11-27 11:53

    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.

    0 讨论(0)
提交回复
热议问题