Friday, 6 March 2020

MapGuide tidbits: An unconventional way to bulk convert features to GeoJSON

Recently in my regular day job I had a spatial data processing task that needed to be carried out in a timely manner.

I needed the current Australian Federal Electorates, which come from the AEC in the form of a single SHP file or MapInfo TAB file and I needed this dataset split up so that each of the 151 federal electorates existed as separate GeoJSON files named based on some combination of attributes in each feature.

After deliberating on possible solutions (I absolutely did not want to have to write a throwaway program that uses GDAL/OGR or FDO to do this conversion unless there was no other choice!), I came up with a somewhat unconventional solution using mapguide-rest and its data publishing feature that I've decided to share in this particular post. Here's what I did.

First, I loaded the electorates SHP file into the MapGuide Server via Maestro. The feature source can be either connected to the SHP file loaded into the resource data files or connect to an external SHP path or aliased path. It ultimately doesn't matter and it's up to you how you prefer to manage your SHP feature sources.

This MapGuide installation already has mapguide-rest installed, so I use the REST Explorer in Maestro to connect to it. Once connected, I proceeded to create 2 data configurations.

The first one is a CSV representation of the SHP feature source, that returns the identity and a computed expression of my desired output file name.

The resulting REST configuration looks like this:

We then set up a 2nd REST configuration to provide a GeoJSON representation of our electorates.

Whose REST configuration looks like this

With these 2 rest configs set up, we now have new URLs available to us to access the electorates in our desired representations. In relation to what I want to achieve, the URLs of interest are:

GET http://servername/mapguide/rest/data/electorateinfo/.csv

To get the id and desired filename of all electorates in a CSV, whose content looks like this:

The other URL is:

GET http://servername/mapguide/rest/data/electorate/{id}.geojson

To get the individual electorate feature by id in GeoJSON format.

With these 2 URLs, we now just need to write a simple script that:
  1. Downloads the CSV of all electorates
  2. Loops through each line in the CSV (except header) to request a GeoJSON download of the electorate for the given id and download it as the requested file name.
Which can be done with a Powershell script like this:

$csvFile = [System.IO.Path]::GetTempFileName();
$workingDirectory = Convert-Path (Resolve-Path -path ".")
$outDir = "$workingDirectory\electorates_geojson"
New-Item -ItemType Directory -Force -Path $outDir
Invoke-WebRequest -Uri "http://localhost/mapguide/rest/data/electorateinfo/.csv" -OutFile $csvFile
$electorates = Import-Csv $csvFile
foreach ($elec in $electorates) {
    $id = $elec.FeatId;
    $fileName = $elec.filename + ".geojson";
    $outPath = [System.IO.Path]::Combine($outDir, $fileName);
    Invoke-WebRequest -Uri "http://localhost/mapguide/rest/data/electorate/$id.geojson" -OutFile $outPath
    Write-Host "Saved electorate ($id) to: $outPath"

Run the script, and a minute or 2 later, all 151 electorate boundary features have been split off and converted into individual GeoJSON files!

I hope this post is as useful to you as it was for me.

No comments: