Created
July 15, 2025 07:18
-
-
Save grigory-rechistov/a710da006e157c3da56f3b65bec8fc37 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| import sys | |
| import json | |
| from html.parser import HTMLParser | |
| import re | |
| gpx_template = """<?xml version='1.0' encoding='UTF-8'?> | |
| <gpx version="1.1" | |
| creator="skookum" | |
| xmlns="http://www.topografix.com/GPX/1/1" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xsi:schemaLocation="http://www.topografix.com/GPX/1/1 | |
| http://www.topografix.com/GPX/1/1/gpx.xsd"> | |
| <trk> | |
| <name>%s</name> | |
| <trkseg> | |
| %s</trkseg> | |
| </trk> | |
| </gpx> | |
| """ | |
| trkpt_template = '<trkpt lat="%s" lon="%s"></trkpt>\n' | |
| class TrailforksParser(HTMLParser): | |
| def __init__(self): | |
| super().__init__() | |
| self.points = list() | |
| self.title = "Trail" | |
| def handle_starttag(self, tag, attrs): | |
| if tag == "meta": | |
| d = dict(attrs) | |
| if d.get('property', None) == "og:title": | |
| self.title = d.get('content', self.title) | |
| def find_sections_with_points(self, data: str): | |
| for line in data.split("\n"): # assume 'sections:" is on its own line | |
| m = re.match(r'\s*sections: \[(.*)\],\s*$', line) | |
| if m: | |
| return m.group(1) | |
| assert False, "Found no sections variable" | |
| def handle_data(self, data): | |
| if 'sections:' in data: | |
| # print("Encountered some data :", data) | |
| sections = self.find_sections_with_points(data) | |
| d = json.loads(sections) | |
| text_points = d['points'] | |
| self.points += self.extract_point_pairs(text_points) | |
| def extract_point_pairs(self, text_points: dict) -> list[str, str]: | |
| return ((elem['lat'], elem['lng']) for elem in text_points) | |
| def form_gpx(self) -> str: | |
| trkpoints = "".join((trkpt_template % entry) for entry in self.points) | |
| gpx_text = gpx_template % (self.title, trkpoints) | |
| return gpx_text | |
| def main(argv): | |
| parser = TrailforksParser() | |
| with open(sys.argv[1]) as f: | |
| parser.feed(f.read()) | |
| assert len(parser.points), "Collected GPX points are empty" | |
| return parser.form_gpx() | |
| if __name__ == "__main__": | |
| print(main(sys.argv[1])) | |
| sys.exit(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment