Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3e8aea4
Showing
11 changed files
with
1,277 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
language: go | ||
|
||
go: | ||
- 1.2 | ||
- 1.3 | ||
|
||
after_script: | ||
- FIXED=$(go vet ./... | wc -l); if [ $FIXED -gt 0 ]; then echo "go vet - $FIXED issues(s), please fix." && exit 2; fi | ||
- FIXED=$(go fmt ./... | wc -l); if [ $FIXED -gt 0 ]; then echo "gofmt - $FIXED file(s) not formatted correctly, please run gofmt to fix this." && exit 2; fi | ||
|
||
script: | ||
- go test -v | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
go.geojson | ||
========== | ||
|
||
go.geojson is a library for **encoding and decoding** [GeoJSON](http://geojson.org/) into Go structs. | ||
Supports both the [json.Marshaler](http://golang.org/pkg/encoding/json/#Marshaler) and [json.Unmarshaler](http://golang.org/pkg/encoding/json/#Unmarshaler) | ||
interfaces as well as helper functions such as `UnmarshalFeatureCollection`, `UnmarshalFeature` and `UnmarshalGeometry`. | ||
|
||
#### To install | ||
|
||
go get github.com/paulmach/go.geojson | ||
|
||
#### To use, imports as package name `geojson`: | ||
|
||
import "github.com/paulmach/go.geojson" | ||
|
||
<br /> | ||
[![Build Status](https://travis-ci.org/paulmach/go.geojson.png?branch=master)](https://travis-ci.org/paulmach/go.geojson) | ||
| ||
[![Coverage Status](https://coveralls.io/repos/paulmach/go.geojson/badge.png?branch=master)](https://coveralls.io/r/paulmach/go.geojson?branch=master) | ||
| ||
[![Godoc Reference](https://godoc.org/github.com/paulmach/go.geojson?status.png)](https://godoc.org/github.com/paulmach/go.geojson) | ||
|
||
## Examples | ||
|
||
* #### Unmarshalling (JSON -> Go) | ||
|
||
go.geojson supports both the [json.Marshaler](http://golang.org/pkg/encoding/json/#Marshaler) and [json.Unmarshaler](http://golang.org/pkg/encoding/json/#Unmarshaler) interfaces as well as helper functions such as `UnmarshalFeatureCollection`, `UnmarshalFeature` and `UnmarshalGeometry`. | ||
|
||
// Feature Collection | ||
rawFeatureJSON := []byte(` | ||
{ "type": "FeatureCollection", | ||
"features": [ | ||
{ "type": "Feature", | ||
"geometry": {"type": "Point", "coordinates": [102.0, 0.5]}, | ||
"properties": {"prop0": "value0"} | ||
} | ||
] | ||
}`) | ||
|
||
fc1, err := geojson.UnmarshalFeatureCollection(rawFeatureJSON) | ||
|
||
fc2 := geojson.NewFeatureCollection() | ||
err := json.Unmarshal(rawJSON, fc2) | ||
|
||
// Geometry | ||
rawGeometryJSON := []byte(`{"type": "Point", "coordinates": [102.0, 0.5]}`) | ||
g, err := geojson.UnmarshalGeometry(rawGeometryJSON) | ||
|
||
g.IsPoint() == true | ||
g.Point == []float64{102.0, 0.5} | ||
|
||
|
||
* #### Marshalling (Go -> JSON) | ||
|
||
g := geojson.NewPointGeometry([]float64{1, 2}) | ||
rawJSON, err := g.MarshalJSON() | ||
|
||
fc := geojson.NewFeatureCollection() | ||
fc.AddFeature(geojson.NewPointFeature([]float64{1,2})) | ||
rawJSON, err := fc.MarshalJSON() | ||
|
||
* #### Dealing with different Geometry types | ||
|
||
A geometry can be of several types, causing problems in a statically typed language. | ||
Thus there is a separate attribute on Geometry for each type. | ||
See the [Geometry object](https://godoc.org/github.com/paulmach/go.geojson#Geometry) for more details. | ||
|
||
g := UnmarshalGeometry([]byte(` | ||
{ | ||
"type": "LineString", | ||
"coordinates": [ | ||
[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0] | ||
] | ||
}`)) | ||
|
||
switch { | ||
case g.IsPoint(): | ||
// do something with g.Point | ||
case g.IsLineString(): | ||
// do something with g.LineString | ||
} | ||
|
||
## Feature Properties | ||
|
||
GeoJSON [Features](http://geojson.org/geojson-spec.html#feature-objects) can have properties of any type | ||
causing issues in a statically typed language such as Go. | ||
So, included are some helper methods on the Feature object to make the ease the pain. | ||
|
||
// functions to do the casting for you | ||
func (f Feature) PropertyBool(key string) (bool, error) { | ||
func (f Feature) PropertyInt(key string) (int, error) { | ||
func (f Feature) PropertyFloat64(key string) (float64, error) { | ||
func (f Feature) PropertyString(key string) (string, error) { | ||
|
||
// functions that hide the error and let you define default | ||
func (f Feature) PropertyMustBool(key string, def ...bool) bool { | ||
func (f Feature) PropertyMustInt(key string, def ...int) int { | ||
func (f Feature) PropertyMustFloat64(key string, def ...float64) float64 { | ||
func (f Feature) PropertyMustString(key string, def ...string) string { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package geojson | ||
|
||
import ( | ||
"encoding/json" | ||
) | ||
|
||
// A Feature corresponds to GeoJSON feature object | ||
type Feature struct { | ||
ID string `json:"id,omitempty"` | ||
Type string `json:"type"` | ||
BoundingBox []float64 `json:"bbox,omitempty"` | ||
Geometry *Geometry `json:"geometry"` | ||
Properties map[string]interface{} `json:"properties"` | ||
CRS map[string]interface{} `json:"crs,omitempty"` // Coordinate Reference System Objects are not currently supported | ||
} | ||
|
||
// NewFeature creates and initializes a GeoJSON feature given the required attributes. | ||
func NewFeature(geometry *Geometry) *Feature { | ||
return &Feature{ | ||
Type: "Feature", | ||
Geometry: geometry, | ||
Properties: make(map[string]interface{}), | ||
} | ||
} | ||
|
||
// NewPointFeature creates and initializes a GeoJSON feature with a point geometry using the given coordinate. | ||
func NewPointFeature(coordinate []float64) *Feature { | ||
return NewFeature(NewPointGeometry(coordinate)) | ||
} | ||
|
||
// NewMultiPointFeature creates and initializes a GeoJSON feature with a multi-point geometry using the given coordinates. | ||
func NewMultiPointFeature(coordinates ...[]float64) *Feature { | ||
return NewFeature(NewMultiPointGeometry(coordinates...)) | ||
} | ||
|
||
// NewLineStringFeature creates and initializes a GeoJSON feature with a line string geometry using the given coordinates. | ||
func NewLineStringFeature(coordinates [][]float64) *Feature { | ||
return NewFeature(NewLineStringGeometry(coordinates)) | ||
} | ||
|
||
// NewMultiLineStringFeature creates and initializes a GeoJSON feature with a multi-line string geometry using the given lines. | ||
func NewMultiLineStringFeature(lines ...[][]float64) *Feature { | ||
return NewFeature(NewMultiLineStringGeometry(lines...)) | ||
} | ||
|
||
// NewPolygonFeature creates and initializes a GeoJSON feature with a polygon geometry using the given polygon. | ||
func NewPolygonFeature(polygon [][][]float64) *Feature { | ||
return NewFeature(NewPolygonGeometry(polygon)) | ||
} | ||
|
||
// NewMultiPolygonFeature creates and initializes a GeoJSON feature with a multi-polygon geometry using the given polygons. | ||
func NewMultiPolygonFeature(polygons ...[][][]float64) *Feature { | ||
return NewFeature(NewMultiPolygonGeometry(polygons...)) | ||
} | ||
|
||
// NewCollectionFeature creates and initializes a GeoJSON feature with a geometry collection geometry using the given geometries. | ||
func NewCollectionFeature(geometries ...*Geometry) *Feature { | ||
return NewFeature(NewCollectionGeometry(geometries...)) | ||
} | ||
|
||
// MarshalJSON converts the feature object into the proper JSON. | ||
// It will handle the encoding of all the child geometries. | ||
// Alternately one can call json.Marshal(f) directly for the same result. | ||
func (f *Feature) MarshalJSON() ([]byte, error) { | ||
f.Type = "Feature" | ||
if len(f.Properties) == 0 { | ||
f.Properties = nil | ||
} | ||
|
||
return json.Marshal(*f) | ||
} | ||
|
||
// UnmarshalFeature decodes the data into a GeoJSON feature. | ||
// Alternately one can call json.Unmarshal(f) directly for the same result. | ||
func UnmarshalFeature(data []byte) (*Feature, error) { | ||
f := &Feature{} | ||
err := json.Unmarshal(data, f) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return f, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
Package go.geojson is a library for encoding and decoding GeoJSON into Go structs. | ||
Supports both the json.Marshaler and json.Unmarshaler interfaces as well as helper functions | ||
such as `UnmarshalFeatureCollection`, `UnmarshalFeature` and `UnmarshalGeometry`. | ||
*/ | ||
package geojson | ||
|
||
import ( | ||
"encoding/json" | ||
) | ||
|
||
// A FeatureCollection correlates to a GeoJSON feature collection. | ||
type FeatureCollection struct { | ||
Type string `json:"type"` | ||
BoundingBox []float64 `json:"bbox,omitempty"` | ||
Features []*Feature `json:"features"` | ||
CRS map[string]interface{} `json:"crs,omitempty"` // Coordinate Reference System Objects are not currently supported | ||
} | ||
|
||
// NewFeatureCollection creates and initializes a new feature collection. | ||
func NewFeatureCollection() *FeatureCollection { | ||
return &FeatureCollection{ | ||
Type: "FeatureCollection", | ||
Features: make([]*Feature, 0), | ||
} | ||
} | ||
|
||
// AddFeature appends a feature to the collection. | ||
func (fc *FeatureCollection) AddFeature(feature *Feature) *FeatureCollection { | ||
fc.Features = append(fc.Features, feature) | ||
return fc | ||
} | ||
|
||
// MarshalJSON converts the feature collection object into the proper JSON. | ||
// It will handle the encoding of all the child features and geometries. | ||
// Alternately one can call json.Marshal(fc) directly for the same result. | ||
func (fc *FeatureCollection) MarshalJSON() ([]byte, error) { | ||
fc.Type = "FeatureCollection" | ||
if fc.Features == nil { | ||
fc.Features = make([]*Feature, 0) // GeoJSON requires the feature attribute to be at least [] | ||
} | ||
return json.Marshal(*fc) | ||
} | ||
|
||
// UnmarshalFeatureCollection decodes the data into a GeoJSON feature collection. | ||
// Alternately one can call json.Unmarshal(fc) directly for the same result. | ||
func UnmarshalFeatureCollection(data []byte) (*FeatureCollection, error) { | ||
fc := &FeatureCollection{} | ||
err := json.Unmarshal(data, fc) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return fc, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package geojson | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
) | ||
|
||
func TestNewFeatureCollection(t *testing.T) { | ||
fc := NewFeatureCollection() | ||
|
||
if fc.Type != "FeatureCollection" { | ||
t.Errorf("should have type of FeatureCollection, got %v", fc.Type) | ||
} | ||
} | ||
|
||
func TestUnmarshalFeatureCollection(t *testing.T) { | ||
rawJSON := ` | ||
{ "type": "FeatureCollection", | ||
"features": [ | ||
{ "type": "Feature", | ||
"geometry": {"type": "Point", "coordinates": [102.0, 0.5]}, | ||
"properties": {"prop0": "value0"} | ||
}, | ||
{ "type": "Feature", | ||
"geometry": { | ||
"type": "LineString", | ||
"coordinates": [ | ||
[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0] | ||
] | ||
}, | ||
"properties": { | ||
"prop0": "value0", | ||
"prop1": 0.0 | ||
} | ||
}, | ||
{ "type": "Feature", | ||
"geometry": { | ||
"type": "Polygon", | ||
"coordinates": [ | ||
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], | ||
[100.0, 1.0], [100.0, 0.0] ] | ||
] | ||
}, | ||
"properties": { | ||
"prop0": "value0", | ||
"prop1": {"this": "that"} | ||
} | ||
} | ||
] | ||
}` | ||
|
||
fc, err := UnmarshalFeatureCollection([]byte(rawJSON)) | ||
if err != nil { | ||
t.Fatalf("should unmarshal feature collection without issue, err %v", err) | ||
} | ||
|
||
if fc.Type != "FeatureCollection" { | ||
t.Errorf("should have type of FeatureCollection, got %v", fc.Type) | ||
} | ||
|
||
if len(fc.Features) != 3 { | ||
t.Errorf("should have 3 features but got %d", len(fc.Features)) | ||
} | ||
} | ||
|
||
func TestFeatureCollectionMarshalJSON(t *testing.T) { | ||
fc := NewFeatureCollection() | ||
blob, err := fc.MarshalJSON() | ||
|
||
if err != nil { | ||
t.Fatalf("should marshal to json just fine but got %v", err) | ||
} | ||
|
||
if !bytes.Contains(blob, []byte(`"features":[]`)) { | ||
t.Errorf("json should set features object to at least empty array") | ||
} | ||
} |
Oops, something went wrong.