Last active
August 29, 2015 14:21
-
-
Save baylej/31cf3bd3ee49dc250756 to your computer and use it in GitHub Desktop.
Python script to export paragliding sites in France to a KML file (for Google Earth)
This file contains 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
# -*- coding: utf-8 -*- | |
code_to_name = dict({ | |
'01': "Ain", | |
'02': "Aisne", | |
'03': "Allier", | |
'04': "Alpes-de-Haute-Provence", | |
'05': "Hautes-Alpes", | |
'06': "Alpes-Maritimes", | |
'07': "Ardèche", | |
'08': "Ardennes", | |
'09': "Ariège", | |
'10': "Aube", | |
'11': "Aude", | |
'12': "Aveyron", | |
'13': "Bouches-du-Rhône", | |
'14': "Calvados", | |
'15': "Cantal", | |
'16': "Charente", | |
'17': "Charente-Maritime", | |
'18': "Cher", | |
'19': "Corrèze", | |
'2A': "Corse-du-Sud", | |
'2B': "Haute-Corse", | |
'20': "Corse", | |
'21': "Côte-d'Or", | |
'22': "Côtes-d'Armor", | |
'23': "Creuse", | |
'24': "Dordogne", | |
'25': "Doubs", | |
'26': "Drôme", | |
'27': "Eure", | |
'28': "Eure-et-Loir", | |
'29': "Finistère", | |
'30': "Gard", | |
'31': "Haute-Garonne", | |
'32': "Gers", | |
'33': "Gironde", | |
'34': "Hérault", | |
'35': "Ille-et-Vilaine", | |
'36': "Indre", | |
'37': "Indre-et-Loire", | |
'38': "Isère", | |
'39': "Jura", | |
'40': "Landes", | |
'41': "Loir-et-Cher", | |
'42': "Loire", | |
'43': "Haute-Loire", | |
'44': "Loire-Atlantique", | |
'45': "Loiret", | |
'46': "Lot", | |
'47': "Lot-et-Garonne", | |
'48': "Lozère", | |
'49': "Maine-et-Loire", | |
'50': "Manche", | |
'51': "Marne", | |
'52': "Haute-Marne", | |
'53': "Mayenne", | |
'54': "Meurthe-et-Moselle", | |
'55': "Meuse", | |
'56': "Morbihan", | |
'57': "Moselle", | |
'58': "Nièvre", | |
'59': "Nord", | |
'60': "Oise", | |
'61': "Orne", | |
'62': "Pas-de-Calais", | |
'63': "Puy-de-Dôme", | |
'64': "Pyrénées-Atlantiques", | |
'65': "Hautes-Pyrénées", | |
'66': "Pyrénées-Orientales", | |
'67': "Bas-Rhin", | |
'68': "Haut-Rhin", | |
'69': "Rhône", | |
'70': "Haute-Saône", | |
'71': "Saône-et-Loire", | |
'72': "Sarthe", | |
'73': "Savoie", | |
'74': "Haute-Savoie", | |
'75': "Paris", | |
'76': "Seine-Maritime", | |
'77': "Seine-et-Marne", | |
'78': "Yvelines", | |
'79': "Deux-Sèvres", | |
'80': "Somme", | |
'81': "Tarn", | |
'82': "Tarn-et-Garonne", | |
'83': "Var", | |
'84': "Vaucluse", | |
'85': "Vendée", | |
'86': "Vienne", | |
'87': "Haute-Vienne", | |
'88': "Vosges", | |
'89': "Yonne", | |
'90': "Territoire de Belfort", | |
'91': "Essonne", | |
'92': "Hauts-de-Seine", | |
'93': "Seine-Saint-Denis", | |
'94': "Val-de-Marne", | |
'95': "Val-d'Oise", | |
'97': "Département d'Outre-Mer", | |
'971': "Guadeloupe", | |
'972': "Martinique", | |
'973': "Guyane", | |
'974': "La Réunion", | |
'975': "Saint-Pierre-et-Miquelon", | |
'976': "Mayotte", | |
'977': "Saint-Barthélemy", | |
'978': "Saint-Martin", | |
'98': "Collectivités d'Outre-Mer", | |
'986': "Wallis-et-Futuna", | |
'987': "Polynésie Française", | |
'988': "Nouvelle-Calédonie" | |
}) |
This file contains 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
# -*- coding: utf-8 -*- | |
from urllib.request import urlopen | |
from xml.parsers import expat | |
import france_departements | |
class KMLBuilder: | |
""" Builds the KML document. """ | |
__spc_c = 2 | |
__spc_l = 2 | |
__is_built = False | |
__document = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
def __init__(self, name): | |
self.__document += "<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\" xmlns:kml=\"http://www.opengis.net/kml/2.2\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n" | |
self.__document += "<Document>\n" | |
self.__document += self.__spc_c*' ' + "<name>" + name +"</name>\n" | |
def enter_folder(self, name, desc=None): | |
self.__chk_built() | |
self.__document += self.__spc_c*' ' + "<Folder>\n" | |
self.__spc_c += self.__spc_l | |
self.__document += self.__spc_c*' ' + "<name>" + name + "</name>\n" | |
if desc is not None: | |
self.__document += self.__spc_c*' ' + " <description>" + desc + "</description>\n" | |
def close_folder(self): | |
self.__chk_built() | |
self.__spc_c -= self.__spc_l | |
self.__document += self.__spc_c*' ' + "</Folder>\n" | |
def mk_placemark(self, name, lon, lat, alt, desc=None): | |
self.__chk_built() | |
self.__document += self.__spc_c*' ' + "<Placemark>\n" | |
self.__document += self.__spc_c*' ' + " <name>" + name + "</name>\n" | |
self.__document += self.__spc_c*' ' + " <Point>\n" | |
self.__document += self.__spc_c*' ' + " <coordinates>" + str(lon) + ',' + str(lat) +',' + str(alt) + "</coordinates>\n" | |
self.__document += self.__spc_c*' ' + " </Point>\n" | |
if desc is not None: | |
self.__document += self.__spc_c*' ' + " <description>" + desc + "</description>\n" | |
self.__document += self.__spc_c*' ' + "</Placemark>\n" | |
def build(self): | |
if self.__spc_c != 2: | |
raise Exception("Unclosed folders") | |
self.__is_built = True | |
self.__document += "</Document>\n" | |
self.__document += "</kml>\n" | |
return self.__document | |
def __chk_built(self): | |
if self.__is_built == True: | |
raise Exception("this instance has already been built"); | |
# DOWNLOAD TEH DATA | |
takeoffs_url = "http://carte.ffvl.fr/xml/sites/decollages.xml" | |
landings_url = "http://carte.ffvl.fr/xml/sites/atterrissages.xml" | |
viewsite_url = "http://federation.ffvl.fr/sites_pratique/voir/" | |
takeoffs = urlopen(takeoffs_url).read() | |
landings = urlopen(landings_url).read() | |
# PARSE THE DATA | |
class Spot: | |
ident = 0 | |
dept = None | |
lat = 0 | |
lon = 0 | |
alt = 0 | |
name = str() | |
spots_per_dept = dict() | |
is_name = False | |
current_spot = None | |
def start_element(name, attrs): | |
global current_spot | |
global is_name | |
if name == "site": | |
current_spot = Spot() | |
if name == "nom": | |
is_name = True | |
if name == "codepostal": | |
try: | |
current_spot.dept = attrs['value'][:2] | |
# handling DOM-TOMs names | |
if int(current_spot.dept) >= 97: | |
current_spot.dept = attrs['value'][:3] | |
except: | |
pass | |
if name == "altitude": | |
current_spot.alt = int(attrs['value']) | |
if name == "coord": | |
current_spot.lon = float(attrs['lon']) | |
current_spot.lat = float(attrs['lat']) | |
if name == "id": | |
current_spot.ident = int(attrs['value']) | |
def end_element(name): | |
global current_spot | |
global is_name | |
global spots | |
if name == "nom": | |
is_name = False | |
if name == "site": | |
if str(current_spot.dept) not in spots_per_dept: | |
spots_per_dept[str(current_spot.dept)] = dict() | |
spots = spots_per_dept[str(current_spot.dept)] | |
if str(current_spot.ident) not in spots: | |
spots[str(current_spot.ident)] = [] | |
spots[str(current_spot.ident)].append(current_spot) | |
# CAUTION: expat splits on escaped characters (eg: &x#22;) | |
def char_data(data): | |
global current_spot | |
global is_name | |
if is_name == True: | |
current_spot.name += data.strip() | |
parser = expat.ParserCreate() | |
parser.StartElementHandler = start_element | |
parser.EndElementHandler = end_element | |
parser.CharacterDataHandler = char_data | |
parser.Parse(takeoffs) | |
parser = expat.ParserCreate() | |
parser.StartElementHandler = start_element | |
parser.EndElementHandler = end_element | |
parser.CharacterDataHandler = char_data | |
parser.Parse(landings) | |
# BUILD THE KML | |
doc = KMLBuilder("Paragliding Spots in France") | |
for dept in spots_per_dept: | |
spots = spots_per_dept[dept] | |
if dept == None or dept == '': | |
doc.enter_folder("Unknown") | |
else: | |
doc.enter_folder(france_departements.code_to_name[dept]) | |
for site_id in spots.keys(): | |
if spots[site_id][0].name != None and spots[site_id][0].name != '': | |
doc.enter_folder(spots[site_id][0].name) | |
else: | |
doc.enter_folder("Unnamed site") | |
for site in spots[site_id]: | |
doc.mk_placemark(site.name, site.lon, site.lat, site.alt, viewsite_url + str(site.ident)) | |
doc.close_folder() | |
doc.close_folder() | |
# OUTPUT | |
file = open("France_paragliding_spots.kml", "w", encoding="utf-8") | |
file.write(doc.build()) | |
file.flush() | |
file.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment