2 # -*- coding: iso-8859-15 -*-
5 """This module contains winterrodeln specific functions that are prcocessing the MediaWiki markup.
8 import xml.etree.ElementTree
10 import wrpylib.wrvalidators
11 import wrpylib.mwmarkup
13 WRMAP_POINT_TYPES = ['gasthaus', 'haltestelle', 'parkplatz', 'achtung', 'punkt']
14 WRMAP_LINE_TYPES = ['rodelbahn', 'gehweg', 'alternative', 'lift', 'anfahrt', 'linie']
17 class ParseError(RuntimeError):
18 """Exception used by some of the functions"""
22 def _conv(fnct, value, fieldname):
24 Like one of the to_xxx functions (e.g. to_bool), but adds the field name to the error message"""
25 try: return fnct(value)
26 except formencode.Invalid as e: raise formencode.Invalid(u"Conversion error in field '%s': %s" % (fieldname, unicode(e)), e.value, e.state)
29 def rodelbahnbox_to_sledrun(wikitext, sledrun=None):
30 """Converts a sledrun wiki page containing the {{Rodelbahnbox}}
31 to a sledrun. sledrun may be an instance of WrSledrunCache or an "empty" class (object()) (default).
32 Raises a formencode.Invalid exception if the format is not OK or the Rodelbahnbox is not found.
33 :return: (start, end, sledrun) tuple of the Rodelbahnbox."""
35 class Sledrun(object): pass
39 start, end = wrpylib.mwmarkup.find_template(wikitext, u'Rodelbahnbox')
40 if start is None: raise formencode.Invalid(u"Rodelbahnbox nicht gefunden", wikitext, None)
41 template_title, properties = wrpylib.mwmarkup.split_template(wikitext[start:end])
44 for key, value in properties.iteritems():
45 if key == u'Position': sledrun.position_latitude, sledrun.position_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
46 elif key == u'Position oben': sledrun.top_latitude, sledrun.top_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
47 elif key == u'Höhe oben': sledrun.top_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # '2000'
48 elif key == u'Position unten': sledrun.bottom_latitude, sledrun.bottom_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
49 elif key == u'Höhe unten': sledrun.bottom_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # '1200'
50 elif key == u'Länge': sledrun.length = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # 3500
51 elif key == u'Schwierigkeit': sledrun.difficulty = _conv(wrpylib.wrvalidators.GermanDifficulty().to_python, value, key) # 'mittel' elif key == u'Lawinen': sledrun.avalanches = _conv(wrpylib.wrvalidators.GermanAvalanches().to_python, value, key) # 'kaum'
52 elif key == u'Lawinen': sledrun.avalanches = _conv(wrpylib.wrvalidators.GermanAvalanches().to_python, value, key) # 'kaum'
53 elif key == u'Betreiber': sledrun.operator = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key) # 'Max Mustermann'
54 elif key == u'Öffentliche Anreise': sledrun.public_transport = _conv(wrpylib.wrvalidators.GermanPublicTransport().to_python, value, key) # 'Mittelmäßig'
55 elif key == u'Aufstieg möglich': sledrun.walkup_possible = _conv(wrpylib.wrvalidators.GermanBoolNone().to_python, value, key) # 'Ja'
56 elif key == u'Aufstieg getrennt': sledrun.walkup_separate, sledrun.walkup_separate_comment = _conv(wrpylib.wrvalidators.GermanTristateFloatComment().to_python, value, key) # 'Ja'
57 elif key == u'Gehzeit': sledrun.walkup_time = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # 90
58 elif key == u'Aufstiegshilfe': sledrun.lift, sledrun.lift_details = _conv(wrpylib.wrvalidators.GermanLift().to_python, value, key) # 'Gondel (unterer Teil)'
59 elif key == u'Beleuchtungsanlage': sledrun.night_light, sledrun.night_light_comment = _conv(wrpylib.wrvalidators.GermanTristateFloatComment().to_python, value, key)
60 elif key == u'Beleuchtungstage': sledrun.night_light_days, sledrun.night_light_days_comment = _conv(wrpylib.wrvalidators.UnsignedCommentNone(7).to_python, value, key) # '3 (Montag, Mittwoch, Freitag)'
61 elif key == u'Rodelverleih': sledrun.sled_rental, sledrun.sled_rental_comment = _conv(wrpylib.wrvalidators.SledRental().to_python, value, key) # 'Talstation Serlesbahnan'
62 elif key == u'Gütesiegel': sledrun.cachet = _conv(wrpylib.wrvalidators.GermanCachet().to_python, value, key) # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
63 elif key == u'Webauskunft': sledrun.information_web = _conv(wrpylib.wrvalidators.UrlNeinNone().to_python, value, key) # 'http://www.nösslachhütte.at/page9.php'
64 elif key == u'Telefonauskunft': sledrun.information_phone = _conv(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=False).to_python, value, key) # '+43-664-5487520 (Mitterer Alm)'
65 elif key == u'Bild': sledrun.image = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
66 elif key == u'In Übersichtskarte': sledrun.show_in_overview = _conv(wrpylib.wrvalidators.GermanBoolNone().to_python, value, key)
67 elif key == u'Forumid': sledrun.forum_id = _conv(wrpylib.wrvalidators.UnsignedNeinNone().to_python, value, key)
68 else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Rodelbahnbox: '%s' (mit Wert '%s')" % (key, value), value, None)
69 return start, end, sledrun
72 def sledrun_to_rodelbahnbox(sledrun, version):
73 """Converts a sledrun class to the {{Rodelbahnbox}} representation.
74 The sledrun class has to have properties like position_latitude, ...
75 See the table sledruncache for field (column) values.
76 :param sledrun: an arbitrary class that contains the right properties
77 :param version: a string specifying the version of the rodelbahnbox zu produce.
78 Version '1.3' and '1.4' are supported."""
81 keys.append(u'Position')
82 values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.position_latitude, sledrun.position_longitude)))
83 keys.append(u'Position oben')
84 values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.top_latitude, sledrun.top_longitude)))
85 keys.append(u'Höhe oben')
86 values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.top_elevation))
87 keys.append(u'Position unten')
88 values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.bottom_latitude, sledrun.bottom_longitude)))
89 keys.append(u'Höhe unten')
90 values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.bottom_elevation))
92 values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.length))
93 keys.append(u'Schwierigkeit')
94 values.append(wrpylib.wrvalidators.GermanDifficulty().from_python(sledrun.difficulty))
95 keys.append(u'Lawinen')
96 values.append(wrpylib.wrvalidators.GermanAvalanches().from_python(sledrun.avalanches))
97 keys.append(u'Betreiber')
98 values.append(wrpylib.wrvalidators.UnicodeNone().from_python(sledrun.operator))
99 keys.append(u'Öffentliche Anreise')
100 values.append(wrpylib.wrvalidators.GermanPublicTransport().from_python(sledrun.public_transport))
102 keys.append(u'Aufstieg möglich')
103 values.append(wrpylib.wrvalidators.GermanBoolNone().from_python(sledrun.walkup_possible))
104 keys.append(u'Aufstieg getrennt')
105 values.append(wrpylib.wrvalidators.GermanTristateFloatComment().from_python((sledrun.walkup_separate, sledrun.walkup_separate_comment)))
106 keys.append(u'Gehzeit')
107 values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.walkup_time))
108 keys.append(u'Aufstiegshilfe')
109 values.append(wrpylib.wrvalidators.GermanLift().from_python((sledrun.lift, sledrun.lift_details)))
110 keys.append(u'Beleuchtungsanlage')
111 values.append(wrpylib.wrvalidators.GermanTristateFloatComment().from_python((sledrun.night_light, sledrun.night_light_comment)))
112 keys.append(u'Beleuchtungstage')
113 values.append(wrpylib.wrvalidators.UnsignedCommentNone(max=7).from_python((sledrun.night_light_days, sledrun.night_light_days_comment)))
114 keys.append(u'Rodelverleih')
115 values.append(wrpylib.wrvalidators.SledRental().from_python((sledrun.sled_rental, sledrun.sled_rental_comment)))
116 keys.append(u'Gütesiegel')
117 values.append(wrpylib.wrvalidators.GermanCachet().from_python(sledrun.cachet))
118 keys.append(u'Webauskunft')
119 values.append(wrpylib.wrvalidators.UrlNeinNone().from_python(sledrun.information_web))
120 keys.append(u'Telefonauskunft')
121 values.append(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=False).from_python(sledrun.information_phone))
123 values.append(wrpylib.wrvalidators.UnicodeNone().from_python(sledrun.image))
124 keys.append(u'In Übersichtskarte')
125 values.append(wrpylib.wrvalidators.GermanBoolNone().from_python(sledrun.show_in_overview))
126 keys.append(u'Forumid')
127 values.append(wrpylib.wrvalidators.UnsignedNeinNone().from_python(sledrun.forum_id))
128 return wrpylib.mwmarkup.create_template(u'Rodelbahnbox', [], keys, values, True, 20)
131 def gasthausbox_to_inn(wikitext, inn=None):
132 """Converts a inn wiki page containing a {{Gasthausbox}} to an inn.
133 raises a formencode.Invalid exception if an error occurs.
134 :return: (start, end, inn) tuple."""
136 class Inn(object): pass
140 start, end = wrpylib.mwmarkup.find_template(wikitext, u'Gasthausbox')
141 if start is None: raise formencode.Invalid(u"No 'Gasthausbox' found", wikitext, None)
142 template_title, properties = wrpylib.mwmarkup.split_template(wikitext[start:end])
145 for key, value in properties.iteritems():
146 if key == u'Position': inn.position_latitude, inn.position_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
147 elif key == u'Höhe': inn.position_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key)
148 elif key == u'Betreiber': inn.operator = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
149 elif key == u'Sitzplätze': inn.seats = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key)
150 elif key == u'Übernachtung': inn.overnight, inn.overnight_comment = _conv(wrpylib.wrvalidators.BoolUnicodeTupleValidator().to_python, value, key)
151 elif key == u'Rauchfrei': inn.nonsmoker_area, inn.smoker_area = _conv(wrpylib.wrvalidators.GermanTristateTuple().to_python, value, key)
152 elif key == u'Rodelverleih': inn.sled_rental, inn.sled_rental_comment = _conv(wrpylib.wrvalidators.BoolUnicodeTupleValidator().to_python, value, key)
153 elif key == u'Handyempfang': inn.mobile_provider = _conv(wrpylib.wrvalidators.ValueCommentListNeinLoopNone().to_python, value, key)
154 elif key == u'Homepage': inn.homepage = _conv(wrpylib.wrvalidators.UrlNeinNone().to_python, value, key)
155 elif key == u'E-Mail': inn.email_list = _conv(wrpylib.wrvalidators.EmailCommentListNeinLoopNone(allow_masked_email=True).to_python, value, key)
156 elif key == u'Telefon': inn.phone_list = _conv(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=True).to_python, value, key)
157 elif key == u'Bild': inn.image = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
158 elif key == u'Rodelbahnen': inn.sledding_list = _conv(wrpylib.wrvalidators.WikiPageListLoopNone().to_python, value, key)
159 else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Gasthausbox: '%s' (mit Wert '%s')" % (key, value), value, None)
160 return start, end, inn
163 def inn_to_gasthausbox(inn):
164 """Converts the inn class to the {{Gasthausbox}} representation."""
167 keys.append(u'Position')
168 values.append(wrpylib.wrvalidators.GeoNone().from_python((inn.position_latitude, inn.position_longitude)))
170 values.append(wrpylib.wrvalidators.UnsignedNone().from_python(inn.position_elevation))
171 keys.append(u'Betreiber')
172 values.append(wrpylib.wrvalidators.UnicodeNone().from_python(inn.operator))
173 keys.append(u'Sitzplätze')
174 values.append(wrpylib.wrvalidators.UnsignedNone().from_python(inn.seats))
175 keys.append(u'Übernachtung')
176 values.append(wrpylib.wrvalidators.BoolUnicodeTupleValidator().from_python((inn.overnight, inn.overnight_comment)))
177 keys.append(u'Rauchfrei')
178 values.append(wrpylib.wrvalidators.GermanTristateTuple().from_python((inn.nonsmoker_area, inn.smoker_area)))
179 keys.append(u'Rodelverleih')
180 values.append(wrpylib.wrvalidators.BoolUnicodeTupleValidator().from_python((inn.sled_rental, inn.sled_rental_comment)))
181 keys.append(u'Handyempfang')
182 values.append(wrpylib.wrvalidators.ValueCommentListNeinLoopNone().from_python(inn.mobile_provider))
183 keys.append(u'Homepage')
184 values.append(wrpylib.wrvalidators.UrlNeinNone().from_python(inn.homepage))
185 keys.append(u'E-Mail')
186 values.append(wrpylib.wrvalidators.EmailCommentListNeinLoopNone(allow_masked_email=True).from_python(inn.email_list))
187 keys.append(u'Telefon')
188 values.append(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=True).from_python(inn.phone_list))
190 values.append(wrpylib.wrvalidators.UnicodeNone().from_python(inn.image))
191 keys.append(u'Rodelbahnen')
192 values.append(wrpylib.wrvalidators.WikiPageListLoopNone().from_python(inn.sledding_list))
193 result = [u'{{Gasthausbox']
194 return wrpylib.mwmarkup.create_template(u'Gasthausbox', [], keys, values, True)
197 def find_template_latlon_ele(wikitext, template_title):
198 """Finds the first occurance of the '{{template_title|47.076207 N 11.453553 E|1890}}' template
199 and returns the tuple (start, end, lat, lon, ele) or (None, None, None, None, None) if the
200 template was not found. If the template has no valid format, an exception is thrown."""
201 start, end = wrpylib.mwmarkup.find_template(wikitext, template_title)
202 if start is None: return (None,) * 5
203 title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
204 lat, lon = wrpylib.wrvalidators.GeoNone().to_python(params[u'1'].strip())
205 ele = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'2'].strip())
206 return start, end, lat, lon, ele
209 def create_template_latlon_ele(template_title, lat, lon, ele):
210 geo = wrpylib.wrvalidators.GeoNone().from_python((lat, lon))
211 if len(geo) == 0: geo = u' '
212 ele = wrpylib.wrvalidators.UnsignedNone().from_python(ele)
213 if len(ele) == 0: ele = u' '
214 return wrpylib.mwmarkup.create_template(template_title, [geo, ele])
217 def find_template_PositionOben(wikitext):
218 """Same as find_template_latlon_ele with template '{{Position oben|47.076207 N 11.453553 E|1890}}'"""
219 return find_template_latlon_ele(wikitext, u'Position oben')
222 def create_template_PositionOben(lat, lon, ele):
223 return create_template_latlon_ele(u'Position, oben', lat, lon, ele)
226 def find_template_PositionUnten(wikitext):
227 """Same as find_template_latlon_ele with template '{{Position unten|47.076207 N 11.453553 E|1890}}'"""
228 return find_template_latlon_ele(wikitext, u'Position unten')
231 def find_template_unsigned(wikitext, template_title):
232 """Finds the first occurance of the '{{template_title|1890}}' template
233 and returns the tuple (start, end, unsigned_value) or (None, None, None) if the
234 template was not found. If the template has no valid format, an exception is thrown."""
235 start, end = wrpylib.mwmarkup.find_template(wikitext, template_title)
236 if start is None: return (None,) * 3
237 title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
238 unsigned_value = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'1'].strip())
239 return start, end, unsigned_value
242 def create_template_unsigned(template_title, unsigned):
243 unsigned = wrpylib.wrvalidators.UnsignedNone().from_python(unsigned)
244 if len(unsigned) == 0: unsigned = u' '
245 return wrpylib.mwmarkup.create_template(template_title, [unsigned])
248 def find_template_Hoehenunterschied(wikitext):
249 """Same as find_template_unsigned with template '{{Höhenunterschied|350}}'"""
250 return find_template_unsigned(wikitext, u'Höhenunterschied')
253 def create_template_Hoehenunterschied(ele_diff):
254 return create_template_unsigned(u'Höhenunterschied', ele_diff)
257 def find_template_Bahnlaenge(wikitext):
258 """Same as find_template_unsigned with template '{{Bahnlänge|4500}}'"""
259 return find_template_unsigned(wikitext, u'Bahnlänge')
262 def create_template_Bahnlaenge(length):
263 return create_template_unsigned(u'Bahnlänge', length)
266 def find_template_Gehzeit(wikitext):
267 """Same as find_template_unsigned with template '{{Gehzeit|60}}'"""
268 return find_template_unsigned(wikitext, u'Gehzeit')
271 def create_template_Gehzeit(walkup_time):
272 return create_template_unsigned(u'Gehzeit', walkup_time)
275 def find_template_Forumlink(wikitext):
276 """Same as find_template_unsigned with template '{{Forumlink|26}}'"""
277 start, end = wrpylib.mwmarkup.find_template(wikitext, u'Forumlink')
278 if start is None: return (None,) * 3
279 title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
280 forumid = params[u'1'].strip()
281 if forumid == u'<nummer einfügen>': unsigned_value = None
282 else: unsigned_value = wrpylib.wrvalidators.UnsignedNone().to_python(forumid)
283 return start, end, unsigned_value
284 # return find_template_unsigned(wikitext, u'Forumlink')
287 def find_template_Parkplatz(wikitext):
288 """Same as find_template_latlon_ele with template '{{Parkplatz|47.076207 N 11.453553 E|1890}}'"""
289 return find_template_latlon_ele(wikitext, u'Parkplatz')
292 def find_template_Haltestelle(wikitext):
293 """Finds the first occurance of the '{{Haltestelle|Ortsname|Haltestellenname|47.076207 N 11.453553 E|1890}}' template
294 and returns the tuple (start, end, city, stop, lat, lon, ele) or (None, None, None, None, None, None, None) if the
295 template was not found. If the template has no valid format, an exception is thrown."""
296 start, end = wrpylib.mwmarkup.find_template(wikitext, u'Haltestelle')
297 if start is None: return (None,) * 7
298 title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
299 city = wrpylib.wrvalidators.UnicodeNone().to_python(params[u'1'].strip())
300 stop = wrpylib.wrvalidators.UnicodeNone().to_python(params[u'2'].strip())
301 lat, lon = wrpylib.wrvalidators.GeoNone().to_python(params[u'3'].strip())
302 ele = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'4'].strip())
303 return start, end, city, stop, lat, lon, ele
306 def find_all_templates(wikitext, find_func):
307 """Returns a list of return values of find_func that searches for a template.
309 >>> find_all_tempaltes(wikitext, find_template_Haltestelle)
310 Returns an empty list if the template was not found at all.
313 result = find_func(wikitext)
314 start, end = result[:2]
315 while start is not None:
316 results.append(result)
317 result = find_func(wikitext[end:])
318 if result[0] is None:
321 start = result[0] + end
323 result = (start, end) + result[2:]
327 def parse_googlemap(wikitext):
328 """Parses the (unicode) u'<googlemap ...>content</googlemap>' of the googlemap extension
329 out of a page. If wikitext does not contain the googlemaps extension text None is returned.
330 If the googlemap contains invalid formatted lines, a ParseError is raised.
332 :param wikitext: wikitext containing the template. Example:
335 <googlemap version="0.9" lat="47.113291" lon="11.272337" zoom="15">
336 (Parkplatz)47.114958,11.266026
339 (Gasthaus) 47.114715, 11.266262, Alt Bärnbad (Gasthaus)
348 :returns: (GeoJSON as nested Python datatypes)
350 center, zoom, coords, paths = wrpylib.mwmarkup.parse_googlemap(wikitext)
355 lon, lat, symbol, title = point
357 if symbol is not None: properties['type'] = symbol.lower()
358 if title is not None: properties['name'] = title
359 json_features.append({
361 'geometry': {'type': 'Point', 'coordinates': [lon, lat]},
362 'properties': properties})
366 style, entries = path
367 style = style.lower()
368 PATH_TYPES = {u'6#ff014e9a': u'rodelbahn', u'6#ffe98401': u'gehweg', u'6#ff7f7fff': u'alternative', u'3#ff000000': u'lift', u'3#ffe1e100': u'anfahrt'}
369 if PATH_TYPES.has_key(style):
370 properties = {'type': PATH_TYPES[style]}
372 properties = {'type': 'line'}
373 properties['dicke'] = style[0]
374 properties['farbe'] = style[4:]
375 json_features.append({
378 'type': 'LineString',
379 'coordinates': [[lon, lat] for lon, lat, symbol, title in entries]},
380 'properties': properties})
383 'type': 'FeatureCollection',
384 'features': json_features,
385 'properties': {'lon': center[0], 'lat': center[1], 'zoom': zoom}}
389 def parse_wrmap_coordinates(coords):
390 '''gets a string coordinates and returns an array of lon/lat coordinate pairs, e.g.
394 [[11.87, 47.12], [11.70, 47.13]]'''
397 for match in re.finditer(r'\s*(\d+\.?\d*)\s*N?\s+(\d+\.?\d*)\s*E?\s*', coords):
398 if match.start() != pos:
400 result.append([float(match.groups()[1]), float(match.groups()[0])])
403 if pos == len(coords):
405 raise RuntimeError('Wrong coordinate format: {}'.format(coords))
408 def parse_wrmap(wikitext):
409 """Parses the (unicode) u'<wrmap ...>content</wrmap>' of the Winterrodeln wrmap extension
410 out of a page. If wikitext does not contain the wrmap extension text None is returned.
411 If the wrmap contains invalid formatted lines, a ParseError is raised.
413 :param wikitext: wikitext containing the template. Example:
416 <wrmap lat="47.2417134" lon="11.21408895" zoom="14" width="700" height="400">
417 <gasthaus name="Rosskogelhütte" wiki="Rosskogelhütte">47.240689 11.190454</gasthaus>
418 <parkplatz>47.245789 11.238971</parkplatz>
419 <haltestelle name="Oberperfuss Rangger Köpfl Lift">47.245711 11.238283</haltestelle>
427 :returns: GeoJSON as nested Python datatype
431 wrmap_xml = xml.etree.ElementTree.fromstring(wikitext.encode('utf-8'))
432 except xml.etree.ElementTree.ParseError as e:
433 row, column = e.position
434 raise ParseError("XML parse error on row {}, column {}: {}".format(row, column, e))
435 if wrmap_xml.tag not in ['wrmap', 'wrgmap']:
436 raise ParseError('No valid tag name')
438 # convert XML to geojson (http://www.geojson.org/geojson-spec.html)
440 for feature in wrmap_xml:
441 # determine feature type
442 is_point = feature.tag in WRMAP_POINT_TYPES
443 is_line = feature.tag in WRMAP_LINE_TYPES
444 if (not is_point and not is_line):
445 raise ParseError('Unknown element <{}>.'.format(feature.tag))
449 properties = {'type': feature.tag}
450 allowed_properties = set(['name', 'wiki'])
451 wrong_properties = set(feature.attrib.keys()) - allowed_properties
452 if len(wrong_properties) > 0:
453 raise ParseError("The attribute '{}' is not allowed at <{}>.".format(list(wrong_properties)[0], feature.tag))
454 properties.update(feature.attrib)
455 coordinates = parse_wrmap_coordinates(feature.text)
456 if len(coordinates) != 1:
457 raise ParseError('The element <{}> has to have exactly one coordinate pair.'.format(feature.tag))
458 json_features.append({
460 'geometry': {'type': 'Point', 'coordinates': coordinates[0]},
461 'properties': properties})
465 properties = {'type': feature.tag}
466 allowed_properties = set(['farbe', 'dicke'])
467 wrong_properties = set(feature.attrib.keys()) - allowed_properties
468 if len(wrong_properties) > 0:
469 raise ParseError("The attribute '{}' is not allowed at <{}>.".format(list(wrong_properties)[0], feature.tag))
470 if feature.attrib.has_key('farbe'):
471 if not re.match('#[0-9a-fA-F]{6}$', feature.attrib['farbe']):
472 raise ParseError('The attribute "farbe" has to have a format like "#a0bb43".')
473 properties['strokeColor'] = feature.attrib['farbe'] # e.g. #a200b7
474 if feature.attrib.has_key('dicke'):
476 properties['strokeWidth'] = int(feature.attrib['dicke']) # e.g. 6
478 raise ParseError('The attribute "dicke" has to be an integer.')
479 json_features.append({
481 'geometry': {'type': 'LineString', 'coordinates': parse_wrmap_coordinates(feature.text)},
482 'properties': properties})
486 for k, v in wrmap_xml.attrib.iteritems():
487 if k in ['lat', 'lon']:
489 properties[k] = float(v)
491 raise ParseError('Attribute "{}" has to be a float value.'.format(k))
492 elif k in ['zoom', 'width', 'height']:
494 properties[k] = int(v)
496 raise ParseError('Attribute "{}" has to be an integer value.'.format(k))
498 raise ParseError('Unknown attribute "{}".'.format(k))
501 'type': 'FeatureCollection',
502 'features': json_features,
503 'properties': properties}
508 def create_wrmap_coordinates(coords):
511 result.append('{:.6f} N {:.6f} E'.format(coord[1], coord[0]))
512 return '\n'.join(result)
515 def create_wrmap(geojson):
516 """Creates a <wrmap> wikitext from geojson (as python types)."""
517 wrmap_xml = xml.etree.ElementTree.Element('wrmap')
518 for k, v in geojson['properties'].iteritems():
519 wrmap_xml.attrib[k] = str(v)
521 assert geojson['type'] == 'FeatureCollection'
522 json_features = geojson['features']
523 for json_feature in json_features:
524 feature_xml = xml.etree.ElementTree.SubElement(wrmap_xml, json_feature['properties']['type'])
525 geo = json_feature['geometry']
526 if geo['type'] == 'Point':
527 feature_xml.text = create_wrmap_coordinates([geo['coordinates']])
529 feature_xml.text = create_wrmap_coordinates(geo['coordinates'])
530 feature_xml.attrib = json_feature['properties']
532 return xml.etree.ElementTree.tostring(wrmap_xml)