Suitable struct type for unmarshal of geojson

go

Solution

What you want is to create 3 different types of object from the same json dictionary.

As far as I know that isn't possible, however you can use the RawMessage type to delay the json decoding and use a bit of pre-processing like this

package main

import (
    "encoding/json"
    "fmt"
)

type Point struct {
    Coordinates []float64
}

type Line struct {
    Points [][]float64
}

type Polygon struct {
    Lines [][][]float64
}

type GeojsonType struct {
    Type        string
    Coordinates json.RawMessage
    Point       Point
    Line        Line
    Polygon     Polygon
}

var jsonBlob = []byte(`[
{"Type":"Point", "Coordinates":[1.1,2.0]},
{"Type":"LineString", "Coordinates":[[1.1,2.0],[3.0,6.3]]},
{"Type":"Polygon", "Coordinates":[[[1.1,2.0],[3.0,6.3],[5.1,7.0],[1.1,2.0]]]}
]`)

func main() {
    var geojsonPoints []GeojsonType
    err := json.Unmarshal(jsonBlob, &geojsonPoints)
    if err != nil {
        fmt.Println("error:", err)
    }

    // Postprocess the coordinates  

    for i := range geojsonPoints {
        t := &geojsonPoints[i]

        switch t.Type {
        case "Point":
            err = json.Unmarshal(t.Coordinates, &t.Point.Coordinates)
        case "LineString":
            err = json.Unmarshal(t.Coordinates, &t.Line.Points)
        case "Polygon":
            err = json.Unmarshal(t.Coordinates, &t.Polygon.Lines)
        default:
            panic("Unknown type")
        }
        if err != nil {
            fmt.Printf("Failed to convert %s: %s", t.Type, err)
        }
        fmt.Printf("%+v\n", t)
    }
}

Which prints

&{Type:Point Coordinates:[91 49 46 49 44 50 46 48 93] Point:{Coordinates:[1.1 2]} Line:{Points:[]} Polygon:{Lines:[]}}
&{Type:LineString Coordinates:[91 91 49 46 49 44 50 46 48 93 44 91 51 46 48 44 54 46 51 93 93] Point:{Coordinates:[]} Line:{Points:[[1.1 2] [3 6.3]]} Polygon:{Lines:[]}}
&{Type:Polygon Coordinates:[91 91 91 49 46 49 44 50 46 48 93 44 91 51 46 48 44 54 46 51 93 44 91 53 46 49 44 55 46 48 93 44 91 49 46 49 44 50 46 48 93 93 93] Point:{Coordinates:[]} Line:{Points:[]} Polygon:{Lines:[[[1.1 2] [3 6.3] [5.1 7] [1.1 2]]]}}

Problem

I want to unmarshal a geojson string into a suitable struct type. I have three different geojson strings that I want to unmarshal into the same struct: ``` var jsonBlobPointString = []byte(`{"Type":"Point", "Coordinates":[1.1,2.0]}`) var jsonBlobLineString = []byte(`{"Type":"LineString", "Coordinates":[[1.1,2.0],[3.0,6.3]]}`) var jsonBlobPolygonString = []byte(`{"Type":"Polygon", "Coordinates":[[[1.1,2.0],[3.0,6.3],[5.1,7.0],[1.1,2.0]]]}`) ``` I came up with a struct type that I´m not totally happy with: ``` type GeojsonType struct { Type string Coordinates interface{} } ``` See this link for complete example: http://play.golang.org/p/Bt-51BX__A I would rather not use interface{} for Coordinates. I would instead use somehting that give me some validation for example Coordinates [] float64 for Point and Coordinates[][] float64 for LineString. Is it possible to create a struct type so that Point, LineString and Polygon all can be represented in Coordinates without using interface?

Original source