Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

feeds.py 5.9KB

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