gooby 0.9.3 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README +96 -43
- data/bin/example_usage.rb +15 -6
- data/bin/tcx_ex.rb +35 -0
- data/data/2007_03_04.tcx +16751 -0
- data/data/activity_2007_03_04_15_22_36.xml +10545 -0
- data/lib/gooby/cls_gooby_command.rb +14 -3
- data/lib/gooby/cls_training_center_parser.rb +183 -0
- data/lib/gooby/cls_training_center_splitter.rb +109 -0
- data/lib/gooby/mod_project_info.rb +1 -1
- data/lib/gooby.rb +303 -5
- data/pkg/pkg.rb +2 -0
- data/tests/tc_mod_project_info.rb +1 -1
- data/tests/ts_gooby.rb +2 -2
- metadata +7 -21
- data/data/20051119_dowd_ymca_hm.csv +0 -251
- data/data/20051119_dowd_ymca_hm.xml +0 -2210
- data/data/run_2007_01_06_15_27_31.xml +0 -2020
- data/data/run_2007_01_10_12_25_47.xml +0 -820
- data/data/run_2007_01_10_22_44_54.csv +0 -112
- data/data/run_2007_01_10_22_44_54.xml +0 -908
- data/data/run_2007_01_11_10_48_45.xml +0 -1292
- data/data/run_2007_01_13_15_37_06.xml +0 -1964
- data/data/run_2007_01_14_15_46_02.xml +0 -1368
- data/data/run_2007_01_15_14_01_48.xml +0 -1868
- data/data/run_2007_01_20_16_22_05.xml +0 -1702
- data/data/run_2007_01_27_17_32_13.xml +0 -3626
- data/data/run_2007_01_28_19_14_52.xml +0 -2538
- data/data/run_2007_02_03_14_30_20.xml +0 -2016
- data/data/run_2007_02_04_18_02_30.xml +0 -1476
- data/data/run_2007_02_17_16_29_35.xml +0 -1236
- data/data/run_2007_02_19_14_44_33.xml +0 -1816
- data/data/run_2007_02_23_15_53_55.xml +0 -36
- data/data/run_2007_02_23_15_55_20.xml +0 -1296
@@ -14,17 +14,28 @@ module Gooby
|
|
14
14
|
Gooby::Options.new(yaml_filename)
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def split_garmin_forerunner_logbook_xml(xml_filename, out_dir)
|
18
18
|
splitter = Gooby::ForerunnerXmlSplitter.new(xml_filename, out_dir)
|
19
19
|
splitter.split
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def split_garmin_training_center_xml(tcx_filename, out_dir)
|
23
|
+
splitter = Gooby::TrainingCenterXmlSplitter.new(tcx_filename, out_dir)
|
24
|
+
splitter.split
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_garmin_forerunner_logbook_xml(xml_filename)
|
23
28
|
handler = Gooby::ForerunnerXmlParser.new
|
24
29
|
Document.parse_stream((File.new xml_filename), handler)
|
25
30
|
handler.put_all_run_tkpt_csv(true)
|
26
31
|
end
|
27
|
-
|
32
|
+
|
33
|
+
def parse_garmin_training_center_xml(tcx_filename)
|
34
|
+
handler = Gooby::TrainingCenterXmlParser.new
|
35
|
+
Document.parse_stream((File.new tcx_filename), handler)
|
36
|
+
handler.put_all_run_tkpt_csv(true)
|
37
|
+
end
|
38
|
+
|
28
39
|
def generate_google_map(csv_filename, options_obj)
|
29
40
|
generator = Gooby::GoogleMapGenerator.new(csv_filename)
|
30
41
|
generator.generate_page(options_obj)
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module Gooby
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
Instances of this class are used to parse a Garmin TrainingCenter XML file
|
5
|
+
in a SAX-like manner. Instances of the model classes - History, Run, Track,
|
6
|
+
Trackpoint, etc. are created in this parsing process.
|
7
|
+
|
8
|
+
See http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd for the XML
|
9
|
+
Schema Definition for Garmin TrainingCenter XML.
|
10
|
+
=end
|
11
|
+
|
12
|
+
class TrainingCenterXmlParser
|
13
|
+
|
14
|
+
DETAIL_TAGS = %w( Notes StartTime Duration Length Time
|
15
|
+
TotalTimeSeconds DistanceMeters
|
16
|
+
LatitudeDegrees LongitudeDegrees AltitudeMeters BeginPosition EndPosition )
|
17
|
+
|
18
|
+
include REXML::StreamListener
|
19
|
+
|
20
|
+
attr_reader :history, :cvHash, :tagCount
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@cvHash = Hash.new("")
|
24
|
+
@tagCount = 0
|
25
|
+
@runCount = 0
|
26
|
+
@lapCount = 0
|
27
|
+
@trackCount = 0
|
28
|
+
@trackpoint_count = 0
|
29
|
+
@currText = "";
|
30
|
+
@history = History.new
|
31
|
+
@currRun = nil
|
32
|
+
@currLap = nil
|
33
|
+
@currTrack = nil
|
34
|
+
@currBeginPosition = nil
|
35
|
+
@currEndPosition = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
public
|
39
|
+
|
40
|
+
# SAX API method; handles 'Activity', 'Lap', 'Track'.
|
41
|
+
def tag_start(tagname, attrs)
|
42
|
+
@tagCount += 1
|
43
|
+
@currTag = tagname
|
44
|
+
@cvHash[tagname] = ''
|
45
|
+
|
46
|
+
if detail_tag?(tagname)
|
47
|
+
@inDetail = true
|
48
|
+
end
|
49
|
+
|
50
|
+
if is_tag?('Activity', tagname)
|
51
|
+
@runCount = @runCount + 1
|
52
|
+
@lapCount = 0
|
53
|
+
@trackCount = 0
|
54
|
+
@currRun = Run.new(@runCount)
|
55
|
+
@history.add_run(@currRun)
|
56
|
+
@cvHash['Notes'] = ''
|
57
|
+
return
|
58
|
+
end
|
59
|
+
|
60
|
+
if is_tag?('Lap', tagname)
|
61
|
+
@lapCount = @lapCount + 1
|
62
|
+
@currLap = Lap.new(@lapCount)
|
63
|
+
# TODO - capture value of 'StartTime' attribute.
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
if is_tag?('Track', tagname)
|
68
|
+
@trackCount = @trackCount + 1
|
69
|
+
@currTrack = Track.new(@trackCount)
|
70
|
+
@trackpoint_count = 0
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
# SAX API method; handles 'Position', 'Trackpoint', 'Track', 'Lap', 'Run'.
|
77
|
+
def tag_end(tagname)
|
78
|
+
if @inDetail
|
79
|
+
@cvHash[tagname] = @currText
|
80
|
+
else
|
81
|
+
if is_tag?('Position', tagname)
|
82
|
+
lat = @cvHash['LatitudeDegrees']
|
83
|
+
long = @cvHash['LongitudeDegrees']
|
84
|
+
@currBeginPosition = Position.new(lat.strip, long.strip, '')
|
85
|
+
@currEndPosition = Position.new(lat.strip, long.strip, '')
|
86
|
+
end
|
87
|
+
|
88
|
+
if is_tag?('BeginPosition', tagname)
|
89
|
+
lat = @cvHash['LatitudeDegrees']
|
90
|
+
long = @cvHash['LongitudeDegrees']
|
91
|
+
@currBeginPosition = Position.new(lat.strip, long.strip, '')
|
92
|
+
end
|
93
|
+
|
94
|
+
if is_tag?('EndPosition', tagname)
|
95
|
+
lat = @cvHash['LatitudeDegrees']
|
96
|
+
long = @cvHash['LongitudeDegrees']
|
97
|
+
@currEndPosition = Position.new(lat.strip, long.strip, '')
|
98
|
+
end
|
99
|
+
|
100
|
+
if is_tag?('Trackpoint', tagname)
|
101
|
+
@trackpoint_count = @trackpoint_count + 1
|
102
|
+
lat = @cvHash['LatitudeDegrees']
|
103
|
+
long = @cvHash['LongitudeDegrees']
|
104
|
+
alt = @cvHash['AltitudeMeters']
|
105
|
+
time = @cvHash['Time']
|
106
|
+
tp = Trackpoint.new(@trackpoint_count, lat, long, alt, time)
|
107
|
+
@currTrack.add_trackpoint(tp)
|
108
|
+
end
|
109
|
+
|
110
|
+
if is_tag?('Track', tagname)
|
111
|
+
if @currRun != nil
|
112
|
+
@currRun.add_track(@currTrack)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
if is_tag?('Lap', tagname)
|
117
|
+
# TotalTimeSeconds DistanceMeters
|
118
|
+
# TODO - rework tnd of Lap for tcx
|
119
|
+
# @currLap.startTime = @cvHash['StartTime']
|
120
|
+
# @currLap.duration = Duration.new(@cvHash['Duration'])
|
121
|
+
# @currLap.length = @cvHash['Length']
|
122
|
+
# @currLap.beginPosition = @currBeginPosition
|
123
|
+
# @currLap.endPosition = @currEndPosition
|
124
|
+
@currRun.add_lap(@currLap)
|
125
|
+
end
|
126
|
+
|
127
|
+
if is_tag?('Activity', tagname)
|
128
|
+
@currRun.notes = @cvHash['Notes']
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
@inDetail = false
|
133
|
+
@currText = ""
|
134
|
+
@currTag = ""
|
135
|
+
end
|
136
|
+
|
137
|
+
# SAX API method.
|
138
|
+
def text(txt)
|
139
|
+
if @inDetail
|
140
|
+
@currText = @currText + txt
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Iterate all parsed Run objects and print each with to_s.
|
145
|
+
def gdump()
|
146
|
+
@history.runs().each { |run| puts run.to_s }
|
147
|
+
end
|
148
|
+
|
149
|
+
# Iterate all parsed Run objects and print each with to_s.
|
150
|
+
def dump()
|
151
|
+
@history.runs().each { |run| puts run.to_s }
|
152
|
+
end
|
153
|
+
|
154
|
+
# Iterate all parsed Run objects and print each with put_csv.
|
155
|
+
def put_run_csv()
|
156
|
+
@history.runs().each { |run| run.put_csv() }
|
157
|
+
end
|
158
|
+
|
159
|
+
# Iterate all parsed Run objects and print each with put_tkpt_csv.
|
160
|
+
def put_all_run_tkpt_csv(with_header_comment)
|
161
|
+
@history.runs.each { |run|
|
162
|
+
run.put_tkpt_csv(with_header_comment)
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def is_tag?(tagname, value)
|
169
|
+
tagname == value
|
170
|
+
end
|
171
|
+
|
172
|
+
def detail_tag?(tagname)
|
173
|
+
DETAIL_TAGS.each { |typ|
|
174
|
+
if typ == tagname
|
175
|
+
return true
|
176
|
+
end
|
177
|
+
}
|
178
|
+
return false
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
end # end of module
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Gooby
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
Instances of this class are used to split a large Garmin TrainingCenter
|
5
|
+
*.tcx file into individual 'activity_' files.
|
6
|
+
=end
|
7
|
+
|
8
|
+
class TrainingCenterXmlSplitter < GoobyObject
|
9
|
+
|
10
|
+
attr_reader :out_dir, :training_center_files, :out_files_hash
|
11
|
+
|
12
|
+
def initialize(tcx_file, out_dir)
|
13
|
+
@out_dir = out_dir
|
14
|
+
@training_center_files = Array.new
|
15
|
+
@training_center_files << tcx_file
|
16
|
+
@out_files_hash = Hash.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def split
|
20
|
+
@training_center_files.each { |f| process_file(f) }
|
21
|
+
write_files
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def process_file(training_center_tcx_file)
|
27
|
+
@file_name = training_center_tcx_file
|
28
|
+
@tcx_lines = read_lines(@file_name, false)
|
29
|
+
@line_num = 0
|
30
|
+
@activity_num = 0
|
31
|
+
@curr_activity_lines = Array.new
|
32
|
+
@curr_activity_tkpts = 0
|
33
|
+
@start_line_num = 0
|
34
|
+
@end_line_num = 0
|
35
|
+
@activity_start_time = nil
|
36
|
+
|
37
|
+
@tcx_lines.each { |line|
|
38
|
+
@line_num = @line_num + 1
|
39
|
+
if (line.match(/<Activity /))
|
40
|
+
@activity_num = @activity_num + 1
|
41
|
+
@start_line_num = @line_num
|
42
|
+
@curr_activity_lines = Array.new
|
43
|
+
@curr_activity_lines << line
|
44
|
+
elsif (line.match(/<Id>/)) # <Id>2007-03-03T15:58:57Z</Id> <StartTime>2007-01-13T15:37:06Z</StartTime>
|
45
|
+
@curr_activity_lines << line
|
46
|
+
if @activity_start_time == nil
|
47
|
+
clone = String.new(line)
|
48
|
+
clone.gsub!(/[<>]/, ' ')
|
49
|
+
clone.gsub!(/[-:T]/, '_')
|
50
|
+
clone.gsub!(/[Z]/, '')
|
51
|
+
tokens = clone.split
|
52
|
+
@activity_start_time = tokens[1]
|
53
|
+
end
|
54
|
+
elsif (line.match(/<Trackpoint>/))
|
55
|
+
@curr_activity_tkpts = @curr_activity_tkpts + 1
|
56
|
+
@curr_activity_lines << line
|
57
|
+
elsif (line.match(/<\/Activity/))
|
58
|
+
@end_line_num = @line_num
|
59
|
+
@curr_activity_lines << line
|
60
|
+
end_run
|
61
|
+
elsif (@curr_activity_lines.size > 0)
|
62
|
+
@curr_activity_lines << line
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def end_run
|
68
|
+
out_file = "#{@out_dir}/activity_#{@activity_start_time}.xml"
|
69
|
+
comment = "<!-- file: #{out_file} lines: #{@curr_activity_lines.size} (#{@start_line_num} to #{@end_line_num}) tkpts: #{@curr_activity_tkpts} --> \n"
|
70
|
+
@curr_activity_lines.insert(0, comment)
|
71
|
+
|
72
|
+
prev_entry = @out_files_hash[out_file]
|
73
|
+
if prev_entry
|
74
|
+
if (@curr_activity_lines.size >= prev_entry.size)
|
75
|
+
puts "previous entry overlaid for #{out_file}. curr=#{@curr_activity_lines.size} prev=#{prev_entry.size}"
|
76
|
+
@out_files_hash[out_file] = @curr_activity_lines
|
77
|
+
else
|
78
|
+
puts "previous entry retained for #{out_file}. curr=#{@curr_activity_lines.size} prev=#{prev_entry.size}"
|
79
|
+
end
|
80
|
+
else
|
81
|
+
puts "new entry for #{out_file}. curr=#{@curr_activity_lines.size}"
|
82
|
+
@out_files_hash[out_file] = @curr_activity_lines
|
83
|
+
end
|
84
|
+
|
85
|
+
@curr_activity_lines = Array.new
|
86
|
+
@curr_activity_tkpts = 0
|
87
|
+
@start_line_num = 0
|
88
|
+
@end_line_num = 0
|
89
|
+
@activity_start_time = nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def write_files
|
93
|
+
out_names = @out_files_hash.keys.sort
|
94
|
+
puts "Writing #{out_names.size} extract files..."
|
95
|
+
out_names.each { |out_name|
|
96
|
+
lines = @out_files_hash[out_name]
|
97
|
+
out = File.new out_name, "w+"
|
98
|
+
lines.each { |line| out.write line }
|
99
|
+
out.flush
|
100
|
+
out.close
|
101
|
+
puts "File written: #{out_name}"
|
102
|
+
}
|
103
|
+
puts "output files written."
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end # end of module
|
109
|
+
|
data/lib/gooby.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Packaged on
|
1
|
+
# Packaged on Fri Mar 09 06:03:09 EST 2007
|
2
2
|
|
3
3
|
=begin
|
4
4
|
|
@@ -34,7 +34,7 @@ module Gooby
|
|
34
34
|
|
35
35
|
# Return a String version number, like '1.0.0'.
|
36
36
|
def project_version_number
|
37
|
-
'0.9.
|
37
|
+
'0.9.4'
|
38
38
|
end
|
39
39
|
|
40
40
|
# Return a String date, like '2007/02/25'.
|
@@ -805,6 +805,293 @@ module Gooby
|
|
805
805
|
end
|
806
806
|
|
807
807
|
|
808
|
+
=begin rdoc
|
809
|
+
Instances of this class are used to parse a Garmin TrainingCenter XML file
|
810
|
+
in a SAX-like manner. Instances of the model classes - History, Run, Track,
|
811
|
+
Trackpoint, etc. are created in this parsing process.
|
812
|
+
|
813
|
+
See http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd for the XML
|
814
|
+
Schema Definition for Garmin TrainingCenter XML.
|
815
|
+
=end
|
816
|
+
|
817
|
+
class TrainingCenterXmlParser
|
818
|
+
|
819
|
+
DETAIL_TAGS = %w( Notes StartTime Duration Length Time
|
820
|
+
TotalTimeSeconds DistanceMeters
|
821
|
+
LatitudeDegrees LongitudeDegrees AltitudeMeters BeginPosition EndPosition )
|
822
|
+
|
823
|
+
include REXML::StreamListener
|
824
|
+
|
825
|
+
attr_reader :history, :cvHash, :tagCount
|
826
|
+
|
827
|
+
def initialize
|
828
|
+
@cvHash = Hash.new("")
|
829
|
+
@tagCount = 0
|
830
|
+
@runCount = 0
|
831
|
+
@lapCount = 0
|
832
|
+
@trackCount = 0
|
833
|
+
@trackpoint_count = 0
|
834
|
+
@currText = "";
|
835
|
+
@history = History.new
|
836
|
+
@currRun = nil
|
837
|
+
@currLap = nil
|
838
|
+
@currTrack = nil
|
839
|
+
@currBeginPosition = nil
|
840
|
+
@currEndPosition = nil
|
841
|
+
end
|
842
|
+
|
843
|
+
public
|
844
|
+
|
845
|
+
# SAX API method; handles 'Activity', 'Lap', 'Track'.
|
846
|
+
def tag_start(tagname, attrs)
|
847
|
+
@tagCount += 1
|
848
|
+
@currTag = tagname
|
849
|
+
@cvHash[tagname] = ''
|
850
|
+
|
851
|
+
if detail_tag?(tagname)
|
852
|
+
@inDetail = true
|
853
|
+
end
|
854
|
+
|
855
|
+
if is_tag?('Activity', tagname)
|
856
|
+
@runCount = @runCount + 1
|
857
|
+
@lapCount = 0
|
858
|
+
@trackCount = 0
|
859
|
+
@currRun = Run.new(@runCount)
|
860
|
+
@history.add_run(@currRun)
|
861
|
+
@cvHash['Notes'] = ''
|
862
|
+
return
|
863
|
+
end
|
864
|
+
|
865
|
+
if is_tag?('Lap', tagname)
|
866
|
+
@lapCount = @lapCount + 1
|
867
|
+
@currLap = Lap.new(@lapCount)
|
868
|
+
# TODO - capture value of 'StartTime' attribute.
|
869
|
+
return
|
870
|
+
end
|
871
|
+
|
872
|
+
if is_tag?('Track', tagname)
|
873
|
+
@trackCount = @trackCount + 1
|
874
|
+
@currTrack = Track.new(@trackCount)
|
875
|
+
@trackpoint_count = 0
|
876
|
+
return
|
877
|
+
end
|
878
|
+
|
879
|
+
end
|
880
|
+
|
881
|
+
# SAX API method; handles 'Position', 'Trackpoint', 'Track', 'Lap', 'Run'.
|
882
|
+
def tag_end(tagname)
|
883
|
+
if @inDetail
|
884
|
+
@cvHash[tagname] = @currText
|
885
|
+
else
|
886
|
+
if is_tag?('Position', tagname)
|
887
|
+
lat = @cvHash['LatitudeDegrees']
|
888
|
+
long = @cvHash['LongitudeDegrees']
|
889
|
+
@currBeginPosition = Position.new(lat.strip, long.strip, '')
|
890
|
+
@currEndPosition = Position.new(lat.strip, long.strip, '')
|
891
|
+
end
|
892
|
+
|
893
|
+
if is_tag?('BeginPosition', tagname)
|
894
|
+
lat = @cvHash['LatitudeDegrees']
|
895
|
+
long = @cvHash['LongitudeDegrees']
|
896
|
+
@currBeginPosition = Position.new(lat.strip, long.strip, '')
|
897
|
+
end
|
898
|
+
|
899
|
+
if is_tag?('EndPosition', tagname)
|
900
|
+
lat = @cvHash['LatitudeDegrees']
|
901
|
+
long = @cvHash['LongitudeDegrees']
|
902
|
+
@currEndPosition = Position.new(lat.strip, long.strip, '')
|
903
|
+
end
|
904
|
+
|
905
|
+
if is_tag?('Trackpoint', tagname)
|
906
|
+
@trackpoint_count = @trackpoint_count + 1
|
907
|
+
lat = @cvHash['LatitudeDegrees']
|
908
|
+
long = @cvHash['LongitudeDegrees']
|
909
|
+
alt = @cvHash['AltitudeMeters']
|
910
|
+
time = @cvHash['Time']
|
911
|
+
tp = Trackpoint.new(@trackpoint_count, lat, long, alt, time)
|
912
|
+
@currTrack.add_trackpoint(tp)
|
913
|
+
end
|
914
|
+
|
915
|
+
if is_tag?('Track', tagname)
|
916
|
+
if @currRun != nil
|
917
|
+
@currRun.add_track(@currTrack)
|
918
|
+
end
|
919
|
+
end
|
920
|
+
|
921
|
+
if is_tag?('Lap', tagname)
|
922
|
+
# TotalTimeSeconds DistanceMeters
|
923
|
+
# TODO - rework tnd of Lap for tcx
|
924
|
+
# @currLap.startTime = @cvHash['StartTime']
|
925
|
+
# @currLap.duration = Duration.new(@cvHash['Duration'])
|
926
|
+
# @currLap.length = @cvHash['Length']
|
927
|
+
# @currLap.beginPosition = @currBeginPosition
|
928
|
+
# @currLap.endPosition = @currEndPosition
|
929
|
+
@currRun.add_lap(@currLap)
|
930
|
+
end
|
931
|
+
|
932
|
+
if is_tag?('Activity', tagname)
|
933
|
+
@currRun.notes = @cvHash['Notes']
|
934
|
+
end
|
935
|
+
end
|
936
|
+
|
937
|
+
@inDetail = false
|
938
|
+
@currText = ""
|
939
|
+
@currTag = ""
|
940
|
+
end
|
941
|
+
|
942
|
+
# SAX API method.
|
943
|
+
def text(txt)
|
944
|
+
if @inDetail
|
945
|
+
@currText = @currText + txt
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
949
|
+
# Iterate all parsed Run objects and print each with to_s.
|
950
|
+
def gdump()
|
951
|
+
@history.runs().each { |run| puts run.to_s }
|
952
|
+
end
|
953
|
+
|
954
|
+
# Iterate all parsed Run objects and print each with to_s.
|
955
|
+
def dump()
|
956
|
+
@history.runs().each { |run| puts run.to_s }
|
957
|
+
end
|
958
|
+
|
959
|
+
# Iterate all parsed Run objects and print each with put_csv.
|
960
|
+
def put_run_csv()
|
961
|
+
@history.runs().each { |run| run.put_csv() }
|
962
|
+
end
|
963
|
+
|
964
|
+
# Iterate all parsed Run objects and print each with put_tkpt_csv.
|
965
|
+
def put_all_run_tkpt_csv(with_header_comment)
|
966
|
+
@history.runs.each { |run|
|
967
|
+
run.put_tkpt_csv(with_header_comment)
|
968
|
+
}
|
969
|
+
end
|
970
|
+
|
971
|
+
private
|
972
|
+
|
973
|
+
def is_tag?(tagname, value)
|
974
|
+
tagname == value
|
975
|
+
end
|
976
|
+
|
977
|
+
def detail_tag?(tagname)
|
978
|
+
DETAIL_TAGS.each { |typ|
|
979
|
+
if typ == tagname
|
980
|
+
return true
|
981
|
+
end
|
982
|
+
}
|
983
|
+
return false
|
984
|
+
end
|
985
|
+
|
986
|
+
end
|
987
|
+
|
988
|
+
|
989
|
+
=begin rdoc
|
990
|
+
Instances of this class are used to split a large Garmin TrainingCenter
|
991
|
+
*.tcx file into individual 'activity_' files.
|
992
|
+
=end
|
993
|
+
|
994
|
+
class TrainingCenterXmlSplitter < GoobyObject
|
995
|
+
|
996
|
+
attr_reader :out_dir, :training_center_files, :out_files_hash
|
997
|
+
|
998
|
+
def initialize(tcx_file, out_dir)
|
999
|
+
@out_dir = out_dir
|
1000
|
+
@training_center_files = Array.new
|
1001
|
+
@training_center_files << tcx_file
|
1002
|
+
@out_files_hash = Hash.new
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
def split
|
1006
|
+
@training_center_files.each { |f| process_file(f) }
|
1007
|
+
write_files
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
private
|
1011
|
+
|
1012
|
+
def process_file(training_center_tcx_file)
|
1013
|
+
@file_name = training_center_tcx_file
|
1014
|
+
@tcx_lines = read_lines(@file_name, false)
|
1015
|
+
@line_num = 0
|
1016
|
+
@activity_num = 0
|
1017
|
+
@curr_activity_lines = Array.new
|
1018
|
+
@curr_activity_tkpts = 0
|
1019
|
+
@start_line_num = 0
|
1020
|
+
@end_line_num = 0
|
1021
|
+
@activity_start_time = nil
|
1022
|
+
|
1023
|
+
@tcx_lines.each { |line|
|
1024
|
+
@line_num = @line_num + 1
|
1025
|
+
if (line.match(/<Activity /))
|
1026
|
+
@activity_num = @activity_num + 1
|
1027
|
+
@start_line_num = @line_num
|
1028
|
+
@curr_activity_lines = Array.new
|
1029
|
+
@curr_activity_lines << line
|
1030
|
+
elsif (line.match(/<Id>/)) # <Id>2007-03-03T15:58:57Z</Id> <StartTime>2007-01-13T15:37:06Z</StartTime>
|
1031
|
+
@curr_activity_lines << line
|
1032
|
+
if @activity_start_time == nil
|
1033
|
+
clone = String.new(line)
|
1034
|
+
clone.gsub!(/[<>]/, ' ')
|
1035
|
+
clone.gsub!(/[-:T]/, '_')
|
1036
|
+
clone.gsub!(/[Z]/, '')
|
1037
|
+
tokens = clone.split
|
1038
|
+
@activity_start_time = tokens[1]
|
1039
|
+
end
|
1040
|
+
elsif (line.match(/<Trackpoint>/))
|
1041
|
+
@curr_activity_tkpts = @curr_activity_tkpts + 1
|
1042
|
+
@curr_activity_lines << line
|
1043
|
+
elsif (line.match(/<\/Activity/))
|
1044
|
+
@end_line_num = @line_num
|
1045
|
+
@curr_activity_lines << line
|
1046
|
+
end_run
|
1047
|
+
elsif (@curr_activity_lines.size > 0)
|
1048
|
+
@curr_activity_lines << line
|
1049
|
+
end
|
1050
|
+
}
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
def end_run
|
1054
|
+
out_file = "#{@out_dir}/activity_#{@activity_start_time}.xml"
|
1055
|
+
comment = "<!-- file: #{out_file} lines: #{@curr_activity_lines.size} (#{@start_line_num} to #{@end_line_num}) tkpts: #{@curr_activity_tkpts} --> \n"
|
1056
|
+
@curr_activity_lines.insert(0, comment)
|
1057
|
+
|
1058
|
+
prev_entry = @out_files_hash[out_file]
|
1059
|
+
if prev_entry
|
1060
|
+
if (@curr_activity_lines.size >= prev_entry.size)
|
1061
|
+
puts "previous entry overlaid for #{out_file}. curr=#{@curr_activity_lines.size} prev=#{prev_entry.size}"
|
1062
|
+
@out_files_hash[out_file] = @curr_activity_lines
|
1063
|
+
else
|
1064
|
+
puts "previous entry retained for #{out_file}. curr=#{@curr_activity_lines.size} prev=#{prev_entry.size}"
|
1065
|
+
end
|
1066
|
+
else
|
1067
|
+
puts "new entry for #{out_file}. curr=#{@curr_activity_lines.size}"
|
1068
|
+
@out_files_hash[out_file] = @curr_activity_lines
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
@curr_activity_lines = Array.new
|
1072
|
+
@curr_activity_tkpts = 0
|
1073
|
+
@start_line_num = 0
|
1074
|
+
@end_line_num = 0
|
1075
|
+
@activity_start_time = nil
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
def write_files
|
1079
|
+
out_names = @out_files_hash.keys.sort
|
1080
|
+
puts "Writing #{out_names.size} extract files..."
|
1081
|
+
out_names.each { |out_name|
|
1082
|
+
lines = @out_files_hash[out_name]
|
1083
|
+
out = File.new out_name, "w+"
|
1084
|
+
lines.each { |line| out.write line }
|
1085
|
+
out.flush
|
1086
|
+
out.close
|
1087
|
+
puts "File written: #{out_name}"
|
1088
|
+
}
|
1089
|
+
puts "output files written."
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
|
808
1095
|
=begin rdoc
|
809
1096
|
Instances of this class represent a the set of Geographic data defined in file geo.txt
|
810
1097
|
=end
|
@@ -2244,17 +2531,28 @@ HERE
|
|
2244
2531
|
Gooby::Options.new(yaml_filename)
|
2245
2532
|
end
|
2246
2533
|
|
2247
|
-
def
|
2534
|
+
def split_garmin_forerunner_logbook_xml(xml_filename, out_dir)
|
2248
2535
|
splitter = Gooby::ForerunnerXmlSplitter.new(xml_filename, out_dir)
|
2249
2536
|
splitter.split
|
2250
2537
|
end
|
2251
2538
|
|
2252
|
-
def
|
2539
|
+
def split_garmin_training_center_xml(tcx_filename, out_dir)
|
2540
|
+
splitter = Gooby::TrainingCenterXmlSplitter.new(tcx_filename, out_dir)
|
2541
|
+
splitter.split
|
2542
|
+
end
|
2543
|
+
|
2544
|
+
def parse_garmin_forerunner_logbook_xml(xml_filename)
|
2253
2545
|
handler = Gooby::ForerunnerXmlParser.new
|
2254
2546
|
Document.parse_stream((File.new xml_filename), handler)
|
2255
2547
|
handler.put_all_run_tkpt_csv(true)
|
2256
2548
|
end
|
2257
|
-
|
2549
|
+
|
2550
|
+
def parse_garmin_training_center_xml(tcx_filename)
|
2551
|
+
handler = Gooby::TrainingCenterXmlParser.new
|
2552
|
+
Document.parse_stream((File.new tcx_filename), handler)
|
2553
|
+
handler.put_all_run_tkpt_csv(true)
|
2554
|
+
end
|
2555
|
+
|
2258
2556
|
def generate_google_map(csv_filename, options_obj)
|
2259
2557
|
generator = Gooby::GoogleMapGenerator.new(csv_filename)
|
2260
2558
|
generator.generate_page(options_obj)
|
data/pkg/pkg.rb
CHANGED
@@ -60,7 +60,7 @@ class TestModuleProjectInfo < Test::Unit::TestCase
|
|
60
60
|
def test_module_GoobyProjectInfo_project_version_number
|
61
61
|
|
62
62
|
obj = Gooby::GoobyObject.new
|
63
|
-
assert_equal '0.9.
|
63
|
+
assert_equal '0.9.4', obj.project_version_number
|
64
64
|
end
|
65
65
|
|
66
66
|
def test_module_GoobyProjectInfo_project_year
|