Encoding and decoding GeoJSON <-> Go

go.geojson

Go.geojson is a package for encoding and decoding GeoJSON into Go structs. Supports both the json.Marshaler and json.Unmarshaler interfaces as well as sql.Scanner for directly scanning PostGIS query results. The package also provides helper functions such as UnmarshalFeatureCollection, UnmarshalFeature and UnmarshalGeometry.

Important

This package is best for lightweight interaction with GeoJSON. If you want to actually do stuff with the geometry take a look at orb/geojson which decodes the geometries into orb types which you can do all sorts of things with.

To install

go get github.com/paulmach/go.geojson

To use, imports as package name geojson:

import "github.com/paulmach/go.geojson"

Build Status Godoc Reference

Examples

  • Unmarshalling (JSON -> Go)

    go.geojson supports both the json.Marshaler and 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()
    
  • Scanning PostGIS query results

      row := db.QueryRow("SELECT ST_AsGeoJSON(the_geom) FROM postgis_table)
    
      var geometry *geojson.Geometry
      row.Scan(&geometry)
    
  • 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 for more details.

      g := geojson.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 can have properties of any type. This can cause issues in a statically typed language such as Go. So, included are some helper methods on the Feature object to 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 {
Comments
  • Fix JSON int ID handling

    Fix JSON int ID handling

    Parsin JSON like { "type" : "Feature", "id" : 137, ... } fails currently ESRI ArcGIS REST seems to create this kind of GeoJSON.

  • Feature.ID -> interface{}

    Feature.ID -> interface{}

    This fixes an issue brought up by @mikhailswift, @colek42 and @nlacey on https://github.com/paulmach/go.geojson/pull/4 (thank you).

    An ID can be either a string or a number. In order to support both marshalling and unmarshalling of those types changing ID to a generic interface type.

    The user will then need to call something like f.ID.(float64) or f.ID.(string) to get the value they need. This is consistent with how feature properties are handled.

  • MarshalJSON is now picked by json.Marshal when provided with a value

    MarshalJSON is now picked by json.Marshal when provided with a value

    All it took was changing the signature from (x *Type) to (x Type). Added json.Mashal test for both *Type and Type.

    This required (current entered infinite loop) to rewrite feature & feature_collection MarshalJSON. It now mirrors geometry’s implementation (doesn’t mutate caller).

    Made the tests more stringent.

    Signed-off-by: Frédéric Miserey [email protected]

  • Geometry from WKT

    Geometry from WKT

    Hi @paulmach

    Great library, i use it quite a bit and it works great. I have a question, let's say I have a bunch of records in WKT (some points, poly, lines, etc) and I would like build a geojson out of them.

    What would you say is the best way to extract the geometry from WKT in a way that this library will easily understand it? Do you have a recommendation?

    Thanks again!

    Jose

  • Struct to contain feature collection and other custom data

    Struct to contain feature collection and other custom data

    Hello,

    go.geojson is functional for me, however I'd like to add additional custom JSON data to the output, seperate from the FeatureCollection. I have both geojson and event data (for the locations) successfully outputting via REST API as two different routes. However I'd like to combine them so that the JSON has two main children: a 'FeatureCollection' and 'Events' containing my custom events data.

    My first approach has been to create a new struct to encapsulate them both, like so:

    // GeoLocationsEvents type
    type GeoLocationsEvents struct {
    	Locations FeatureCollection `schema:"locations"`
    	Events []Event `schema:"events"`
    }
    

    However I get a type incompatibility error when it comes time to make use of the fc object that go.geojson is outputting.

    This is my router function:

    func (a *App) getLocationsEventsGeoJSON(w http.ResponseWriter, r *http.Request) {
    
     // This successfully returns a complete FeatureCollection (using go.geojson) and a complete Events object.
        fc, events, err := getLocationsEvents(a.DB, start, count)
        if err != nil {
            respondWithError(w, http.StatusInternalServerError, err.Error())
            return
        }
    
    
    // Now, I attempt to merge the two using my new struct.
    // My intention is to pass it to a final function which marshals the json.
    	var locationsEvents GeoLocationsEvents
    
    // THIS CAUSES AN ERROR: cannot use fc (type *geojson.FeatureCollection) as type *FeatureCollection in assignment
    	locationsEvents.Locations = fc
    	locationsEvents.Events = events
    
          // The final function call before outputting to client. If I test with fc or events directly, they both work spitting JSON to the browser. However I want them to be combined.
           respondWithGeoJSON(w, http.StatusOK, locationsEvents)
    }
    
    func getLocationsEvents(db *sql.DB, start, count int) ([]Location, []Event, *geojson.FeatureCollection, error) {
    
    	var events = []Event{}
    	elements := map[int]int{}
    	fc := geojson.NewFeatureCollection()
    
    // and much more... excluded from post
    
    }
    
  • Allow creation of copies of Geometries, rather than references

    Allow creation of copies of Geometries, rather than references

    It would be really nice if one could easily create a copy of a Geometry without having to worry about any references. I see two ways to achieve this, either by modifying the constructors for new Geometries or by adding a Copy() method.

    Currently NewPolygonGeometry for example takes the polygon [][][]float64 and simply uses it. However that means if something modifies the passed polygon it will also modify the geometry.

    For the reason I'd suggest to either create a copy using something like this whenever a new polygon is created

    cp := make([][][]float64, len(polygon))
    copy(cp, polygon)
    

    An alternative would be to explicitly create a new copy of a geometry using a method in the form of func (g *Geometry) Copy() *Geometry (or Clone) returning an exact copy, with now more references to the original.

    The second option would I think would both be cleaner as well as allowing people to choose whether they really want to allocate a new slice.

  • Build fails with

    Build fails with "cannot find package"

    I am trying to build go.geojson and I'm getting the following:

    example_test.go:6:2: cannot find package "git.tech.rz.db.de/streckenkunde40/thirdparty/github/paulmach/go.geojson" in any of:
    	D:\Tools\Go\src\git.tech.rz.db.de\streckenkunde40\thirdparty\github\paulmach\go.geojson (from $GOROOT)
    	D:\Users\BKU\AlexeyValikov\go\src\git.tech.rz.db.de\streckenkunde40\thirdparty\github\paulmach\go.geojson (from $GOPATH)
    

    Any hint how to deal with it?

  • Please tag latest version as 1.4.0

    Please tag latest version as 1.4.0

    Unfortunately go is strict regarding semver. I just did a go get on this package and then checked your releases. A plain go get downloaded v1.3.1 as it's the latest semver compliant tag (vn.n.n), and ignored v1.4 due to the missing last digit. v1.4 should be tagged as v1.4.0 for go 1.11+ with module support to work.

    See https://github.com/golang/go/issues/24476 for some comments where it doesn't appear that this will change, in particular:

    This should be fixed. I think vgo should just completely ignore non-canonical semver tags (v1 or v1.0 instead of v1.0.0) in repos.
    
  • Added a BoundingBox retrieval method to feature

    Added a BoundingBox retrieval method to feature

    Hello!

    I added a Get_Boundingbox() method to the Feature structure. I realize this is sort of maybe a little out of the projects scope comparing with the other methods, but only slightly, and I would find it incredibly useful.

    You may ask why mutate the BoundingBox at the feature level? When at the geometry level Get_BoundingBox() returns a BoundingBox ([]float64) rather than mutate the Geometry, this is because if you change both you have the same bounding box in two places which isn't cool for serialization to text, and I thought it would be more useful at the top level of a feature rather than within a geometry (although one could argue it makes more sense there).

  • Add implementation driver Value interface

    Add implementation driver Value interface

    Implementation driver.Value interface for correct writing Geometry type into DB. When using PostGIS a spatial column would need to be wrapped in ST_GeomFromGeoJSON.

  • Required tag 'properties' Marshalled to 'null'

    Required tag 'properties' Marshalled to 'null'

    It's an interesting issue which I faced with the Feature.Properties json tag.

    Properties  map[string]interface{} `json:"properties"
    

    We're storing the GeoJSON as JSONB into postgres and when the following RawJSON was unmarshalled, it'd be 'null' for properties tag RawJSON:

                        {
                            "geometry": {
                                "coordinates": [
                                    14,
                                    12
                                ],
                                "type": "Point"
                            },
                            "type": "Feature",
                            "properties": {}
                        }
    

    Unmarshalled to

    { "geometry": {"type": "Point", "coordinates": [14, 12]}, "properties": null}]}
    

    which is a invalid GeoJSON format.

Package polyline implements a Google Maps Encoding Polyline encoder and decoder.

go-polyline Package polyline implements a Google Maps Encoding Polyline encoder and decoder. Encoding example func ExampleEncodeCoords() { coords :=

Dec 1, 2022
Package kml provides convenince methods for creating and writing KML documents.

go-kml Package kml provides convenience methods for creating and writing KML documents. Key Features Simple API for building arbitrarily complex KML d

Jul 29, 2022
Types and utilities for working with 2d geometry in Golang

orb Package orb defines a set of types for working with 2d geo and planar/projected geometric data in Golang. There are a set of sub-packages that use

Dec 28, 2022
General purpose library for reading, writing and working with OpenStreetMap data

osm This package is a general purpose library for reading, writing and working with OpenStreetMap data in Go (golang). It has the ability to read OSM

Dec 30, 2022
Publish Your GIS Data(Vector Data) to PostGIS and Geoserver
Publish Your GIS Data(Vector Data) to PostGIS and Geoserver

GISManager Publish Your GIS Data(Vector Data) to PostGIS and Geoserver How to install: go get -v github.com/hishamkaram/gismanager Usage: testdata fol

Sep 26, 2022
Real-time Geospatial and Geofencing
Real-time Geospatial and Geofencing

Tile38 is an open source (MIT licensed), in-memory geolocation data store, spatial index, and realtime geofence. It supports a variety of object types

Dec 30, 2022
A library provides spatial data and geometric algorithms

Geoos Our organization spatial-go is officially established! The first open source project Geoos(Using Golang) provides spatial data and geometric alg

Dec 27, 2022
go-eexcel implements encoding and decoding of XLSX like encoding/json

go-eexcel go-eexcel implements encoding and decoding of XLSX like encoding/json Usage func ExampleMarshal() { type st struct { Name string `eexce

Dec 9, 2021
Go structure annotations that supports encoding and decoding; similar to C-style bitfields. Supports bitfield packing, self-describing layout parameters, and alignment.
Go structure annotations that supports encoding and decoding; similar to C-style bitfields. Supports bitfield packing, self-describing layout parameters, and alignment.

STRUCTure EXtensions structex provides annotation rules that extend Go structures for implementation of encoding and decoding of byte backed data fram

Oct 13, 2022
A simple, semantic and developer-friendly golang package for encoding&decoding and encryption&decryption

A simple, semantic and developer-friendly golang package for encoding&decoding and encryption&decryption

Jan 4, 2023
Some Golang types based on builtin. Implements interfaces Value / Scan and MarshalJSON / UnmarshalJSON for simple working with database NULL-values and Base64 encoding / decoding.

gotypes Some simple types based on builtin Golang types that implement interfaces for working with DB (Scan / Value) and JSON (Marshal / Unmarshal). N

Feb 12, 2022
? ID3 decoding and encoding library for Go

id3v2 Supported ID3 versions: 2.3, 2.4 Installation go get -u github.com/bogem/id3v2 Usage example package main import ( "fmt" "log" "github.com

Dec 31, 2022
Go package for decoding and encoding TARGA image format

tga tga is a Go package for decoding and encoding TARGA image format. It supports RLE and raw TARGA images with 8/15/16/24/32 bits per pixel, monochro

Sep 26, 2022
Encoding and decoding for fixed-width formatted data

fixedwidth Package fixedwidth provides encoding and decoding for fixed-width formatted Data. go get github.com/ianlopshire/go-fixedwidth Usage Struct

Dec 16, 2022
Go package containing implementations of efficient encoding, decoding, and validation APIs.

encoding Go package containing implementations of encoders and decoders for various data formats. Motivation At Segment, we do a lot of marshaling and

Dec 25, 2022
MIME mail encoding and decoding package for Go

enmime enmime is a MIME encoding and decoding library for Go, focused on generating and parsing MIME encoded emails. It is being developed in tandem w

Nov 30, 2022
Package json implements encoding and decoding of JSON as defined in RFC 7159

Package json implements encoding and decoding of JSON as defined in RFC 7159. The mapping between JSON and Go values is described in the documentation for the Marshal and Unmarshal functions

Jun 26, 2022
encLib is a simple golang package for quickly encoding and decoding string data in hex

encLib is a simple golang package for quickly encoding and decoding string data in hex

Nov 1, 2021
json encoding and decoding

jx Package jx implements encoding and decoding of json [RFC 7159]. Lightweight fork of jsoniter. go get github.com/go-faster/jx Usage and examples Roa

Dec 27, 2022
A Form Encoding & Decoding Package for Go

form A Form Encoding & Decoding Package for Go, written by Alvaro J. Genial. Synopsis This library is designed to allow seamless, high-fidelity encodi

Nov 23, 2022