Comment obtenir une réponse JSON dans Golang

J’essaie de lire les données JSON à partir du Web, mais ce code renvoie un résultat vide. Je ne suis pas sûr de ce que je fais mal ici.

package main import "os" import "fmt" import "net/http" import "io/ioutil" import "encoding/json" type Tracks struct { Toptracks []Toptracks_info } type Toptracks_info struct { Track []Track_info Attr []Attr_info } type Track_info struct { Name ssortingng Duration ssortingng Listeners ssortingng Mbid ssortingng Url ssortingng Streamable []Streamable_info Artist []Artist_info Attr []Track_attr_info } type Attr_info struct { Country ssortingng Page ssortingng PerPage ssortingng TotalPages ssortingng Total ssortingng } type Streamable_info struct { Text ssortingng Fulltrack ssortingng } type Artist_info struct { Name ssortingng Mbid ssortingng Url ssortingng } type Track_attr_info struct { Rank ssortingng } func get_content() { // json data url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" res, err := http.Get(url) if err != nil { panic(err.Error()) } body, err := ioutil.ReadAll(res.Body) if err != nil { panic(err.Error()) } var data Tracks json.Unmarshal(body, &data) fmt.Printf("Results: %v\n", data) os.Exit(0) } func main() { get_content() } 

Le moyen idéal est de ne pas utiliser ioutil.ReadAll, mais plutôt d’utiliser directement un décodeur sur le lecteur. Voici une belle fonction qui obtient une URL et décode sa réponse sur une structure target .

 var myClient = &http.Client{Timeout: 10 * time.Second} func getJson(url ssortingng, target interface{}) error { r, err := myClient.Get(url) if err != nil { return err } defer r.Body.Close() return json.NewDecoder(r.Body).Decode(target) } 

Exemple d’utilisation:

 type Foo struct { Bar ssortingng } func main() { foo1 := new(Foo) // or &Foo{} getJson("http://example.com", foo1) println(foo1.Bar) // alternately: foo2 := Foo{} getJson("http://example.com", &foo2) println(foo2.Bar) } 

Vous ne devriez pas utiliser la structure par défaut * http.Client en production car cette réponse a initialement été démontrée! (Quel est ce que http.Get / etc appel à). La raison en est que le client par défaut n’a pas de délai d’expiration défini; Si le serveur distant ne répond pas, vous allez avoir une mauvaise journée.

Votre problème était les déclarations de tranche dans vos structs données (sauf pour Track , elles ne devraient pas être des tranches …). Cela a été aggravé par des noms de champs plutôt bizarres dans le fichier json récupéré, qui peuvent être corrigés via structtags, voir godoc .

Le code ci-dessous a analysé le json avec succès. Si vous avez d’autres questions, faites-le moi savoir.

 package main import "fmt" import "net/http" import "io/ioutil" import "encoding/json" type Tracks struct { Toptracks Toptracks_info } type Toptracks_info struct { Track []Track_info Attr Attr_info `json: "@attr"` } type Track_info struct { Name ssortingng Duration ssortingng Listeners ssortingng Mbid ssortingng Url ssortingng Streamable Streamable_info Artist Artist_info Attr Track_attr_info `json: "@attr"` } type Attr_info struct { Country ssortingng Page ssortingng PerPage ssortingng TotalPages ssortingng Total ssortingng } type Streamable_info struct { Text ssortingng `json: "#text"` Fulltrack ssortingng } type Artist_info struct { Name ssortingng Mbid ssortingng Url ssortingng } type Track_attr_info struct { Rank ssortingng } func perror(err error) { if err != nil { panic(err) } } func get_content() { url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" res, err := http.Get(url) perror(err) defer res.Body.Close() decoder := json.NewDecoder(res.Body) var data Tracks err = decoder.Decode(&data) if err != nil { fmt.Printf("%T\n%s\n%#v\n",err, err, err) switch v := err.(type){ case *json.SyntaxError: fmt.Println(ssortingng(body[v.Offset-40:v.Offset])) } } for i, track := range data.Toptracks.Track{ fmt.Printf("%d: %s %s\n", i, track.Artist.Name, track.Name) } } func main() { get_content() } 

Vous avez besoin des noms de propriété en majuscule dans vos structures pour pouvoir être utilisés par les packages json.

Les noms de propriété en majuscule sont des exported properties . Les noms de propriété minuscules ne sont pas exportés.

Vous devez également transmettre votre object de données par référence ( &data ).

 package main import "os" import "fmt" import "net/http" import "io/ioutil" import "encoding/json" type tracks struct { Toptracks []toptracks_info } type toptracks_info struct { Track []track_info Attr []attr_info } type track_info struct { Name ssortingng Duration ssortingng Listeners ssortingng Mbid ssortingng Url ssortingng Streamable []streamable_info Artist []artist_info Attr []track_attr_info } type attr_info struct { Country ssortingng Page ssortingng PerPage ssortingng TotalPages ssortingng Total ssortingng } type streamable_info struct { Text ssortingng Fulltrack ssortingng } type artist_info struct { Name ssortingng Mbid ssortingng Url ssortingng } type track_attr_info struct { Rank ssortingng } func get_content() { // json data url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" res, err := http.Get(url) if err != nil { panic(err.Error()) } body, err := ioutil.ReadAll(res.Body) if err != nil { panic(err.Error()) } var data tracks json.Unmarshal(body, &data) fmt.Printf("Results: %v\n", data) os.Exit(0) } func main() { get_content() } 

Les résultats de json.Unmarshal (dans var data interface{} ) ne correspondent pas directement à vos déclarations de type et de variable Go. Par exemple,

 package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" "os" ) type Tracks struct { Toptracks []Toptracks_info } type Toptracks_info struct { Track []Track_info Attr []Attr_info } type Track_info struct { Name ssortingng Duration ssortingng Listeners ssortingng Mbid ssortingng Url ssortingng Streamable []Streamable_info Artist []Artist_info Attr []Track_attr_info } type Attr_info struct { Country ssortingng Page ssortingng PerPage ssortingng TotalPages ssortingng Total ssortingng } type Streamable_info struct { Text ssortingng Fulltrack ssortingng } type Artist_info struct { Name ssortingng Mbid ssortingng Url ssortingng } type Track_attr_info struct { Rank ssortingng } func get_content() { // json data url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" url += "&limit=1" // limit data for testing res, err := http.Get(url) if err != nil { panic(err.Error()) } body, err := ioutil.ReadAll(res.Body) if err != nil { panic(err.Error()) } var data interface{} // TopTracks err = json.Unmarshal(body, &data) if err != nil { panic(err.Error()) } fmt.Printf("Results: %v\n", data) os.Exit(0) } func main() { get_content() } 

Sortie:

 Results: map[toptracks:map[track:map[name:Get Lucky (feat. Pharrell Williams) listeners:1863 url:http://www.last.fm/music/Daft+Punk/_/Get+Lucky+(feat.+Pharrell+Williams) artist:map[name:Daft Punk mbid:056e4f3e-d505-4dad-8ec1-d04f521cbb56 url:http://www.last.fm/music/Daft+Punk] image:[map[#text:http://soffr.miximages.com/json/88137413.png size:small] map[#text:http://soffr.miximages.com/json/88137413.png size:medium] map[#text:http://soffr.miximages.com/json/88137413.png size:large] map[#text:http://soffr.miximages.com/json/88137413.png size:extralarge]] @attr:map[rank:1] duration:369 mbid: streamable:map[#text:1 fulltrack:0]] @attr:map[country:Netherlands page:1 perPage:1 totalPages:500 total:500]]]