Hands On

How to Work with GeoJSON Data in Golang for HERE XYZ

By Nic Raboy | 04 June 2019

Since I’m personally becoming more familiar with HERE XYZ, I’ve been learning about all the bits and pieces that go with it, and that includes data formats such as GeoJSON. In a previous tutorial titled, Format Data into GeoJSON with JavaScript to be used with HERE XYZ, I demonstrated how to work with GeoJSON data in JavaScript. However, I’m a huge fan of the Go programming language so I figured it would be awesome to try to replicate what I did with Golang.

We’re not going to work directly with HERE XYZ in this example. We’re just going to get our data ready to be sent to HERE XYZ or received from it. I have other tutorials where we make HTTP requests to the HERE XYZ APIs using Golang.

Before we create a project, execute the following from the command line:

go get github.com/paulmach/go.geojson

The above command will get the community supported go.geojson package for use in our project.

Within your $GOPATH, create a new project with a main.go file. In that main.go file, include the following boilerplate code:

package main

import (
    "fmt"

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

type Position struct {}
type XYZData struct {}

func NewGeoJSON(position Position, tags []string) ([]byte, error) {}
func main() {}

You’ll notice that we have two data structures and two functions, one of which is our main function. Under normal circumstances, using the pure GeoJSON package would be sufficient, but we’re going to create our own helper function to work with HERE XYZ.

Essentially HERE XYZ allows tagging which is useful when issuing search queries. You could, for example, create a tag for a date and then return results that only match that tag. This doesn’t break the GeoJSON specification, but it does mean we need to include certain things.

Let’s first create our Position data structure:

type Position struct {
    Latitude  float64 `json:"lat"`
    Longitude float64 `json:"lng"`
}

As you guessed, we have a latitude and longitude property to work with instead of a plain floating point slice. The XYZData data structure will look like the following:

type XYZData struct {
    Tags []string `json:"tags"`
}

With those two data structures in place, we can start constructing our GeoJSON feature collection. We’re going to create our full feature collection in the NewGeoJSON function and return a slice of bytes which could later be sent to HERE XYZ.

func NewGeoJSON(position Position, tags []string) ([]byte, error) {
    featureCollection := geojson.NewFeatureCollection()
    feature := geojson.NewPointFeature([]float64{position.Longitude, position.Latitude})
    feature.SetProperty("@ns:com:here:xyz", XYZData{Tags: tags})
    featureCollection.AddFeature(feature)
    return featureCollection.MarshalJSON()
}

In the above function we are accepting a position of latitude and longitude coordinates as well as any number of tags to be stored.

After creating a new feature for the collection we are adding a property to that feature. The property has a specific key and it is an object. We want our final output to look something like this:

{
    "type": "FeatureCollection",
    "features": [
        { 
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [-121,37]
            },
            "properties": {
                "@ns:com:here:xyz": {
                    "tags": ["foo","bar"]
                }
            }
        }
    ]
}

We can make use of this NewGeoJSON function in the main function. Take the following for example to reproduce the above output:

func main() {
    g, _ := NewGeoJSON(Position{37, -121}, []string{"foo", "bar"})
    fmt.Println(string(g))
}

Not so bad right?

GeoJSON can be a lot more complex, but this is just a basic example, something that was valuable for one of my own projects. In my example I was collecting latitude and longitude positions and needed to send it to HERE XYZ. So I took the data I had and converted it to GeoJSON format.

Conclusion

You just saw how to work with GeoJSON data in Golang. While the go.geojson package for Golang makes it easy in general, we wanted to make some changes that better accommodate working with HERE XYZ.

To learn more about working with location data in Golang, check out my previous tutorial titled, Reverse Geocoding NEO 6M GPS Positions with Golang and a Serial UART Connection.