Skip Menu |

This queue is for tickets about the Geo-Gpx CPAN distribution.

Report information
The Basics
Id: 29909
Status: resolved
Worked: 30 min
Priority: 0/
Queue: Geo-Gpx

People
Owner: andy [...] hexten.net
Requestors: gyles19 [...] visi.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in:
  • 0.15
  • 0.18
Fixed in: (no value)



Subject: Garmin POILoader rejects Geo::Gpx files as invalid. Hack-fix attached.
I've found that while EasyGPX can read Geo::Gpx's xml okay, Garmin's POILoader rejects it as invalid. I tried running several online XML Validators against both Geo::Gpx'x xml, and EasyGPX's xml, and they are both invalid against the GPX 1.1 and 1.0 DTDs. I didn't investigate how EasyGPX's files are invalid since POILoader accepts them, so I concentrated on Geo::Gpx. I have found that the basic problem is that Geo::Gpx is not following the xml sequence specified in the GPX specification. I subclassed Geo::Gpx and overrode the xml method with a decorator that re-parses the output string and re-orders the <wpt> elements into the correct order. POILoader accepts this file and the custom POIs now show up fine in my StreetPilot c330. Here's the validator I used, and the GPX schema I found success with: http://tools.decisionsoft.com/schemaValidate/ http://www.topografix.com/GPX/1/1/gpx.xsd The basic problem within Geo::Gpx is that it's using a 'sort keys...' ordering for processing the waypoint elements in the generic token handler. It should probably have at least a specific handler for the wpt type to preserve the order in the specification. I suspect the route and track specifications are also ordered, but I didn't look at them. Here's the guts of the change in my hack: my @correct_order = ( 'ele','time','magvar','geoidheight', 'name', 'cmt','desc','src','link','sym', 'type','fix','sat','hdop','vdio', 'pdop','ageofdgpsdata','dgpsid','extensions'); $result .= sprintf "<wpt lat=\"%s\" lon=\"%s\">\n", $attr->{lat},$attr->{lon}; foreach my $key (@correct_order) { $result .= "<$key>" . &Geo::Gpx::_enc( $wpt->{$key}) . "</$key>\n" if defined $wpt->{$key}; } $result .= "</wpt>\n"; Since the StreetPilot c330 doesn't support either routes or tracks, the hack I have isn't suitable for public consumption. In fact, it's an ugly thing I threw together to see if the ordering was the only problem POILoader had with the xml... but it works for me for files which contain only waypoints. The proper fix is to provide a better handler for the wpt elements. I've attached my subclass hack for your amusement. I've also attached a sample gpx file generated with it and which POILoader processes successfully. I would suggest that Geo::Gpx would be much more valuable if the xml it produces is compatible with POILoader and other xml-based tools without having to be reparsed and rewritten by other applications like EasyGPS first, which is a manual process on windows. I'm presently running perl 5.8.8 on an old Red Hat 7.3 linux laptop.
Subject: GUITruckstops.gpx
Download GUITruckstops.gpx
application/octet-stream 2.6k

Message body not shown because it is not plain text.

Subject: Gpx.pm
$Trucker::Gpx::VERSION = sprintf "%d.%03d", q$Revision: 1.1 $ =~ /(\d+)/g; package Trucker::Gpx; use base Geo::Gpx; use HTML::Entities qw(encode_entities encode_entities_numeric); use XML::Descent; sub xml { my $self = shift; my $xml = $self->SUPER::xml(@_); my ($header) = ($xml =~ /^(.+?)<metadata>/s); my $result = ""; $result .= $header; my $p = XML::Descent->new({ Input => \$xml, Namespaces => 0 }); $p->on('gpx' => # gpx handler sub { my ($elem, $attr, $ctx) = @_; $p->on('*' => # everything else handler sub { my ($elem, $attr, $ctx) = @_; $result .= "<$elem>" . $p->xml . "</$elem>\n"; } ); $p->on('wpt' => # waypoint handler within gpx handler sub { my ($elem, $attr, $ctx) = @_; my $wpt = {}; $p->context($wpt); $p->on( '*' => sub { my ($elem, $attr, $ctx) = @_; my $text = $p->text; $ctx->{$elem}=$text; $ctx->{attribs} = $attr; } ); $p->walk; my @correct_order = ( 'ele','time','magvar','geoidheight', 'name', 'cmt','desc','src','link','sym', 'type','fix','sat','hdop','vdio', 'pdop','ageofdgpsdata','dgpsid','extensions'); $result .= sprintf "<wpt lat=\"%s\" lon=\"%s\">\n", $attr->{lat},$attr->{lon}; foreach my $key (@correct_order) { $result .= "<$key>" . &Geo::Gpx::_enc( $wpt->{$key}) . "</$key>\n" if defined $wpt->{$key}; } $result .= "</wpt>\n"; } ); # end of waypoint handler $p->walk; } ); $p->walk; $result .= "</gpx>\n"; return $result; }
Thanks! I've just released 0.19 which should fix the problem :)