merge.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. Created on Fri Nov 1 20:13:02 2019
  5. @author: sebastianw
  6. """
  7. import argparse
  8. import csv
  9. import json
  10. import xmltodict
  11. class HashableDict(dict):
  12. def __hash__(self):
  13. return hash(json.dumps(self, sort_keys=True))
  14. def read_data(*files):
  15. data = set()
  16. for file in files:
  17. for element in xmltodict.parse(file.read())['gpx']['wpt']:
  18. data.add(HashableDict(element))
  19. data = sorted(data, key=lambda x: float(x['@lat']) + float(x['@lon']))
  20. categories = {}
  21. for wpt in data:
  22. if 'extensions' not in wpt:
  23. continue
  24. categories[wpt['type']] = wpt['extensions']['color']
  25. del wpt['extensions']
  26. return data, categories
  27. def write_csv(data, categories, csvfile, categoriesfile):
  28. fieldnames = ['@lat', '@lon', 'name', 'cmt', 'desc', 'type']
  29. writer = csv.DictWriter(csvfile, fieldnames)
  30. writer.writeheader()
  31. writer.writerows(data)
  32. json.dump(categories, categoriesfile,
  33. sort_keys=True, indent=True)
  34. def read_csv(handle):
  35. return list(csv.DictReader(handle))
  36. def write_gpx(data, colors, handle):
  37. handle.write("""<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
  38. <gpx version="1.1" creator="OsmAnd+ 3.4.8" 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">
  39. <metadata>
  40. <name>favourites</name>
  41. </metadata>
  42. """)
  43. for wpt in data:
  44. handle.write(f""" <wpt lat="{wpt['@lat']}" lon="{wpt['@lon']}">
  45. <name>{wpt['name']}</name>
  46. <type>{wpt['type']}</type>
  47. <cmt>{wpt['cmt']}</cmt>
  48. <extensions>
  49. <color>{colors[wpt['type']]}</color>
  50. </extensions>
  51. </wpt>\n""")
  52. handle.write('</gpx>')
  53. def gpx2csv(args):
  54. data, categories = read_data(*args.gpxfiles)
  55. write_csv(data, categories, args.outfile, args.categories)
  56. def csv2gpx(args):
  57. data = read_csv(args.infile)
  58. categories = json.load(args.categories)
  59. write_gpx(data, categories, args.outfile)
  60. if __name__ == '__main__':
  61. parser = argparse.ArgumentParser('gpx-favourites-merge')
  62. subparsers = parser.add_subparsers()
  63. gpx2csvp = subparsers.add_parser('gpx2csv')
  64. gpx2csvp.add_argument('gpxfiles', nargs="+", type=argparse.FileType('r'))
  65. gpx2csvp.add_argument('outfile', type=argparse.FileType('w'))
  66. gpx2csvp.add_argument('categories', type=argparse.FileType('w'))
  67. gpx2csvp.set_defaults(func=gpx2csv)
  68. csv2gpxp = subparsers.add_parser('csv2gpx')
  69. csv2gpxp.add_argument('infile', type=argparse.FileType('r'))
  70. csv2gpxp.add_argument('categories', type=argparse.FileType('r'))
  71. csv2gpxp.add_argument('outfile', type=argparse.FileType('w'))
  72. csv2gpxp.set_defaults(func=csv2gpx)
  73. args = parser.parse_args()
  74. args.func(args)