2011-07-13 17:35:51 +08:00
|
|
|
from django.contrib.syndication.views import Feed as BaseFeed
|
2008-08-17 04:40:47 +08:00
|
|
|
from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed
|
|
|
|
|
2013-11-03 01:18:46 +08:00
|
|
|
|
2017-01-19 15:39:46 +08:00
|
|
|
class GeoFeedMixin:
|
2008-08-17 04:40:47 +08:00
|
|
|
"""
|
|
|
|
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
|
2017-01-21 05:04:05 +08:00
|
|
|
a single white space. Given a tuple of coordinates, return a string
|
|
|
|
GeoRSS representation.
|
2008-08-17 04:40:47 +08:00
|
|
|
"""
|
2013-08-30 07:20:00 +08:00
|
|
|
return ' '.join('%f %f' % (coord[1], coord[0]) for coord in coords)
|
2008-08-17 04:40:47 +08:00
|
|
|
|
|
|
|
def add_georss_point(self, handler, coords, w3c_geo=False):
|
|
|
|
"""
|
|
|
|
Adds a GeoRSS point with the given coords using the given handler.
|
2014-03-02 22:25:53 +08:00
|
|
|
Handles the differences between simple GeoRSS and the more popular
|
2008-08-17 04:40:47 +08:00
|
|
|
W3C Geo specification.
|
|
|
|
"""
|
|
|
|
if w3c_geo:
|
|
|
|
lon, lat = coords[:2]
|
2012-06-08 00:08:47 +08:00
|
|
|
handler.addQuickElement('geo:lat', '%f' % lat)
|
|
|
|
handler.addQuickElement('geo:lon', '%f' % lon)
|
2008-08-17 04:40:47 +08:00
|
|
|
else:
|
2012-06-08 00:08:47 +08:00
|
|
|
handler.addQuickElement('georss:point', self.georss_coords((coords,)))
|
2008-08-17 04:40:47 +08:00
|
|
|
|
|
|
|
def add_georss_element(self, handler, item, w3c_geo=False):
|
2017-01-25 04:31:57 +08:00
|
|
|
"""Add a GeoRSS XML element using the given item and handler."""
|
2008-08-17 04:40:47 +08:00
|
|
|
# Getting the Geometry object.
|
2015-05-14 02:51:18 +08:00
|
|
|
geom = item.get('geometry')
|
2014-03-31 03:11:05 +08:00
|
|
|
if geom is not None:
|
2008-08-17 04:40:47 +08:00
|
|
|
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.
|
2014-03-31 03:11:05 +08:00
|
|
|
if box_coords is not None:
|
2013-10-17 16:17:41 +08:00
|
|
|
if w3c_geo:
|
|
|
|
raise ValueError('Cannot use simple GeoRSS box in W3C Geo feeds.')
|
2012-06-08 00:08:47 +08:00
|
|
|
handler.addQuickElement('georss:box', self.georss_coords(box_coords))
|
2008-08-17 04:40:47 +08:00
|
|
|
else:
|
2018-09-25 22:30:18 +08:00
|
|
|
# Getting the lowercase geometry type.
|
2008-08-17 04:40:47 +08:00
|
|
|
gtype = str(geom.geom_type).lower()
|
|
|
|
if gtype == 'point':
|
2013-10-11 04:42:30 +08:00
|
|
|
self.add_georss_point(handler, geom.coords, w3c_geo=w3c_geo)
|
2008-08-17 04:40:47 +08:00
|
|
|
else:
|
2013-10-17 16:17:41 +08:00
|
|
|
if w3c_geo:
|
|
|
|
raise ValueError('W3C Geo only supports Point geometries.')
|
2008-08-17 04:40:47 +08:00
|
|
|
# For formatting consistent w/the GeoRSS simple standard:
|
|
|
|
# http://georss.org/1.0#simple
|
|
|
|
if gtype in ('linestring', 'linearring'):
|
2012-06-08 00:08:47 +08:00
|
|
|
handler.addQuickElement('georss:line', self.georss_coords(geom.coords))
|
2008-08-17 04:40:47 +08:00
|
|
|
elif gtype in ('polygon',):
|
|
|
|
# Only support the exterior ring.
|
2012-06-08 00:08:47 +08:00
|
|
|
handler.addQuickElement('georss:polygon', self.georss_coords(geom[0].coords))
|
2008-08-17 04:40:47 +08:00
|
|
|
else:
|
|
|
|
raise ValueError('Geometry type "%s" not supported.' % geom.geom_type)
|
|
|
|
|
2013-11-03 01:18:46 +08:00
|
|
|
|
2015-02-06 02:25:34 +08:00
|
|
|
# ### SyndicationFeed subclasses ###
|
2008-08-17 04:40:47 +08:00
|
|
|
class GeoRSSFeed(Rss201rev2Feed, GeoFeedMixin):
|
|
|
|
def rss_attributes(self):
|
2017-01-21 21:13:44 +08:00
|
|
|
attrs = super().rss_attributes()
|
2012-06-08 00:08:47 +08:00
|
|
|
attrs['xmlns:georss'] = 'http://www.georss.org/georss'
|
2008-08-17 04:40:47 +08:00
|
|
|
return attrs
|
|
|
|
|
|
|
|
def add_item_elements(self, handler, item):
|
2017-01-21 21:13:44 +08:00
|
|
|
super().add_item_elements(handler, item)
|
2008-08-17 04:40:47 +08:00
|
|
|
self.add_georss_element(handler, item)
|
|
|
|
|
|
|
|
def add_root_elements(self, handler):
|
2017-01-21 21:13:44 +08:00
|
|
|
super().add_root_elements(handler)
|
2008-08-17 04:40:47 +08:00
|
|
|
self.add_georss_element(handler, self.feed)
|
|
|
|
|
2013-11-03 01:18:46 +08:00
|
|
|
|
2008-08-17 04:40:47 +08:00
|
|
|
class GeoAtom1Feed(Atom1Feed, GeoFeedMixin):
|
|
|
|
def root_attributes(self):
|
2017-01-21 21:13:44 +08:00
|
|
|
attrs = super().root_attributes()
|
2012-06-08 00:08:47 +08:00
|
|
|
attrs['xmlns:georss'] = 'http://www.georss.org/georss'
|
2008-08-17 04:40:47 +08:00
|
|
|
return attrs
|
|
|
|
|
|
|
|
def add_item_elements(self, handler, item):
|
2017-01-21 21:13:44 +08:00
|
|
|
super().add_item_elements(handler, item)
|
2008-08-17 04:40:47 +08:00
|
|
|
self.add_georss_element(handler, item)
|
|
|
|
|
|
|
|
def add_root_elements(self, handler):
|
2017-01-21 21:13:44 +08:00
|
|
|
super().add_root_elements(handler)
|
2008-08-17 04:40:47 +08:00
|
|
|
self.add_georss_element(handler, self.feed)
|
|
|
|
|
2013-11-03 01:18:46 +08:00
|
|
|
|
2008-08-17 04:40:47 +08:00
|
|
|
class W3CGeoFeed(Rss201rev2Feed, GeoFeedMixin):
|
|
|
|
def rss_attributes(self):
|
2017-01-21 21:13:44 +08:00
|
|
|
attrs = super().rss_attributes()
|
2012-06-08 00:08:47 +08:00
|
|
|
attrs['xmlns:geo'] = 'http://www.w3.org/2003/01/geo/wgs84_pos#'
|
2008-08-17 04:40:47 +08:00
|
|
|
return attrs
|
|
|
|
|
|
|
|
def add_item_elements(self, handler, item):
|
2017-01-21 21:13:44 +08:00
|
|
|
super().add_item_elements(handler, item)
|
2008-08-17 04:40:47 +08:00
|
|
|
self.add_georss_element(handler, item, w3c_geo=True)
|
|
|
|
|
|
|
|
def add_root_elements(self, handler):
|
2017-01-21 21:13:44 +08:00
|
|
|
super().add_root_elements(handler)
|
2008-08-17 04:40:47 +08:00
|
|
|
self.add_georss_element(handler, self.feed, w3c_geo=True)
|
|
|
|
|
2013-11-03 01:18:46 +08:00
|
|
|
|
2015-02-06 02:25:34 +08:00
|
|
|
# ### Feed subclass ###
|
2008-08-17 04:40:47 +08:00
|
|
|
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):
|
2015-11-24 23:34:03 +08:00
|
|
|
return {'geometry': self._get_dynamic_attr('geometry', obj)}
|
2008-08-17 04:40:47 +08:00
|
|
|
|
|
|
|
def item_extra_kwargs(self, item):
|
2015-11-24 23:34:03 +08:00
|
|
|
return {'geometry': self._get_dynamic_attr('item_geometry', item)}
|