Objets JSON imbriqués dans Golang

Il y a un quelques questions sur le sujet , mais aucun d'entre eux semblent couvrir mon cas, donc je suis en créer un nouveau.

j'ai JSON comme suit:

{"foo":{ "bar": "1", "baz": "2" }, "more": "text"}

y a-t-il un moyen de démasquer la propriété Bar imbriquée et de l'attribuer directement à une propriété struct sans créer une structure imbriquée?

le la solution que j'adopte maintenant est la suivante:

type Foo struct {
    More String `json:"more"`
    Foo  struct {
        Bar string `json:"bar"`
        Baz string `json:"baz"`
    } `json:"foo"`
    //  FooBar  string `json:"foo.bar"`
}

ceci est une version simplifiée, s'il vous plaît ignorez la verbosité. Comme vous pouvez le voir, j'aimerais pouvoir analyser et attribuer la valeur à

//  FooBar  string `json:"foo.bar"`

j'ai vu des gens utiliser une carte, mais ce n'est pas mon cas. Fondamentalement, Je ne me soucie pas du contenu de foo (qui est un grand objet), sauf pour quelques éléments spécifiques.

Quelle est l'approche correcte dans ce cas? Je ne suis pas à la recherche de piratages bizarres, donc si c'est le chemin à suivre, je suis d'accord avec ça.

73
demandé sur Adrian Forsius 2014-01-22 00:05:58

8 réponses

y a-t-il un moyen de démasquer la propriété Bar imbriquée et de l'attribuer directement à une propriété struct sans créer une structure imbriquée?

Non, encodage/json ne peut pas faire le truc avec ">>profondeur>childnode" comme l'encodage/xml peut faire. Les structures imbriquées sont la voie à suivre.

46
répondu Volker 2014-01-21 20:51:36

comme Volker l'a mentionné, les structures imbriquées sont la voie à suivre. Mais si vous vraiment ne voulez pas de structures imbriquées, vous pouvez outrepasser le func 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
}

s'il vous plaît ignorez le fait que je ne retourne pas une erreur correcte. J'ai quitté pour des raisons de simplicité.

18
répondu rexposadas 2014-06-07 15:02:33

Ceci est un exemple de comment désactiver les réponses JSON de 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)
}
10
répondu Franke 2016-06-06 16:09:54

Oui. Avec gjson tout ce que vous avez à faire maintenant est:

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

bar pourrait être une propriété struct si vous voulez. Aussi, pas de cartes.

7
répondu changingrainbows 2016-11-27 11:37:53

et les champs anonymes? Je ne suis pas sûr que cela constituera une "structure imbriquée" mais c'est plus propre que d'avoir une déclaration de structure imbriquée. Si vous souhaitez réutiliser l'élément imbriqué ailleurs?

type NestedElement struct{
    someNumber int `json:"number"`
    someString string `json:"string"`
}

type BaseElement struct {
    NestedElement `json:"bar"`
}
4
répondu Rixarn 2015-11-21 21:43:17

oui vous pouvez assigner les valeurs de JSON imbriqué à struct jusqu'à ce que vous connaissiez le type sous-jacent de clés json par exemple.

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
répondu Himanshu 2018-02-06 21:02:34

je travaillais sur quelque chose comme ça. Mais fonctionne uniquement avec des structures générées à partir de proto. https://github.com/flowup-labs/grpc-utils

dans votre 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"];
}

alors votre sortie sera

{
"lastname": "Three",
"name": {
    "firstname": "One",
    "inside": {
        "a": {
            "b": {
                "c": "goo"
            }
        }
    },
    "lastname": "Two"
},
"opt1": "var"
}
0
répondu Vladan Ryšavý 2018-03-27 14:09:29

combinant map et struct permettent de désamorcer les objets JSON imbriqués où la clé est dynamique. => carte[string]

par exemple: 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
  }
}

Aller de l'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)
}

la clé dynamique dans le hachage est manier une chaîne, et l'objet imbriqué est représenté par une structure.

0
répondu jvmvik 2018-04-01 02:22:57