8

我想将 geojson 字符串解组为合适的结构类型。我有三个不同的 geojson 字符串,我想将它们解组到同一个结构中:

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]]]}`)

我想出了一个我不完全满意的结构类型:

type GeojsonType struct {
    Type string
    Coordinates interface{}
}

有关完整示例,请参阅此链接: http ://play.golang.org/p/Bt-51BX__A

我宁愿不使用 interface{} 作为坐标。相反,我会使用一些可以验证的东西,例如 Coordinates [] float64 for Point 和 Coordinates[][] float64 for LineString。

是否可以创建一个结构类型,以便点、线串和多边形都可以在不使用接口的情况下以坐标表示?

4

2 回答 2

8

你想要的是从同一个 json 字典中创建 3 种不同类型的对象。

据我所知,这是不可能的,但是您可以使用RawMessage类型来延迟 json 解码并使用像这样的一些预处理

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)
    }
}

哪个打印

&{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]]]}}
于 2013-03-31T10:59:32.387 回答
2

基于 Nick Craig-Wood 的回答,我构建了以下 Marshal/UnMarshal 函数

package geojson

//https://stackoverflow.com/questions/15719532/suitable-struct-type-for-unmarshal-of-geojson

import (
    "encoding/json"
)

type Point struct {
    Coordinates []float64
}

type Line struct {
    Points [][]float64
}

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

type Geojson struct {
    Type        string          `json:"type"`
    Coordinates json.RawMessage `json:"coordinates"`
    Point       Point           `json:"-"`
    Line        Line            `json:"-"`
    Polygon     Polygon         `json:"-"`
}

func (g *Geojson) UnmarshalJSON(b []byte) error {

    type Alias Geojson
    aux := (*Alias)(g)

    err := json.Unmarshal(b, &aux)

    if err != nil {
        return err
    }

    switch g.Type {
    case "Point":
        err = json.Unmarshal(g.Coordinates, &g.Point.Coordinates)
    case "LineString":
        err = json.Unmarshal(g.Coordinates, &g.Line.Points)
    case "Polygon":
        err = json.Unmarshal(g.Coordinates, &g.Polygon.Lines)
    }

    g.Coordinates = []byte(nil)

    return err
}

func (g Geojson) MarshalJSON() ([]byte, error) {

    var raw json.RawMessage
    var err error

    switch g.Type {
    case "Point":
        raw, err = json.Marshal(&g.Point.Coordinates)
    case "LineString":
        raw, err = json.Marshal(&g.Line.Points)
    case "Polygon":
        raw, err = json.Marshal(&g.Polygon.Lines)
    }

    if err != nil {
        return nil, err
    }

    g.Coordinates = raw

    type Alias Geojson
    aux := (*Alias)(&g)
    return json.Marshal(aux)
}
于 2018-07-28T22:14:46.447 回答