diff --git a/gpx.gemspec b/gpx.gemspec index ddb4f79..d13c94b 100644 --- a/gpx.gemspec +++ b/gpx.gemspec @@ -1,5 +1,4 @@ -require 'xml/libxml' -require 'lib/gpx/gpx' # load this and xml/libxml just to get GPX::VERSION +require './lib/gpx/gpx' # load this just to get GPX::VERSION require 'rake' # For FileList Gem::Specification.new do |s| s.name = 'gpx' @@ -13,4 +12,5 @@ Gem::Specification.new do |s| s.email = "doug.fales@gmail.com" s.homepage = "http://dougfales.github.com/gpx/" s.rubyforge_project = "gpx" + s.add_dependency('hpricot') end diff --git a/lib/gpx.rb b/lib/gpx.rb index c7c7f03..096f7d0 100644 --- a/lib/gpx.rb +++ b/lib/gpx.rb @@ -22,7 +22,7 @@ #++ $:.unshift(File.dirname(__FILE__)) require 'rubygems' -require 'xml/libxml' +require 'hpricot' require 'date' require 'time' require 'csv' diff --git a/lib/gpx/gpx.rb b/lib/gpx/gpx.rb index c00d98f..7fd5339 100644 --- a/lib/gpx/gpx.rb +++ b/lib/gpx/gpx.rb @@ -21,12 +21,11 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ module GPX - VERSION = "0.6" + VERSION = "0.7" # A common base class which provides a useful initializer method to many # class in the GPX library. class Base - include XML # This initializer can take an XML::Node and scrape out any text # elements with the names given in the "text_elements" array. Each @@ -35,11 +34,11 @@ module GPX # have to pick out individual text elements in each initializer of each # class (Route, TrackPoint, Track, etc). Just pass an array of possible # attributes to this method. - def instantiate_with_text_elements(parent, text_elements, ns) + def instantiate_with_text_elements(parent, text_elements) text_elements.each do |el| - child_xpath = "gpx:#{el}" - unless parent.find(child_xpath, ns).empty? - val = parent.find(child_xpath, ns).first.content + child_xpath = "//#{el}" + unless parent.at(child_xpath).nil? + val = parent.at(child_xpath).inner_text self.send("#{el}=", val) end end diff --git a/lib/gpx/gpx_file.rb b/lib/gpx/gpx_file.rb index 4e7b035..6ce2229 100644 --- a/lib/gpx/gpx_file.rb +++ b/lib/gpx/gpx_file.rb @@ -52,20 +52,19 @@ module GPX # gpx_file = File.open(gpx_file) #end gpx_file = gpx_file.name if gpx_file.is_a?(File) - @xml = XML::Document.file(gpx_file) + @xml = Hpricot(File.open(gpx_file)) else - parser = XML::Parser.string(opts[:gpx_data]) - @xml = parser.parse + @xml = Hpricot(opts[:gpx_data]) end # set XML namespace for XML find - if @xml.root.namespaces.namespace - @ns = 'gpx:' + @xml.root.namespaces.namespace.href - else - @ns = 'gpx:http://www.topografix.com/GPX/1/1' # default to GPX 1.1 - end + #if @xml.root.namespaces.namespace + # @ns = 'gpx:' + @xml.root.namespaces.namespace.href + #else + # @ns = 'gpx:http://www.topografix.com/GPX/1/1' # default to GPX 1.1 + #end reset_meta_data - bounds_element = (@xml.find("//gpx:gpx/gpx:metadata/gpx:bounds", @ns).to_a.first rescue nil) + bounds_element = (@xml.at("//metadata/bounds") rescue nil) if bounds_element @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}) @@ -75,20 +74,18 @@ module GPX get_bounds = true end - @time = Time.parse(@xml.find("//gpx:gpx/gpx:metadata/gpx:time", @ns).first.content) rescue nil - @name = @xml.find("//gpx:gpx/gpx:metadata/gpx:name", @ns).first.content rescue nil - + @time = Time.parse(@xml.at("//metadata/time").inner_text) rescue nil + @name = @xml.at("//metadata/name").inner_text rescue nil @tracks = [] - @xml.find("//gpx:gpx/gpx:trk", @ns).each do |trk| + @xml.search("//trk").each do |trk| trk = Track.new(:element => trk, :gpx_file => self) update_meta_data(trk, get_bounds) @tracks << trk end @waypoints = [] - @xml.find("//gpx:gpx/gpx:wpt", @ns).each { |wpt| @waypoints << Waypoint.new(:element => wpt, :gpx_file => self) } + @xml.search("//wpt").each { |wpt| @waypoints << Waypoint.new(:element => wpt, :gpx_file => self) } @routes = [] - @xml.find("//gpx:gpx/gpx:rte", @ns).each { |rte| @routes << Route.new(:element => rte, :gpx_file => self) } - + @xml.search("//rte").each { |rte| @routes << Route.new(:element => rte, :gpx_file => self) } @tracks.delete_if { |t| t.empty? } calculate_duration @@ -222,7 +219,7 @@ module GPX doc = Document.new doc.root = Node.new('gpx') gpx_elem = doc.root - gpx_elem['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance" + gpx_elem['xsi'] = "http://www.w3.org/2001/XMLSchema-instance" @version = '1.1' if (@version.nil? || !(['1.0', '1.1'].include?(@version))) # default to version 1.1 of the schema (only version 1.0 and 1.1 of the schema exist) version_dir = @version.gsub('.','/') gpx_elem['xmlns'] = @ns || "http://www.topografix.com/GPX/#{version_dir}" diff --git a/lib/gpx/magellan_track_log.rb b/lib/gpx/magellan_track_log.rb index e2fa052..3d3c28a 100644 --- a/lib/gpx/magellan_track_log.rb +++ b/lib/gpx/magellan_track_log.rb @@ -60,11 +60,11 @@ module GPX # Takes the name of a magellan file, converts the contents to GPX, and # writes the result to gpx_filename. - def convert_to_gpx(magellan_filename, gpx_filename) + def convert_to_gpx(magellan_filename, gpx_filename) segment = Segment.new - CSV.open(magellan_filename, "r") do |row| + CSV.open(magellan_filename, "r").each do |row| next if(row.size < 10 or row[INVALID_FLAG] == 'V') lat_deg = row[LAT][0..1] diff --git a/lib/gpx/point.rb b/lib/gpx/point.rb index 6019cc0..b2d2912 100644 --- a/lib/gpx/point.rb +++ b/lib/gpx/point.rb @@ -38,9 +38,9 @@ module GPX @lat, @lon = elem["lat"].to_f, elem["lon"].to_f @latr, @lonr = (D_TO_R * @lat), (D_TO_R * @lon) #'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? - @time = (Time.xmlschema(elem.find("gpx:time", @gpx_file.ns).first.content) rescue nil) - @elevation = elem.find("gpx:ele", @gpx_file.ns).first.content.to_f unless elem.find("gpx:ele", @gpx_file.ns).empty? - @speed = elem.find("gpx:speed", @gpx_file.ns).first.content.to_f unless elem.find("gpx:speed", @gpx_file.ns).empty? + @time = (Time.xmlschema(elem.at("time").inner_text) rescue nil) + @elevation = elem.at("ele").inner_text.to_f unless elem.at("ele").nil? + @speed = elem.at("speed").inner_text.to_f unless elem.at("speed").nil? else @lat = opts[:lat] @lon = opts[:lon] diff --git a/lib/gpx/route.rb b/lib/gpx/route.rb index 53f7997..ebfc6c2 100644 --- a/lib/gpx/route.rb +++ b/lib/gpx/route.rb @@ -34,9 +34,9 @@ module GPX if(opts[:gpx_file] and opts[:element]) rte_element = opts[:element] @gpx_file = opts[:gpx_file] - @name = rte_element.find("child::gpx:name", @gpx_file.ns).first.content + @name = rte_element.at("//name").inner_text @points = [] - rte_element.find("child::gpx:rtept", @gpx_file.ns).each do |point| + rte_element.search("//rtept").each do |point| @points << Point.new(:element => point, :gpx_file => @gpx_file) end else diff --git a/lib/gpx/segment.rb b/lib/gpx/segment.rb index b285ddb..0835b3c 100644 --- a/lib/gpx/segment.rb +++ b/lib/gpx/segment.rb @@ -46,8 +46,8 @@ module GPX if(opts[:element]) segment_element = opts[:element] last_pt = nil - if segment_element.is_a?(XML::Node) - segment_element.find("child::gpx:trkpt", @gpx_file.ns).each do |trkpt| + if segment_element.is_a?(Hpricot::Elem) + segment_element.search("//trkpt").each do |trkpt| pt = TrackPoint.new(:element => trkpt, :segment => self, :gpx_file => @gpx_file) unless pt.time.nil? @earliest_point = pt if(@earliest_point.nil? or pt.time < @earliest_point.time) diff --git a/lib/gpx/track.rb b/lib/gpx/track.rb index bc16a31..cb8892a 100644 --- a/lib/gpx/track.rb +++ b/lib/gpx/track.rb @@ -41,8 +41,8 @@ module GPX reset_meta_data if(opts[:element]) trk_element = opts[:element] - @name = (trk_element.find("child::gpx:name", @gpx_file.ns).first.content rescue "") - trk_element.find("child::gpx:trkseg", @gpx_file.ns).each do |seg_element| + @name = (trk_element.at("//name").inner_text rescue "") + trk_element.search("//trkseg").each do |seg_element| seg = Segment.new(:element => seg_element, :track => self, :gpx_file => @gpx_file) update_meta_data(seg) @segments << seg @@ -69,8 +69,8 @@ module GPX # correlating things like pictures, video, and other events, if you are # working with a timestamp. def closest_point(time) - segment = segments.find { |s| s.contains_time?(time) } - segment.closest_point(time) + segment = segments.select { |s| s.contains_time?(time) } + segment.first end # Removes all points outside of a given area and updates the meta data. @@ -114,6 +114,7 @@ module GPX # Prints out a friendly summary of this track (sans points). Useful for # debugging and sanity checks. + def to_s result = "Track \n" result << "\tName: #{name}\n" diff --git a/lib/gpx/waypoint.rb b/lib/gpx/waypoint.rb index f1d00a6..3090322 100644 --- a/lib/gpx/waypoint.rb +++ b/lib/gpx/waypoint.rb @@ -46,7 +46,7 @@ module GPX wpt_elem = opts[:element] @gpx_file = opts[:gpx_file] super(:element => wpt_elem, :gpx_file => @gpx_file) - instantiate_with_text_elements(wpt_elem, SUB_ELEMENTS, @gpx_file.ns) + instantiate_with_text_elements(wpt_elem, SUB_ELEMENTS) else opts.each do |key, value| assignment_method = "#{key}=" diff --git a/tests/segment_test.rb b/tests/segment_test.rb index 34a4362..74d838c 100644 --- a/tests/segment_test.rb +++ b/tests/segment_test.rb @@ -12,11 +12,11 @@ class SegmentTest < Test::Unit::TestCase def test_segment_read assert_equal(189, @segment.points.size) - assert_equal("Fri Apr 07 18:12:05 UTC 2006", @segment.earliest_point.time.to_s) - assert_equal("Fri Apr 07 19:26:31 UTC 2006", @segment.latest_point.time.to_s) + assert_equal(1144433525, @segment.earliest_point.time.to_i) + assert_equal(1144437991, @segment.latest_point.time.to_i) assert_equal(1334.447, @segment.lowest_point.elevation) assert_equal(1480.087, @segment.highest_point.elevation) - assert_equal("6.98803359528853", @segment.distance.to_s) + assert_in_delta(6.98803359528853, @segment.distance, 0.001) end def test_segment_crop @@ -27,9 +27,9 @@ class SegmentTest < Test::Unit::TestCase @segment.crop(crop_rectangle) assert_equal(106, @segment.points.size) - assert_equal("4.11422061733046", @segment.distance.to_s) - assert_equal("Fri Apr 07 18:37:21 UTC 2006", @segment.earliest_point.time.to_s) - assert_equal("Fri Apr 07 19:22:32 UTC 2006", @segment.latest_point.time.to_s) + assert_in_delta(4.11422061733046, @segment.distance, 0.001) + assert_equal(1144435041, @segment.earliest_point.time.to_i) + assert_equal(1144437752, @segment.latest_point.time.to_i) assert_equal(1407.027, @segment.lowest_point.elevation) assert_equal(1480.087, @segment.highest_point.elevation) assert_equal(39.173834, @segment.bounds.min_lat) @@ -45,9 +45,9 @@ class SegmentTest < Test::Unit::TestCase :max_lon=> -108.999000) @segment.delete_area(delete_rectangle) assert_equal(83, @segment.points.size) - assert_equal("3.35967118153605", @segment.distance.to_s) - assert_equal("Fri Apr 07 18:12:05 UTC 2006", @segment.earliest_point.time.to_s) - assert_equal("Fri Apr 07 19:26:31 UTC 2006", @segment.latest_point.time.to_s) + assert_in_delta(3.35967118153605, @segment.distance, 0.001) + assert_equal(1144433525, @segment.earliest_point.time.to_i) + assert_equal(1144437991, @segment.latest_point.time.to_i) assert_equal(1334.447, @segment.lowest_point.elevation) assert_equal(1428.176, @segment.highest_point.elevation) assert_equal(39.180572, @segment.bounds.min_lat) diff --git a/tests/track_test.rb b/tests/track_test.rb index 3744976..5afbf87 100644 --- a/tests/track_test.rb +++ b/tests/track_test.rb @@ -13,7 +13,7 @@ class TrackTest < Test::Unit::TestCase assert_equal("ACTIVE LOG", @track.name) assert_equal( 182, @track.points.size) assert_equal(8, @track.segments.size) - assert_equal("3.07249668492626", @track.distance.to_s) + assert_in_delta(3.07249668492626, @track.distance, 0.001) assert_equal(1267.155, @track.lowest_point.elevation) assert_equal(1594.003, @track.highest_point.elevation) assert_equal(38.681488, @track.bounds.min_lat) @@ -32,7 +32,7 @@ class TrackTest < Test::Unit::TestCase assert_equal("ACTIVE LOG", @track.name) assert_equal( 111, @track.points.size) assert_equal(4, @track.segments.size) - assert_equal("1.62136024923607", @track.distance.to_s) + assert_in_delta(1.62136024923607, @track.distance, 0.001) assert_equal(1557.954, @track.lowest_point.elevation) assert_equal(1582.468, @track.highest_point.elevation) assert_equal(38.782511, @track.bounds.min_lat)