I want to parse some json data in go. The data looks like this:
{"id":"someId","key_1":"value_1","key_2":"value_2","key_3":"value_3","points":[[1487100466412,"50.032178","8.526018",300,0.0,26,0],[1487100471563,"50.030869","8.525949",300,0.0,38,0],[1487100475722,"50.028514","8.525959",225,0.0,69,-900],[1487100480834,"50.025827","8.525793",275,0.0,92,-262],...]}
I built a go struct:
type SomeStruct struct {
ID string `json:"id"`
Key1 string `json:"key_1"`
Key2 string `json:"key_2"`
Key3 string `json:"key_3"`
Points []Point `json:"points"`
}
type Point struct {
Timestamp int64 `json:"0"`
Latitude float64 `json:"1,string"`
Longitude float64 `json:"2,string"`
Altitude int `json:"3"`
Value1 float64 `json:"4"`
Value2 int `json:"5"`
Value3 int `json:"6"`
}
I unmarshal the json data
var track SomeStruct
error := json.Unmarshal(data,&track)
if(error != nil){
fmt.Printf("Error while parsing data: %s", error)
}
json: cannot unmarshal array into Go value of type Point{someId value_1 value_2 value_3 [{0 0 0 0 0 0 0} {0 0 0 0 0 0 0} {0 0 0 0 0 0 0}...]}
So the first json keys are parsed correctly, but I cannot figure out how to get the point data, which is an array of arrays.
The generate struct is also the suggest one from here, except I don't use a nested struct but a separate type. Using the suggested nested struct does not make a difference: JSON-to-Go
Do I need to implement my own Unmarshaller for this?
======= UPDATE SOLUTION ============
It is enough to implement the UnmarshalJSON interface for the Point struct. The example below does not contain proper error handling but it show the direction.
Playground example
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type SomeStruct struct {
ID string `json:"id"`
Key1 string `json:"key_1"`
Key2 string `json:"key_2"`
Key3 string `json:"key_3"`
Points []Point `json:"points"`
}
type Point struct {
Timestamp int64
Latitude float64
Longitude float64
Altitude int
Value1 float64
Value2 int16
Value3 int16
}
func (tp *Point) UnmarshalJSON(data []byte) error {
var v []interface{}
if err := json.Unmarshal(data, &v); err != nil {
fmt.Printf("Error whilde decoding %v\n", err)
return err
}
tp.Timestamp = int64(v[0].(float64))
tp.Latitude, _ = strconv.ParseFloat(v[1].(string), 64)
tp.Longitude, _ = strconv.ParseFloat(v[2].(string), 64)
tp.Altitude = int(v[3].(float64))
tp.Value1 = v[4].(float64)
tp.Value2 = int16(v[5].(float64))
tp.Value3 = int16(v[6].(float64))
return nil
}
func main() {
const data = `{"id":"someId","key_1":"value_1","key_2":"value_2","key_3":"value_3","points":[[1487100466412,"50.032178","8.526018",300,0.0,26,0],[1487100471563,"50.030869","8.525949",300,0.0,38,0],[1487100475722,"50.028514","8.525959",225,0.0,69,-900],[1487100480834,"50.025827","8.525793",275,0.0,92,-262]]}`
var something SomeStruct
json.Unmarshal([]byte(data), &something)
fmt.Printf("%v", something)
}
To unmarshal a JSON array into a slice, Unmarshal resets the slice length to zero and then appends each element to the slice. As a special case, to unmarshal an empty JSON array into a slice, Unmarshal replaces the slice with a new empty slice.
To parse JSON, we use the Unmarshal() function in package encoding/json to unpack or decode the data from JSON to a struct. Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. Note: If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.
Golang Unmarshal It allows you to convert byte data into the original data structure. In go, unmarshaling is handled by the json. Unmarshal() method.
A JSON array contains zero, one, or more ordered elements, separated by a comma. The JSON array is surrounded by square brackets [ ] . A JSON array is zero terminated, the first index of the array is zero (0). Therefore, the last index of the array is length - 1.
The JSON:
[
{
"type": "Car",
"wheels": 4
},
{
"type": "Motorcycle",
"wheels": 2
}
]
The Struct:
type Vehicle struct {
Type string
Wheels int
}
The Unmarshaller:
func TestVehicleUnmarshal(t *testing.T) {
response := `[{"type": "Car","wheels": 4},{"type": "Motorcycle","wheels": 2}]`
var vehicles []Vehicle
json.Unmarshal([]byte(response), &vehicles)
assert.IsType(t, Vehicle{}, vehicles[0])
assert.EqualValues(t, "Car", vehicles[0].Type)
assert.EqualValues(t, 4, vehicles[0].Wheels)
assert.EqualValues(t, "Motorcycle", vehicles[1].Type)
assert.EqualValues(t, 2, vehicles[1].Wheels)
}
https://play.golang.org/p/5SfDH-XZt9J
Do I need to implement my own Unmarshaller for this?
Yes.
You're trying to unmarshal an array into a struct (Point
), which means you need to tell the JSON unmarshaler how the array values map to the struct values.
Also note that your tags are incorrect in your Point
definition. json tags refer to the key names, but arrays don't have keys (in JavaScript they can be accessed as if they do, but this isn't JavaScript). In other words, json:"0"
will only work if your JSON looks like {"0":123}
. If you implement your own unmarshaler, you can just get rid of those json tags.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With