Search code examples
arraysjsongoobjectunmarshalling

How to unmarshal objects inside array


I am trying to get access to object's values inside of array

[
  {
    "name": "London",
    "lat": 51.5073219,
    "lon": -0.1276474,
    "country": "GB",
    "state": "England"
  }
]

I use this code to unmarshal it

content, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatal(err)
    }

    var data []ResponseData
    err = json.Unmarshal(content, &data)
    if err != nil {
        log.Fatal(err)
    }

This is my struct

type ResponseData struct {
    Name       string      `json:"name"`
    Lat        float32     `json:"lat"`
    Lon        float32     `json:"lon"`
    Country    string      `json:"country"`
    State      string      `json:"state"`
}

I need to simply fmt.Println(data.Lat, data.Lon) later.


Solution

  • The code you presented should unmarshal your JSON successfully; the issue is with the way you are trying to use the result. You say you want to use fmt.Println(data.Lat, data.Lon) but this will not work because data is a slice ([]ResponseData) not a ResponseData. You could use fmt.Println(data[0].Lat, data[0].Lon) (after checking the number of elements!) or iterate through the elements.

    The below might help you experiment (playground - this contains a little more content than below):

    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
    )
    
    const rawJSON = `[
      {
        "name": "London",
        "lat": 51.5073219,
        "lon": -0.1276474,
        "country": "GB",
        "state": "England"
      }
    ]`
    
    type ResponseData struct {
        Name    string  `json:"name"`
        Lat     float32 `json:"lat"`
        Lon     float32 `json:"lon"`
        Country string  `json:"country"`
        State   string  `json:"state"`
    }
    
    func main() {
        var data []ResponseData
        err := json.Unmarshal([]byte(rawJSON), &data)
        if err != nil {
            log.Fatal(err)
        }
    
        if len(data) == 1 { // Would also work for 2+ but then you are throwing data away...
            fmt.Println("test1", data[0].Lat, data[0].Lon)
        }
    
        for _, e := range data {
            fmt.Println("test2", e.Lat, e.Lon)
        }
    }