Updates courtesy of Gaku Ueda:
* Adding support for GPX 1.0 as well as 1.1 (since libxml namespace parsing was hard-coded to 1.1. previously). * Adding a GPX 1.0 unit test file. * Miscellaneous updates to make it work with Ruby 1.8.6.master
parent
022c7c6813
commit
5aa64f2c3a
|
@ -28,7 +28,6 @@ module GPX
|
||||||
class Base
|
class Base
|
||||||
include XML
|
include XML
|
||||||
|
|
||||||
NS = 'gpx:http://www.topografix.com/GPX/1/1'
|
|
||||||
# This initializer can take an XML::Node and scrape out any text
|
# This initializer can take an XML::Node and scrape out any text
|
||||||
# elements with the names given in the "text_elements" array. Each
|
# elements with the names given in the "text_elements" array. Each
|
||||||
# element found underneath "parent" with a name in "text_elements" causes
|
# element found underneath "parent" with a name in "text_elements" causes
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#++
|
#++
|
||||||
module GPX
|
module GPX
|
||||||
class GPXFile < Base
|
class GPXFile < Base
|
||||||
attr_reader :tracks, :routes, :waypoints, :bounds, :lowest_point, :highest_point, :distance, :duration, :average_speed
|
attr_reader :tracks, :routes, :waypoints, :bounds, :lowest_point, :highest_point, :distance, :duration, :average_speed, :ns
|
||||||
|
|
||||||
|
|
||||||
# This initializer can be used to create a new GPXFile from an existing
|
# This initializer can be used to create a new GPXFile from an existing
|
||||||
|
@ -50,9 +50,16 @@ module GPX
|
||||||
#end
|
#end
|
||||||
gpx_file = gpx_file.name if gpx_file.is_a?(File)
|
gpx_file = gpx_file.name if gpx_file.is_a?(File)
|
||||||
reset_meta_data
|
reset_meta_data
|
||||||
@xml = Document.file(gpx_file)
|
@xml = XML::Document.file(gpx_file)
|
||||||
|
|
||||||
bounds_element = (@xml.find("//gpx:gpx/gpx:metadata/gpx:bounds", NS).to_a.first rescue nil)
|
# set XML namespace for XML find
|
||||||
|
if @xml.root.namespace_node
|
||||||
|
@ns = 'gpx:' + @xml.root.namespace_node.href
|
||||||
|
else
|
||||||
|
@ns = 'gpx:http://www.topografix.com/GPX/1/1' # default to GPX 1.1
|
||||||
|
end
|
||||||
|
|
||||||
|
bounds_element = (@xml.find("//gpx:gpx/gpx:metadata/gpx:bounds", @ns).to_a.first rescue nil)
|
||||||
if bounds_element
|
if bounds_element
|
||||||
@bounds.min_lat = get_bounds_attr_value(bounds_element, %w{ min_lat minlat minLat })
|
@bounds.min_lat = get_bounds_attr_value(bounds_element, %w{ min_lat minlat minLat })
|
||||||
@bounds.min_lon = get_bounds_attr_value(bounds_element, %w{ min_lon minlon minLon})
|
@bounds.min_lon = get_bounds_attr_value(bounds_element, %w{ min_lon minlon minLon})
|
||||||
|
@ -63,15 +70,15 @@ module GPX
|
||||||
end
|
end
|
||||||
|
|
||||||
@tracks = []
|
@tracks = []
|
||||||
@xml.find("//gpx:gpx/gpx:trk", NS).each do |trk|
|
@xml.find("//gpx:gpx/gpx:trk", @ns).each do |trk|
|
||||||
trk = Track.new(:element => trk, :gpx_file => self)
|
trk = Track.new(:element => trk, :gpx_file => self)
|
||||||
update_meta_data(trk, get_bounds)
|
update_meta_data(trk, get_bounds)
|
||||||
@tracks << trk
|
@tracks << trk
|
||||||
end
|
end
|
||||||
@waypoints = []
|
@waypoints = []
|
||||||
@xml.find("//gpx:gpx/gpx:wpt", NS).each { |wpt| @waypoints << Waypoint.new(:element => wpt, :gpx_file => self) }
|
@xml.find("//gpx:gpx/gpx:wpt", @ns).each { |wpt| @waypoints << Waypoint.new(:element => wpt, :gpx_file => self) }
|
||||||
@routes = []
|
@routes = []
|
||||||
@xml.find("//gpx:gpx/gpx:rte", NS).each { |rte| @routes << Route.new(:element => rte, :gpx_file => self) }
|
@xml.find("//gpx:gpx/gpx:rte", @ns).each { |rte| @routes << Route.new(:element => rte, :gpx_file => self) }
|
||||||
|
|
||||||
@tracks.delete_if { |t| t.empty? }
|
@tracks.delete_if { |t| t.empty? }
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,14 @@ module GPX
|
||||||
# addition, you can pass an XML element to this initializer, and the
|
# addition, you can pass an XML element to this initializer, and the
|
||||||
# relevant info will be parsed out.
|
# relevant info will be parsed out.
|
||||||
def initialize(opts = {:lat => 0.0, :lon => 0.0, :elevation => 0.0, :time => Time.now } )
|
def initialize(opts = {:lat => 0.0, :lon => 0.0, :elevation => 0.0, :time => Time.now } )
|
||||||
|
@gpx_file = opts[:gpx_file]
|
||||||
if (opts[:element])
|
if (opts[:element])
|
||||||
elem = opts[:element]
|
elem = opts[:element]
|
||||||
@lat, @lon = elem["lat"].to_f, elem["lon"].to_f
|
@lat, @lon = elem["lat"].to_f, elem["lon"].to_f
|
||||||
@latr, @lonr = (D_TO_R * @lat), (D_TO_R * @lon)
|
@latr, @lonr = (D_TO_R * @lat), (D_TO_R * @lon)
|
||||||
#'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
|
#'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
|
||||||
@time = (Time.xmlschema(elem.find("gpx:time", NS).first.content) rescue nil)
|
@time = (Time.xmlschema(elem.find("gpx:time", @gpx_file.ns).first.content) rescue nil)
|
||||||
@elevation = elem.find("gpx:ele", NS).first.content.to_f unless elem.find("gpx:ele", NS).empty?
|
@elevation = elem.find("gpx:ele", @gpx_file.ns).first.content.to_f unless elem.find("gpx:ele", @gpx_file.ns).empty?
|
||||||
else
|
else
|
||||||
@lat = opts[:lat]
|
@lat = opts[:lat]
|
||||||
@lon = opts[:lon]
|
@lon = opts[:lon]
|
||||||
|
|
|
@ -33,9 +33,9 @@ module GPX
|
||||||
def initialize(opts = {})
|
def initialize(opts = {})
|
||||||
rte_element = opts[:element]
|
rte_element = opts[:element]
|
||||||
@gpx_file = opts[:gpx_file]
|
@gpx_file = opts[:gpx_file]
|
||||||
@name = rte_element.find("child::gpx:name", NS).first.content
|
@name = rte_element.find("child::gpx:name", @ns).first.content
|
||||||
@points = []
|
@points = []
|
||||||
rte_element.find("child::gpx:rtept", NS).each do |point|
|
rte_element.find("child::gpx:rtept", @ns).each do |point|
|
||||||
@points << Point.new(:element => point)
|
@points << Point.new(:element => point)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ module GPX
|
||||||
# If a XML::Node object is passed-in, this will initialize a new
|
# If a XML::Node object is passed-in, this will initialize a new
|
||||||
# Segment based on its contents. Otherwise, a blank Segment is created.
|
# Segment based on its contents. Otherwise, a blank Segment is created.
|
||||||
def initialize(opts = {})
|
def initialize(opts = {})
|
||||||
|
@gpx_file = opts[:gpx_file]
|
||||||
@track = opts[:track]
|
@track = opts[:track]
|
||||||
@points = []
|
@points = []
|
||||||
@earliest_point = nil
|
@earliest_point = nil
|
||||||
|
@ -46,8 +47,8 @@ module GPX
|
||||||
segment_element = opts[:element]
|
segment_element = opts[:element]
|
||||||
last_pt = nil
|
last_pt = nil
|
||||||
if segment_element.is_a?(XML::Node)
|
if segment_element.is_a?(XML::Node)
|
||||||
segment_element.find("child::gpx:trkpt", NS).each do |trkpt|
|
segment_element.find("child::gpx:trkpt", @gpx_file.ns).each do |trkpt|
|
||||||
pt = TrackPoint.new(:element => trkpt, :segment => self)
|
pt = TrackPoint.new(:element => trkpt, :segment => self, :gpx_file => @gpx_file)
|
||||||
unless pt.time.nil?
|
unless pt.time.nil?
|
||||||
@earliest_point = pt if(@earliest_point.nil? or pt.time < @earliest_point.time)
|
@earliest_point = pt if(@earliest_point.nil? or pt.time < @earliest_point.time)
|
||||||
@latest_point = pt if(@latest_point.nil? or pt.time > @latest_point.time)
|
@latest_point = pt if(@latest_point.nil? or pt.time > @latest_point.time)
|
||||||
|
|
|
@ -41,9 +41,9 @@ module GPX
|
||||||
reset_meta_data
|
reset_meta_data
|
||||||
if(opts[:element])
|
if(opts[:element])
|
||||||
trk_element = opts[:element]
|
trk_element = opts[:element]
|
||||||
@name = (trk_element.find("child::gpx:name", NS).first.content rescue "")
|
@name = (trk_element.find("child::gpx:name", @gpx_file.ns).first.content rescue "")
|
||||||
trk_element.find("child::gpx:trkseg", NS).each do |seg_element|
|
trk_element.find("child::gpx:trkseg", @gpx_file.ns).each do |seg_element|
|
||||||
seg = Segment.new(:element => seg_element, :track => self)
|
seg = Segment.new(:element => seg_element, :track => self, :gpx_file => @gpx_file)
|
||||||
update_meta_data(seg)
|
update_meta_data(seg)
|
||||||
@segments << seg
|
@segments << seg
|
||||||
@points.concat(seg.points) unless seg.nil?
|
@points.concat(seg.points) unless seg.nil?
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
require 'test/unit'
|
||||||
|
require File.dirname(__FILE__) + '/../lib/gpx'
|
||||||
|
|
||||||
|
class TestGPX10 < Test::Unit::TestCase
|
||||||
|
GPX_FILE = File.join(File.dirname(__FILE__), "gpx_files/gpx10.gpx")
|
||||||
|
|
||||||
|
def test_read
|
||||||
|
# make sure we can read a GPX 1.0 file
|
||||||
|
@gpx_file = GPX::GPXFile.new(:gpx_file => GPX_FILE)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gpx version="1.0"
|
||||||
|
creator="GPSBabel - http://www.gpsbabel.org"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://www.topografix.com/GPX/1/0"
|
||||||
|
xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
|
||||||
|
<trk>
|
||||||
|
<name>ACTIVE LOG #74</name>
|
||||||
|
<number>82</number>
|
||||||
|
<trkseg>
|
||||||
|
<trkpt lat="37.378388923" lon="-122.063654875">
|
||||||
|
<ele>35.706055</ele>
|
||||||
|
<time>2007-11-23T23:49:43Z</time>
|
||||||
|
</trkpt>
|
||||||
|
</trkseg>
|
||||||
|
</trk>
|
||||||
|
</gpx>
|
Loading…
Reference in New Issue