diff options
Diffstat (limited to 'webapp/django/contrib/gis/feeds.py')
-rw-r--r-- | webapp/django/contrib/gis/feeds.py | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/webapp/django/contrib/gis/feeds.py b/webapp/django/contrib/gis/feeds.py new file mode 100644 index 0000000000..4105ef740b --- /dev/null +++ b/webapp/django/contrib/gis/feeds.py @@ -0,0 +1,135 @@ +from django.contrib.syndication.feeds import Feed as BaseFeed, FeedDoesNotExist +from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed + +class GeoFeedMixin(object): + """ + This mixin provides the necessary routines for SyndicationFeed subclasses + to produce simple GeoRSS or W3C Geo elements. + """ + + def georss_coords(self, coords): + """ + In GeoRSS coordinate pairs are ordered by lat/lon and separated by + a single white space. Given a tuple of coordinates, this will return + a unicode GeoRSS representation. + """ + return u' '.join([u'%f %f' % (coord[1], coord[0]) for coord in coords]) + + def add_georss_point(self, handler, coords, w3c_geo=False): + """ + Adds a GeoRSS point with the given coords using the given handler. + Handles the differences between simple GeoRSS and the more pouplar + W3C Geo specification. + """ + if w3c_geo: + lon, lat = coords[:2] + handler.addQuickElement(u'geo:lat', u'%f' % lat) + handler.addQuickElement(u'geo:lon', u'%f' % lon) + else: + handler.addQuickElement(u'georss:point', self.georss_coords((coords,))) + + def add_georss_element(self, handler, item, w3c_geo=False): + """ + This routine adds a GeoRSS XML element using the given item and handler. + """ + # Getting the Geometry object. + geom = item.get('geometry', None) + if not geom is None: + if isinstance(geom, (list, tuple)): + # Special case if a tuple/list was passed in. The tuple may be + # a point or a box + box_coords = None + if isinstance(geom[0], (list, tuple)): + # Box: ( (X0, Y0), (X1, Y1) ) + if len(geom) == 2: + box_coords = geom + else: + raise ValueError('Only should be two sets of coordinates.') + else: + if len(geom) == 2: + # Point: (X, Y) + self.add_georss_point(handler, geom, w3c_geo=w3c_geo) + elif len(geom) == 4: + # Box: (X0, Y0, X1, Y1) + box_coords = (geom[:2], geom[2:]) + else: + raise ValueError('Only should be 2 or 4 numeric elements.') + # If a GeoRSS box was given via tuple. + if not box_coords is None: + if w3c_geo: raise ValueError('Cannot use simple GeoRSS box in W3C Geo feeds.') + handler.addQuickElement(u'georss:box', self.georss_coords(box_coords)) + else: + # Getting the lower-case geometry type. + gtype = str(geom.geom_type).lower() + if gtype == 'point': + self.add_georss_point(handler, geom.coords, w3c_geo=w3c_geo) + else: + if w3c_geo: raise ValueError('W3C Geo only supports Point geometries.') + # For formatting consistent w/the GeoRSS simple standard: + # http://georss.org/1.0#simple + if gtype in ('linestring', 'linearring'): + handler.addQuickElement(u'georss:line', self.georss_coords(geom.coords)) + elif gtype in ('polygon',): + # Only support the exterior ring. + handler.addQuickElement(u'georss:polygon', self.georss_coords(geom[0].coords)) + else: + raise ValueError('Geometry type "%s" not supported.' % geom.geom_type) + +### SyndicationFeed subclasses ### +class GeoRSSFeed(Rss201rev2Feed, GeoFeedMixin): + def rss_attributes(self): + attrs = super(GeoRSSFeed, self).rss_attributes() + attrs[u'xmlns:georss'] = u'http://www.georss.org/georss' + return attrs + + def add_item_elements(self, handler, item): + super(GeoRSSFeed, self).add_item_elements(handler, item) + self.add_georss_element(handler, item) + + def add_root_elements(self, handler): + super(GeoRSSFeed, self).add_root_elements(handler) + self.add_georss_element(handler, self.feed) + +class GeoAtom1Feed(Atom1Feed, GeoFeedMixin): + def root_attributes(self): + attrs = super(GeoAtom1Feed, self).root_attributes() + attrs[u'xmlns:georss'] = u'http://www.georss.org/georss' + return attrs + + def add_item_elements(self, handler, item): + super(GeoAtom1Feed, self).add_item_elements(handler, item) + self.add_georss_element(handler, item) + + def add_root_elements(self, handler): + super(GeoAtom1Feed, self).add_root_elements(handler) + self.add_georss_element(handler, self.feed) + +class W3CGeoFeed(Rss201rev2Feed, GeoFeedMixin): + def rss_attributes(self): + attrs = super(W3CGeoFeed, self).rss_attributes() + attrs[u'xmlns:geo'] = u'http://www.w3.org/2003/01/geo/wgs84_pos#' + return attrs + + def add_item_elements(self, handler, item): + super(W3CGeoFeed, self).add_item_elements(handler, item) + self.add_georss_element(handler, item, w3c_geo=True) + + def add_root_elements(self, handler): + super(W3CGeoFeed, self).add_root_elements(handler) + self.add_georss_element(handler, self.feed, w3c_geo=True) + +### Feed subclass ### +class Feed(BaseFeed): + """ + This is a subclass of the `Feed` from `django.contrib.syndication`. + This allows users to define a `geometry(obj)` and/or `item_geometry(item)` + methods on their own subclasses so that geo-referenced information may + placed in the feed. + """ + feed_type = GeoRSSFeed + + def feed_extra_kwargs(self, obj): + return {'geometry' : self.__get_dynamic_attr('geometry', obj)} + + def item_extra_kwargs(self, item): + return {'geometry' : self.__get_dynamic_attr('item_geometry', item)} |