web-dev-qa-db-fra.com

Comment analyser un champ intérieur dans un objet JSON imbriqué dans Golang?

J'ai un objet JSON similaire à celui-ci:

{
  "name": "Cain",
  "parents": {
    "mother" : "Eve",
    "father" : "Adam"
  }
}

Maintenant, je veux analyser "nom" et "mère" dans cette structure:

struct {
  Name String
  Mother String `json:"???"`
}

Je veux spécifier le nom du champ JSON avec le json:... struct tag, mais je ne sais pas quoi utiliser comme balise, car ce n'est pas le premier objet qui m'intéresse. Je n'ai rien trouvé à ce sujet dans le encoding/json package docs ni dans le blog populaire JSON et Go . J'ai également testé mother, parents/mother et parents.mother.

37
keks

Malheureusement, contrairement à encoding/xml, le package json ne permet pas d'accéder aux valeurs imbriquées. Vous voudrez soit créer une structure Parents distincte, soit attribuer le type à map[string]string. Par exemple:

type Person struct {
    Name string
    Parents map[string]string
}

Vous pourriez alors fournir un getter pour la mère comme suit:

func (p *Person) Mother() string {
    return p.Parents["mother"]
}

Cela peut ou non jouer dans votre base de code actuelle et si la refactorisation du champ Mother en un appel de méthode n'est pas dans le menu, alors vous voudrez peut-être créer une méthode distincte pour le décodage et la conformité à votre structure actuelle.

18
dskinner

Vous pouvez utiliser des structures tant que vos données entrantes ne sont pas trop dynamiques.

http://play.golang.org/p/bUZ8l6WgvL

package main

import (
    "fmt"
    "encoding/json"
    )

type User struct {
    Name string
    Parents struct {
        Mother string
        Father string
    }
}

func main() {
    encoded := `{
        "name": "Cain",
        "parents": {
            "mother": "Eve",
            "father": "Adam"
        }
    }`

    // Decode the json object
    u := &User{}
    err := json.Unmarshal([]byte(encoded), &u)
    if err != nil {
        panic(err)
    }

    // Print out mother and father
    fmt.Printf("Mother: %s\n", u.Parents.Mother)
    fmt.Printf("Father: %s\n", u.Parents.Father)
}
19
Daniel

Voici un code que j'ai préparé très rapidement dans le Go Playground

http://play.golang.org/p/PiWwpUbBqt

package main

import (
    "fmt"
    "encoding/json"
    )

func main() {
    encoded := `{
        "name": "Cain",
        "parents": {
            "mother": "Eve"
            "father": "Adam"
        }
    }`

    // Decode the json object
    var j map[string]interface{}
    err := json.Unmarshal([]byte(encoded), &j)
    if err != nil {
        panic(err)
    }

    // pull out the parents object
    parents := j["parents"].(map[string]interface{})

    // Print out mother and father
    fmt.Printf("Mother: %s\n", parents["mother"].(string))
    fmt.Printf("Father: %s\n", parents["father"].(string))
}

Il pourrait y avoir une meilleure façon. J'ai hâte de voir les autres réponses. :-)

6
Daniel

Plus récemment, gjson prend en charge la sélection des propriétés JSON imbriquées.

name := gjson.Get(json, "name")
mother := gjson.Get(json, "parents.mother")
5
changingrainbows

Que diriez-vous d'utiliser une structure intermédiaire comme celle suggérée ci-dessus pour l'analyse, puis de mettre les valeurs pertinentes dans votre structure "réelle"?

import (
    "fmt"
    "encoding/json"
    )

type MyObject struct{
  Name string
  Mother string
}

type MyParseObj struct{
   Name string
   Parents struct {
         Mother string
         Father string
   } 
}


func main() {
    encoded := `{
         "name": "Cain",
         "parents": {
             "mother": "Eve",
             "father": "Adam"
         }
    }`

    pj := &MyParseObj{}
    if err := json.Unmarshal([]byte(encoded), pj); err != nil {
        return
    }
    final := &MyObject{Name: pj.Name, Mother: pj.Parents.Mother}
    fmt.Println(final)  
}
2
tike