Simple gpx export from ridewithgps
Dima Kogan
<p>
The <a href="https://tourdelospadres.weebly.com/">Tour de Los Padres</a> is coming! The race organizer post <a href="https://ridewithgps.com/routes/54493422">the route on
ridewithgps</a>. This works, but has convoluted interfaces for people not wanting to
use their service. I just wrote a simple script to export their data into a
plain .gpx file, <i>including</i> all the waypoints; their exporter omits those.
</p>
<p>
I've seen two flavors of their data, so here're two flavors of the
<code>gpx-from-ridewithgps.py</code> script:
</p>
<div class="org-src-container">
<pre class="src src-python"><span style="color: #cdcd00;">#</span><span style="color: #cdcd00;">!/usr/bin/python3</span>
<span style="color: #00cdcd; font-weight: bold;">import</span> sys
<span style="color: #00cdcd; font-weight: bold;">import</span> json
<span style="color: #00cdcd; font-weight: bold;">def</span> <span style="color: #0000ee; font-weight: bold;">quote_xml</span>(s):
<span style="color: #00cdcd; font-weight: bold;">return</span> s.replace(<span style="color: #00cd00;">"&"</span>, <span style="color: #00cd00;">"&amp;"</span>).replace(<span style="color: #00cd00;">"<"</span>, <span style="color: #00cd00;">"&lt;"</span>).replace(<span style="color: #00cd00;">">"</span>, <span style="color: #00cd00;">"&gt;"</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">"Reading stdin"</span>, <span style="color: #0000ee; font-weight: bold;">file</span>=sys.stderr)
<span style="color: #cdcd00;">data</span> = json.load(sys.stdin)
<span style="color: #00cdcd; font-weight: bold;">print</span>(r<span style="color: #00cd00;">"""<?xml version="1.0" encoding="UTF-8"?></span>
<span style="color: #00cd00;"><gpx version="1.1" creator="gpx-from-ridewithgps.py" xmlns="http://www.topografix.com/GPX/1/1">"""</span>)
<span style="color: #00cdcd; font-weight: bold;">for</span> item <span style="color: #00cdcd; font-weight: bold;">in</span> data[<span style="color: #00cd00;">"extras"</span>]:
<span style="color: #00cdcd; font-weight: bold;">if</span> item[<span style="color: #00cd00;">"type"</span>] != <span style="color: #00cd00;">"point_of_interest"</span>:
<span style="color: #00cdcd; font-weight: bold;">continue</span>
<span style="color: #cdcd00;">poi</span> = item[<span style="color: #00cd00;">"point_of_interest"</span>]
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <wpt lat="{poi["lat"]}" lon="{poi["lng"]}">'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <name>{quote_xml(poi["name"])}</name>'</span>)
<span style="color: #cdcd00;">desc</span> = poi.get(<span style="color: #00cd00;">"description"</span>,<span style="color: #00cd00;">""</span>)
<span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #0000ee; font-weight: bold;">len</span>(desc):
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <desc>{quote_xml(desc)}</desc>'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' </wpt>'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">" <trk><trkseg>"</span>)
<span style="color: #00cdcd; font-weight: bold;">for</span> pt <span style="color: #00cdcd; font-weight: bold;">in</span> data.get(<span style="color: #00cd00;">"route"</span>, {}).get(<span style="color: #00cd00;">"track_points"</span>, []):
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <trkpt lat="{pt["y"]}" lon="{pt["x"]}"><ele>{pt["e"]}</ele></trkpt>'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">" </trkseg></trk>"</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">"</gpx>"</span>)
</pre>
</div>
<div class="org-src-container">
<pre class="src src-python"><span style="color: #cdcd00;">#</span><span style="color: #cdcd00;">!/usr/bin/python3</span>
<span style="color: #00cdcd; font-weight: bold;">import</span> sys
<span style="color: #00cdcd; font-weight: bold;">import</span> json
<span style="color: #00cdcd; font-weight: bold;">def</span> <span style="color: #0000ee; font-weight: bold;">quote_xml</span>(s):
<span style="color: #00cdcd; font-weight: bold;">return</span> s.replace(<span style="color: #00cd00;">"&"</span>, <span style="color: #00cd00;">"&amp;"</span>).replace(<span style="color: #00cd00;">"<"</span>, <span style="color: #00cd00;">"&lt;"</span>).replace(<span style="color: #00cd00;">">"</span>, <span style="color: #00cd00;">"&gt;"</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">"Reading stdin"</span>, <span style="color: #0000ee; font-weight: bold;">file</span>=sys.stderr)
<span style="color: #cdcd00;">data</span> = json.load(sys.stdin)
<span style="color: #00cdcd; font-weight: bold;">print</span>(r<span style="color: #00cd00;">"""<?xml version="1.0" encoding="UTF-8"?></span>
<span style="color: #00cd00;"><gpx version="1.1" creator="gpx-from-ridewithgps.py" xmlns="http://www.topografix.com/GPX/1/1">"""</span>)
<span style="color: #00cdcd; font-weight: bold;">for</span> poi <span style="color: #00cdcd; font-weight: bold;">in</span> data[<span style="color: #00cd00;">"points_of_interest"</span>]:
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <wpt lat="{poi["lat"]}" lon="{poi["lng"]}">'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <name>{quote_xml(poi["name"])}</name>'</span>)
<span style="color: #cdcd00;">desc</span> = poi.get(<span style="color: #00cd00;">"description"</span>,<span style="color: #00cd00;">""</span>)
<span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #0000ee; font-weight: bold;">len</span>(desc):
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <desc>{quote_xml(desc)}</desc>'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' </wpt>'</span>)
<span style="color: #00cdcd; font-weight: bold;">for</span> poi <span style="color: #00cdcd; font-weight: bold;">in</span> data[<span style="color: #00cd00;">"course_points"</span>]:
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <wpt lat="{poi["y"]}" lon="{poi["x"]}">'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <name>{quote_xml(poi["n"])}</name>'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' </wpt>'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">" <trk><trkseg>"</span>)
<span style="color: #00cdcd; font-weight: bold;">for</span> pt <span style="color: #00cdcd; font-weight: bold;">in</span> data[<span style="color: #00cd00;">'track_points'</span>]:
<span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">' <trkpt lat="{pt["y"]}" lon="{pt["x"]}"><ele>{pt["e"]}</ele></trkpt>'</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">" </trkseg></trk>"</span>)
<span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">"</gpx>"</span>)
</pre>
</div>
<p>
You invoke it by downloading the route and feeding it into the script:
</p>
<div class="org-src-container">
<pre class="src src-sh">curl -s https://ridewithgps.com/routes/54493422.json | ./ridewithgps-to-gpx.py > out.gpx
</pre>
</div>
<p>
Note that the route number 54493422 is in the url above.</p>