X-Git-Url: https://git.toastfreeware.priv.at/philipp/winterrodeln/wrpylib.git/blobdiff_plain/cc3137e1ea73e04eb48afba1f4f100c80131ebbc..dc5c42f67c79be7d672786b5c5727677dbec254f:/wrpylib/wrmwmarkup.py diff --git a/wrpylib/wrmwmarkup.py b/wrpylib/wrmwmarkup.py index 62bf20a..c968b20 100644 --- a/wrpylib/wrmwmarkup.py +++ b/wrpylib/wrmwmarkup.py @@ -1,10 +1,11 @@ -#!/usr/bin/python2.6 +#!/usr/bin/python2.7 # -*- coding: iso-8859-15 -*- # $Id$ # $HeadURL$ """This module contains winterrodeln specific functions that are prcocessing the MediaWiki markup. """ import re +import xml.etree.ElementTree import formencode import wrpylib.wrvalidators import wrpylib.mwmarkup @@ -314,3 +315,171 @@ def find_all_templates(wikitext, find_func): result = (start, end) + result[2:] return results + +def parse_googlemap(wikitext): + """Parses the (unicode) u'content' of the googlemap extension + out of a page. If wikitext does not contain the googlemaps extension text None is returned. + If the googlemap contains invalid formatted lines, a RuntimeError is raised. + + :param wikitext: wikitext containing the template. Example: + + wikitext = ''' + + (Parkplatz)47.114958,11.266026 + Parkplatz + + (Gasthaus) 47.114715, 11.266262, Alt Bärnbad (Gasthaus) + 6#FF014E9A + 47.114715,11.266262 + 47.114135,11.268381 + 47.113421,11.269322 + 47.11277,11.269979 + 47.112408,11.271119 + + ''' + :returns: (attributes, GeoJSON as Python datatypes) + """ + center, zoom, coords, paths = wrpylib.mwmarkup.parse_googlemap(wikitext) + json_features = [] + + # point + for point in coords: + lon, lat, symbol, title = point + properties = {'type': symbol} + if title: properties['name'] = title + json_features.append({ + 'type': 'feature', + 'geometry': {'type': 'Point', 'coordinates': [lon, lat]}, + 'properties': properties}) + + # path + for path in paths: + style, entries = path + properties = {'type': 'line'} + json_features.append({ + 'type': 'feature', + 'geometry': { + 'type': 'LineString', + 'coordinates': [[lon, lat] for lon, lat, symbol, title in entries]}, + 'properties': properties}) + + json = {'type': 'FeatureCollection', 'features': json_features} + return {'lon': center[0], 'lat': center[1], 'zoom': zoom}, json + + +def parse_wrmap_coordinates(coords): + '''gets a string coordinates and returns an array of lon/lat coordinate pairs, e.g. + 47.12 N 11.87 E + 47.13 N 11.70 E + -> + [[11.87, 47.12], [11.70, 47.13]]''' + result = [] + pos = 0 + for match in re.finditer(r'\s*(\d+\.?\d*)\s*N?\s+(\d+\.?\d*)\s*E?\s*', coords): + if match.start() != pos: + break + result.append([float(match.groups()[1]), float(match.groups()[0])]) + pos = match.end() + else: + if pos == len(coords): + return result + raise RuntimeError('Wrong coordinate format: {}'.format(coords)) + + +def parse_wrmap(wikitext): + """Parses the (unicode) u'content' of the Winterrodeln wrmap extension + out of a page. If wikitext does not contain the googlemaps extension text None is returned. + If the googlemap contains invalid formatted lines, a RuntimeError is raised. + + :param wikitext: wikitext containing the template. Example: + + wikitext = u''' + + 47.240689 11.190454 + 47.245789 11.238971 + 47.245711 11.238283 + + 47.238587 11.203360 + 47.244951 11.230868 + 47.245470 11.237853 + + + ''' + :returns: (attributes, GeoJSON as Python datatypes) + """ + # parse XML + try: + wrmap_xml = xml.etree.ElementTree.fromstring(wikitext.encode('utf-8')) + except xml.etree.ElementTree.ParseError as e: + row, column = e.position + raise RuntimeError("XML parse error on row {}, column {}: {}".format(row, column, e)) + # assert(in_array($tagname, array('wrmap', 'wrgmap'))); # TODO + + # convert XML to geojson (http://www.geojson.org/geojson-spec.html) + json_features = [] + point_type = {'gasthaus': 'inn', 'haltestelle': 'busstop', 'parkplatz': 'carpark', 'achtung': 'attention', 'punkt': 'point'} + line_type = {'rodelbahn': 'sledrun', 'gehweg': 'walk', 'alternative': 'alternative', 'lift': 'lift', 'linie': 'line'} + for feature in wrmap_xml: + # determine feature type + is_point = point_type.has_key(feature.tag) + is_line = line_type.has_key(feature.tag) + if (not is_point and not is_line): + raise RuntimeError('Unknown element <{}>.'.format(feature.tag)) + + # point + if is_point: + properties = {'type': point_type[feature.tag]} + allowed_properties = set(['name', 'wiki']) + wrong_properties = set(feature.attrib.keys()) - allowed_properties + if len(wrong_properties) > 0: + raise RuntimeError("The attribute '{}' is not allowed at <{}>.".format(list(wrong_properties)[0], feature.tag)) + properties.update(feature.attrib) + coordinates = parse_wrmap_coordinates(feature.text) + if len(coordinates) != 1: + raise RuntimeError('The element <{}> has to have exactly one coordinate pair.'.format(feature.tag)) + json_features.append({ + 'type': 'feature', + 'geometry': {'type': 'Point', 'coordinates': coordinates[0]}, + 'properties': properties}) + + # line + if is_line: + properties = {'type': line_type[feature.tag]} + allowed_properties = set(['farbe', 'dicke']) + wrong_properties = set(feature.attrib.keys()) - allowed_properties + if len(wrong_properties) > 0: + raise RuntimeError("The attribute '{}' is not allowed at <{}>.".format(list(wrong_properties)[0], feature.tag)) + if feature.attrib.has_key('farbe'): + # TODO: check value + properties['strokeColor'] = feature.attrib['farbe'] # e.g. #a200b7 + if feature.attrib.has_key('dicke'): + try: + properties['strokeWidth'] = int(feature.attrib['dicke']) # e.g. 6 + except ValueError: + raise RuntimeError('The attribute "farbe" has to be an integer.') + json_features.append({ + 'type': 'feature', + 'geometry': {'type': 'LineString', 'coordinates': parse_wrmap_coordinates(feature.text)}, + 'properties': properties}) + + json = { + 'type': 'FeatureCollection', + 'features': json_features} + + # attributes # TODO: check + attributes = {} + attributes['lat'] = float(wrmap_xml.attrib.get('lat', 47.267648)) # center lat + attributes['lon'] = float(wrmap_xml.attrib.get('lon', 11.404655)) # center lon + attributes['zoom'] = int(wrmap_xml.attrib.get('zoom', 10)) # Google Zoom Level + attributes['width'] = int(wrmap_xml.attrib['width']) if wrmap_xml.attrib.has_key('width') else None # None corresponds to 100% + attributes['height'] = int(wrmap_xml.attrib.get('height', 450)) # map height in px + # show_sledruns = (wrmap_xml.tag == 'wrgmap') + + return attributes, json + + +def create_wrmap(geojson): + """Creates a wikitext from geojson.""" + pass + +