GPXIN-20: Implement support for extensions



Issue Information

Issue Type: New Feature
 
Priority: Major
Status: Open

Reported By:
Ben Tasker
Assigned To:
Ben Tasker
Project: PHP GPXIngest (GPXIN)
Resolution: Unresolved
Affects Version: 1.03,
Target version: 1.03,

Created: 2015-08-09 00:47:19
Time Spent Working


Description
Depending on the system used to generate the GPX file, speed may be listed under an extension, as below (from GPXIN-19)

  <trk>
    <trkseg>
      <trkpt lat=3D"11.543009877" lon=3D"-85.697211027">
        <ele>55.0</ele>
        <time>2015-07-25T12:02:02.989Z</time>
        <extensions>
          <nmea:course>11.6</nmea:course>
          <nmea:speed>1.7</nmea:speed>
        </extensions>
      </trkpt>


There's no way to know for sure what extension the data we need will be listed under, so will need to add a method so that the class can be told what to look for (and perhaps set some known defaults too?)


Issue Links

GPX Schema Documentation
Toggle State Changes

Activity


As there's no explicit namespace for extensions (http://www.topografix.com/GPX/1/1/#type_extensionsType) , there isn't a schema that can be used for a one-size-fits-all solution.

I think the first thing I'd like to do is to at least get the extensions data into the object's output, then look at ways in which developers can tell the class to use those extensions.

Taking the example above, it'd be good to be able to do something similar to the following
<?php
require 'GPXIngest.class.php';

$gpx = new GPXIngest();
$gpx->useExtension('nmea_speed','speed'); // Tell the class to use extensions->nmea:speed as the speed field
$gpx->loadFile('test.gpx');
$gpx->ingest();
echo $json = $gpx->getJSON();

But, if we can at least get the extensions written into the JSON first, there'll at least be a way to grab the raw data.

We'll need to read in the namespace URL from the GPX file for SimpleXML to be able to access the relevant elements though.

That aside, dropping the following in seems to work OK
foreach ($trkpt->extensions->children('http://trekbuddy.net/2009/01/gpx/nmea') as $t){
echo $t->getName()."-".$t."\n";
}
/* The above outputs
course-11.6
speed-1.7
*/

So should just be a case of getting the class to look for namespaces in the GPX file, cycle through those and then add values for each of the extensions to an array or object.
OK, the basic implementation is there, the namespaces present in the GPX file are written into the object under created->namespaces and then any relevant extension data is written into each of the trackpoints.

Each of the namespaces is it's own array, so the seperation is maintained.

Not sure if I like the implementation yet, but it is at least functional.

Repo: PHP-GPX-Ingest
Commit: 302545f7fe9d13553ec39746037cc2127fd72713
Author: Ben Tasker <github@<Domain Hidden>>

Date: Tue Aug 11 00:39:24 2015 +0100
Commit Message: Started implementing support for GPX Extensions. See GPXIN-20



Modified (-)(+)
-------
GPXIngest.class.php




Webhook User-Agent

GitHub-Hookshot/29237e4


View Commit

Added a new utility function to list the namespaces used:
$gpx->getGPXNameSpaces();

Repo: PHP-GPX-Ingest
Commit: 8a3da3a4f7543a74642d7fd9489a1827005607bf
Author: Ben Tasker <github@<Domain Hidden>>

Date: Tue Aug 11 00:49:08 2015 +0100
Commit Message: Added utility function to list namespaces. See GPXIN-20



Modified (-)(+)
-------
GPXIngest.class.php




Webhook User-Agent

GitHub-Hookshot/29237e4


View Commit

For mapping certain fields to extensions, I think the best bet is to have the field name (including the namespace) passed through, with the name of a field to map to passed through. For example, assuming the XML declaration is
<?xml version='1.0' encoding='ISO-8859-1' ?>
<gpx version="1.1" creator="TrekBuddy 1.30" xmlns="http://www.topografix.com/GPX/1/1" xmlns:nmea="http://trekbuddy.net/2009/01/gpx/nmea">

We'd call something like
$gpx->mapExtensionField('nmea:speed','speed');

To create a mapping.

It means adding additional complexity to ingest though, and that method is already overly complex to read through. Might need to look at breaking the processing logic for this out into another function. Also need to work out the best failure scenario, if I've used the example above but the trackpoint XML is
<trkpt lat=3D"11.543009877" lon=3D"-85.697211027">
        <ele>55.0</ele>
        <time>2015-07-25T12:02:02.989Z</time>
        <desc>1.7</desc>
        <extensions>
          <nmea:course>11.6</nmea:course>
        </extensions>
      </trkpt>

Do we fall back to using desc (the default), ignore or throw an exception?

Will need to give it some more thought before doing much more.
I think my preferred solution is to create a new method to be called whilst processing the ingest (on or around https://github.com/bentasker/PHP-GPX-Ingest/blob/8a3da3a4f7543a74642d7fd9489a1827005607bf/GPXIngest.class.php#L330 ) to dictate which field should be used as the speed.

The existing calculations around https://github.com/bentasker/PHP-GPX-Ingest/blob/8a3da3a4f7543a74642d7fd9489a1827005607bf/GPXIngest.class.php#L276 will need to be moved/removed.

The idea being that the method should return two values which will be pushed into ptspeed and speed_string

Any direct references to trkpt->desc will need to be replaced with speed_string

The auto-calculation logic introduced in 05af1e8 (View Commit) can largely stay unchanged - if the field used is empty (or doesn't exist) the class can then autocalc the speed based on position data.

That way the new chunk of logic can go into a new method (avoiding adding extra length to ingest itself) and the decision as to where the values of ptspeed and speed_string can be centralised to one location.

The decision as to whether to automatically suppress speed (https://github.com/bentasker/PHP-GPX-Ingest/blob/8a3da3a4f7543a74642d7fd9489a1827005607bf/GPXIngest.class.php#L282) will likely need to move though.

Haven't got time to start implementing the changes right now, so largely noting the plans down for when I have a minute free.