PageRenderTime 760ms CodeModel.GetById 484ms app.highlight 86ms RepoModel.GetById 134ms app.codeStats 0ms

/django/contrib/gis/feeds.py

https://code.google.com/p/mango-py/
Python | 135 lines | 83 code | 16 blank | 36 comment | 17 complexity | 0d979417c8ea1269bfee7d3a1d1ff5fd MD5 | raw file
  1from django.contrib.syndication.feeds import Feed as BaseFeed, FeedDoesNotExist
  2from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed
  3
  4class GeoFeedMixin(object):
  5    """
  6    This mixin provides the necessary routines for SyndicationFeed subclasses
  7    to produce simple GeoRSS or W3C Geo elements.
  8    """
  9
 10    def georss_coords(self, coords):
 11        """
 12        In GeoRSS coordinate pairs are ordered by lat/lon and separated by
 13        a single white space.  Given a tuple of coordinates, this will return
 14        a unicode GeoRSS representation.
 15        """
 16        return u' '.join([u'%f %f' % (coord[1], coord[0]) for coord in coords])
 17
 18    def add_georss_point(self, handler, coords, w3c_geo=False):
 19        """
 20        Adds a GeoRSS point with the given coords using the given handler.
 21        Handles the differences between simple GeoRSS and the more pouplar
 22        W3C Geo specification.
 23        """
 24        if w3c_geo:
 25            lon, lat = coords[:2]
 26            handler.addQuickElement(u'geo:lat', u'%f' % lat)
 27            handler.addQuickElement(u'geo:lon', u'%f' % lon)
 28        else:
 29            handler.addQuickElement(u'georss:point', self.georss_coords((coords,)))
 30
 31    def add_georss_element(self, handler, item, w3c_geo=False):
 32        """
 33        This routine adds a GeoRSS XML element using the given item and handler.
 34        """
 35        # Getting the Geometry object.
 36        geom = item.get('geometry', None)
 37        if not geom is None:
 38            if isinstance(geom, (list, tuple)):
 39                # Special case if a tuple/list was passed in.  The tuple may be
 40                # a point or a box
 41                box_coords = None
 42                if isinstance(geom[0], (list, tuple)):
 43                    # Box: ( (X0, Y0), (X1, Y1) )
 44                    if len(geom) == 2:
 45                        box_coords = geom
 46                    else:
 47                        raise ValueError('Only should be two sets of coordinates.')
 48                else:
 49                    if len(geom) == 2:
 50                        # Point: (X, Y)
 51                        self.add_georss_point(handler, geom, w3c_geo=w3c_geo)
 52                    elif len(geom) == 4:
 53                        # Box: (X0, Y0, X1, Y1)
 54                        box_coords = (geom[:2], geom[2:])
 55                    else:
 56                        raise ValueError('Only should be 2 or 4 numeric elements.')
 57                # If a GeoRSS box was given via tuple.
 58                if not box_coords is None:
 59                    if w3c_geo: raise ValueError('Cannot use simple GeoRSS box in W3C Geo feeds.')
 60                    handler.addQuickElement(u'georss:box', self.georss_coords(box_coords))
 61            else:
 62                # Getting the lower-case geometry type.
 63                gtype = str(geom.geom_type).lower()
 64                if gtype == 'point':
 65                    self.add_georss_point(handler, geom.coords, w3c_geo=w3c_geo) 
 66                else:
 67                    if w3c_geo: raise ValueError('W3C Geo only supports Point geometries.')
 68                    # For formatting consistent w/the GeoRSS simple standard:
 69                    # http://georss.org/1.0#simple
 70                    if gtype in ('linestring', 'linearring'):
 71                        handler.addQuickElement(u'georss:line', self.georss_coords(geom.coords))
 72                    elif gtype in ('polygon',):
 73                        # Only support the exterior ring.
 74                        handler.addQuickElement(u'georss:polygon', self.georss_coords(geom[0].coords))
 75                    else:
 76                        raise ValueError('Geometry type "%s" not supported.' % geom.geom_type)
 77
 78### SyndicationFeed subclasses ###
 79class GeoRSSFeed(Rss201rev2Feed, GeoFeedMixin):
 80    def rss_attributes(self):
 81        attrs = super(GeoRSSFeed, self).rss_attributes()
 82        attrs[u'xmlns:georss'] = u'http://www.georss.org/georss'
 83        return attrs
 84
 85    def add_item_elements(self, handler, item):
 86        super(GeoRSSFeed, self).add_item_elements(handler, item)
 87        self.add_georss_element(handler, item)
 88
 89    def add_root_elements(self, handler):
 90        super(GeoRSSFeed, self).add_root_elements(handler)
 91        self.add_georss_element(handler, self.feed)
 92
 93class GeoAtom1Feed(Atom1Feed, GeoFeedMixin):
 94    def root_attributes(self):
 95        attrs = super(GeoAtom1Feed, self).root_attributes()
 96        attrs[u'xmlns:georss'] = u'http://www.georss.org/georss'
 97        return attrs
 98
 99    def add_item_elements(self, handler, item):
100        super(GeoAtom1Feed, self).add_item_elements(handler, item)
101        self.add_georss_element(handler, item)
102
103    def add_root_elements(self, handler):
104        super(GeoAtom1Feed, self).add_root_elements(handler)
105        self.add_georss_element(handler, self.feed)
106
107class W3CGeoFeed(Rss201rev2Feed, GeoFeedMixin):
108    def rss_attributes(self):
109        attrs = super(W3CGeoFeed, self).rss_attributes()
110        attrs[u'xmlns:geo'] = u'http://www.w3.org/2003/01/geo/wgs84_pos#'
111        return attrs
112
113    def add_item_elements(self, handler, item):
114        super(W3CGeoFeed, self).add_item_elements(handler, item)
115        self.add_georss_element(handler, item, w3c_geo=True)
116
117    def add_root_elements(self, handler):
118        super(W3CGeoFeed, self).add_root_elements(handler)
119        self.add_georss_element(handler, self.feed, w3c_geo=True)
120
121### Feed subclass ###
122class Feed(BaseFeed):
123    """
124    This is a subclass of the `Feed` from `django.contrib.syndication`.
125    This allows users to define a `geometry(obj)` and/or `item_geometry(item)`
126    methods on their own subclasses so that geo-referenced information may
127    placed in the feed.
128    """
129    feed_type = GeoRSSFeed
130
131    def feed_extra_kwargs(self, obj):
132        return {'geometry' : self.__get_dynamic_attr('geometry', obj)}
133
134    def item_extra_kwargs(self, item):
135        return {'geometry' : self.__get_dynamic_attr('item_geometry', item)}