2016-05-31 1 views
1

Je suis en train de travailler avec l'API Flickr et j'ai un point final qui me donne une réponse comme çaUnmarshal ne me donne que premier élément de tableau qui est imbriqué en réponse JSON

{ 
    "photos": { 
    "page": 1, 
    "pages": 500, 
    "perpage": 1, 
    "total": 500, 
    "photo": [ 
     { 
     "id": "12345", 
     "owner": "[email protected]", 
     "secret": "12ab345xyz", 
     "server": "1234", 
     "farm": 1, 
     "title": "Some Title", 
     "ispublic": 1, 
     "isfriend": 0, 
     "isfamily": 0 
     }, 
    ... 
    ] 
    }, 
    "stat": "ok" 
} 

J'ai un struct ressemble à ceci

type FlickrResp struct { 
    Photos struct { 
     Page int   `json:"page"`  //what page the results were retreived from 
     Pages int   `json:"pages"`  //total number of pages of results 
     Perpage int   `json:"perpage"` //number of results per page 
     Total int   `json:"total"`  //total number of results 
     Photo []struct { 
      ID string  `json:"id"`   //image ID 
      Owner string `json:"owner"`  //owner ID 
      Secret string `json:"secret"`  //owner secret 
      Server string `json:"server"`  //server ID 
      Farm int  `json:"farm"`  //farm ID 
      Title string `json:"title"`  //image title 
      Ispublic string `json:"ispublic"` //is image publicly viewable? 
      Isfriend string `json:"isfriend"` //is image owner my friend? 
      Isfamily string `json:"isfamily"` //is image owner my family? 
     }     `json:"photo"`  //array of objects with details of photos 
    }      `json:"photos"`  //object that holds information about photoset 
    Stat string    `json:"stat"`  //status 
} 

et je suis en train de Unmarshal thusly

var fr FlickrResp            //create blank struct of type FlickrResp to hold JSON 
resp, err := ioutil.ReadAll(flickrCB.Body)      //read HTTP GET response 
if err != nil { 

} 
json.Unmarshal([]byte(resp), &fr)        //serialize JSON into template 

flickCB.Body provient d'un n http.Get

Le problème est que je n'obtenir le premier élément du tableau photo. Je peux voir que j'ai plus d'un élément quand j'imprime l'objet de réponse cast en tant que chaîne. Qu'est-ce que je fais mal? Je me suis cogné la tête contre Unmarshal et des réponses JSON plus compliquées pendant quelques jours maintenant.

+2

Lisez-vous l'erreur de 'json.Unmarshal'? Quand j'essaie ce qui précède, j'ai un problème avec la différence de type entre 'ispublic',' isfriend', et 'isfamily' par rapport aux chaînes attendues par la structure. Si je change les types, cela semble fonctionner. Voici un exemple avec le changement, y compris l'utilisation d'un champ de 'json.Number', ce qui peut être pratique dans des cas comme celui-ci - https://play.golang.org/p/4fE_MkxgxS. Je vois deux entrées dans 'Photo' dans les résultats. – Bubbles

+0

Ca l'a fait, merci. Je ne veux pas parler du nombre de fois que je suis passé par là. –

Répondre

4

Questions traitées à l'origine dans les commentaires, mais pour un peu plus de précisions:

Une erreur non détectée de json.Unmarshal:

json: cannot unmarshal number into Go value of type string

Causé par une incompatibilité de type entre l'API de scintillement envoie-ispublic, isfriend , et isfamily comme entiers, mais la structure attendait des chaînes. Une solution facile est juste de les convertir en ints. Une autre option pour ce genre de situations est d'utiliser json.Number, qui enveloppe une chaîne de base de la source json et fournit quelques méthodes pratiques pour la convertir en nombre plus tard (ou simplement la garder comme une chaîne). En faisant dire

Ispublic json.Number `json:"ispublic"` //is image publicly viewable? 
Isfriend json.Number `json:"isfriend"` //is image owner my friend? 
Isfamily json.Number `json:"isfamily"` 

Il fonctionnera très bien, et le résultat peut facilement être obtenu sous forme de chaîne via fr.Ispublic.String().

Un changement plus complexe qui pourrait être utile dans cette situation est d'utiliser un type booléen personnalisé. Les valeurs en question semblent refléter les booléens, mais les entiers ne sont pas non plus mappés proprement aux booléens. Un type désérialisé personnalisé peut être utilisé. L'emprunt de this example ailleurs sur stackoverflow:

type ConvertibleBoolean bool 

func (bit ConvertibleBoolean) UnmarshalJSON(data []byte) error { 
    asString := string(data) 
    if asString == "1" || asString == "true" { 
     bit = true 
    } else if asString == "0" || asString == "false" { 
     bit = false 
    } else { 
     return errors.New(fmt.Sprintf("Boolean unmarshal error: invalid input %s", asString)) 
    } 
    return nil 
} 

ci-dessus ne vous racontons les Is* valeurs ConvertibleBoolean, et la carte automatiquement les 0 & 1 valeurs que vous souhaitez sans doute obtenez dans ces champs de Flickr à booléens.