2012-11-27 21 views
35

Ho un oggetto JSON simile a questo:Come analizzare un campo interno in un oggetto JSON nidificato in Golang?

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

Ora voglio analizzare "nome" e "madre" in questo struct:

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

voglio specificare il nome del campo JSON con il tag struct json:..., tuttavia non so cosa usare come tag, perché non è l'oggetto principale a cui sono interessato. Non ho trovato nulla a riguardo nei documenti del pacchetto encoding/json né nel popolare post del blog JSON and Go. Ho anche testato mother, parents/mother e parents.mother.

risposta

16

Sfortunatamente, a differenza encoding/xml, il pacchetto json non fornisce un modo per accedere ai valori nidificate. Dovrai creare una struttura Parents separata o assegnare il tipo a map[string]string. Per esempio:

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

Si potrebbe quindi fornire un getter per la madre come così:

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

Questo può o non può giocare nella vostra base di codice attuale e se refactoring il campo Mother ad una chiamata di metodo non è Nel menu, è possibile creare un metodo separato per la decodifica e la conformità alla struttura corrente.

6

Ecco qualche codice ho cotto fino reale veloce nel 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)) 
} 

Ci potrebbe essere un modo migliore. Non vedo l'ora di vedere le altre risposte. :-)

+0

So che questo funziona, ma spero che ci sia una soluzione più ... leggibile. – keks

+0

Deve funzionare in questo modo perché l'interfaccia {} deve essere dichiarata come un tipo (in questo caso, digitare map [string] interface {}). Il modo più semplice è quello di usare una lib con metodi helper come [go-simplejson] (http://godoc.org/github.com/bitly/go-simplejson) – Druska

+0

questa struttura nidificata che non esegue il riarmo mi sta dando grossi grattacapi. boooo –

17

È possibile utilizzare le strutture finché i dati in ingresso non sono troppo dinamici.

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) 
} 
+1

Ne sono consapevole. Comunque non voglio usare due structs ma uno, e non voglio nidificarli. I tag di campo Struct forniscono un modo per specificare quale campo JSON deve essere usato, ma ero curioso di sapere se danno un modo per accedere ai campi nidificati, campi che non sono membri dell'oggetto root. – keks

+1

'remy_o' ha detto su' # go-nuts', che il pacchetto 'encoding/json' non fa quello che ho chiesto, quindi questa è la risposta con cui sono bloccato. O nelle sue parole: "il pacchetto JSON non è XPath". – keks

2

Come utilizzare una struttura intermedia come quella suggerita sopra per l'analisi e quindi inserire i valori rilevanti nella struttura "reale"?

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) 
} 
3

Più recentemente, gjson supporta la selezione di proprietà JSON nidificate.

name := gjson.Get(json, "name") 
mother := gjson.Get(json, "parents.mother") 
Problemi correlati