Démarrez les objets JSON imbriqués


122

Il y a quelques questions sur le sujet mais aucune d'elles ne semble couvrir mon cas, j'en crée donc une nouvelle.

J'ai JSON comme le suivant:

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

Existe-t-il un moyen d'annuler la valeur de la propriété de barre imbriquée et de l'affecter directement à une propriété de structure sans créer de structure imbriquée?

La solution que j'adopte en ce moment 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, veuillez ignorer 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. Je ne me soucie fondamentalement pas du contenu de foo(qui est un gros objet), à l'exception de quelques éléments spécifiques.

Quelle est la bonne approche dans ce cas? Je ne cherche pas de hacks étranges, donc si c'est la voie à suivre, je suis d'accord avec ça.

Réponses:


67

Existe-t-il un moyen d'annuler la valeur de la propriété de barre imbriquée et de l'affecter directement à une propriété de structure sans créer de structure imbriquée?

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


1
Pourquoi est-ce différent de encoding / xml?
Caleb Hearth

1
@CalebThompson La structure pour XML et JSON est complètement différente, même si les cas simples se ressemblent. Le contenu d'une balise XML est en quelque sorte: (Une carte ordonnée de sous-balises OU Texte) ET une carte non ordonnée d'attributs. JSON ressemble beaucoup plus à une structure Go. Le mappage de JSON aux structures est donc beaucoup plus simple: modélisez simplement la structure après votre JSON.
Volker

dans mon cas, la structure de JSON n'est pas réellement décidée afin que je puisse créer une structure et quand je l'analyse en utilisant la carte de [string] interface {}, j'ai des problèmes pour les éléments imbriqués. Ce qui peut être fait.?
viveksinghggits

Mais pourquoi ne pouvons-nous pas annuler le mars pour structurer à l'intérieur de struct?
Vitaly Zdanevich

29

Comme ce que Volker a mentionné, les structures imbriquées sont la voie à suivre. Mais si vous ne voulez vraiment pas de structures imbriquées, vous pouvez remplacer la fonction UnmarshalJSON.

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
}

Veuillez ignorer le fait que je ne renvoie pas une erreur appropriée. J'ai laissé cela pour simplifier.

MISE À JOUR: Récupération correcte de la valeur "plus".


3
Je reçois & {FooBar: 1 FooBaz: 2 More:}. "Texte" manquant
Guy Segev

@GuySegev Je suis allé de l'avant et j'ai mis à jour ma réponse pour résoudre ce problème. Merci d'avoir fait remarquer cela.
rexposadas

22

Voici un exemple de la façon d'annuler les réponses JSON du serveur proxy sbserver de l'API Safebrowsing v4: 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)
}

2
Merci d'avoir montré que json.Unmarshal peut démarshal une donnée json complexe profondément imbriquée. Mon problème était que je lisais JSON à partir d'un fichier et que je me suis retrouvé avec un rembourrage nul. Heureux que vous ayez partagé ça!
Rohanthewiz

12

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

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

barpourrait être une propriété struct si vous le souhaitez. De plus, pas de cartes.


1
fastjson permet également le même truc: fastjson.GetString(json, "foo", "bar")
valyala

9

Qu'en est-il des champs anonymes? Je ne sais pas si cela constituera une "structure imbriquée" mais c'est plus propre que d'avoir une déclaration de structure imbriquée. Que faire 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"`
}

1

Attribuez les valeurs de nested jsonà struct jusqu'à ce que vous connaissiez le type sous-jacent des clés 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)
}

0

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

dans ton 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"
}

2
Ajoutez quelques lignes pour expliquer comment cela répond à la question. Si le dépôt est supprimé, il ne reste aucune valeur dans la réponse.
Ubercool

Je ne pense pas qu'il revienne, les amis.
DevX

-1

La combinaison de map et de struct permet de démarshaling des objets JSON imbriqués où la clé est dynamique. => carte [chaîne]

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 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 gère une chaîne et l'objet imbriqué est représenté par une structure.


3
cela semble incomplet. raw n'est pas utilisé
buildmaestro
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.