from qgisrest.vectorformats.Feature import Feature
from qgisrest.vectorformats.Formats.Format import Format
from datetime import datetime
import time
import xml.dom.minidom as m
class GeoRSS(Format):
title = "No title"
url = "/"
feedname = ""
edit_link = False
debug = False
def encode(self, result):
timestamp = datetime.fromtimestamp(time.time())
timestamp = str(timestamp.strftime('%Y-%m-%dT%H:%M:%SZ'))
results = ["""
%s
%s
FeatureServer
%s
""" % (self.title, self.url, self.url, timestamp) ]
for action in result:
results.append( self.encode_feature(action))
results.append("")
return "\n".join(results)
def encode_feature(self, feature):
import xml.dom.minidom as m
doc = m.Document()
entry = doc.createElement("entry")
id_node = doc.createElement("id")
id_node.appendChild(doc.createTextNode("%s%s%s.atom" % (self.url, self.feedname, feature.id)))
entry.appendChild(id_node)
link_node = doc.createElement("link")
link_node.setAttribute("href", "%s%s%s.atom" % (self.url, self.feedname, feature.id))
entry.appendChild(link_node)
if self.edit_link:
link_node = doc.createElement("link")
link_node.setAttribute("href", "%s%s%s.atom" % (self.url, self.feedname, feature.id))
link_node.setAttribute("rel", "edit")
entry.appendChild(link_node)
title_node = doc.createElement("title")
title = None
if feature.properties.has_key("title"):
title = doc.createTextNode(feature.properties['title'])
else:
title = doc.createTextNode("Feature #%s" % feature.id)
title_node.appendChild(title)
entry.appendChild(title_node)
if feature.properties.has_key('timestamp'):
timestamp = feature.properties['timestamp']
del feature.properties['timestamp']
edited = doc.createElement("app:edited")
timestamp = datetime.fromtimestamp(timestamp)
edited.appendChild(doc.createTextNode(str(timestamp.strftime('%Y-%m-%dT%H:%M:%SZ'))))
entry.appendChild(edited)
updated = doc.createElement("updated")
timestamp = datetime.fromtimestamp(timestamp)
updated.appendChild(doc.createTextNode(str(timestamp.strftime('%Y-%m-%dT%H:%M:%SZ'))))
entry.appendChild(updated)
else:
updated = doc.createElement("updated")
timestamp = datetime.fromtimestamp(time.time())
updated.appendChild(doc.createTextNode(str(timestamp.strftime('%Y-%m-%dT%H:%M:%SZ'))))
entry.appendChild(updated)
desc_node = doc.createElement("content")
desc_node.setAttribute("type", "html")
description = ""
if feature.properties.has_key("description"):
description = feature.properties['description']
else:
desc_fields = []
for key, value in feature.properties.items():
if isinstance(value, str):
value = unicode(value, "utf-8")
desc_fields.append( "%s: %s" % (key, value) )
description = "%s" % ("
".join(desc_fields))
desc_node.appendChild(doc.createTextNode(description))
entry.appendChild(desc_node)
if feature.geometry['type'] == "Point":
coords = "%s %s" % (feature.geometry['coordinates'][1], feature.geometry['coordinates'][0])
geo_node = doc.createElement("georss:point")
geo_node.appendChild(doc.createTextNode(coords))
elif feature.geometry['type'] == "LineString":
coords = " ".join(map(lambda x: "%s %s" % (x[1], x[0]), feature.geometry['coordinates']))
geo_node = doc.createElement("georss:line")
geo_node.appendChild(doc.createTextNode(coords))
else:
coords = " ".join(map(lambda x: "%s %s" % (x[1], x[0]), feature.geometry['coordinates'][0]))
geo_node = doc.createElement("georss:polygon")
geo_node.appendChild(doc.createTextNode(coords))
entry.appendChild(geo_node)
return entry.toxml()
def decode(self, post_data):
try:
doc = m.parseString(post_data)
except Exception, E:
raise Exception("Unable to parse GeoRSS. (%s)\nContent was: %s" % (E, post_data))
entries = doc.getElementsByTagName("entry")
if not entries:
entries = doc.getElementsByTagName("item")
entries.reverse()
features = []
for entry in entries:
feature_obj = self.entry_to_feature(entry)
if feature_obj:
features.append(feature_obj)
return features
def coordinates_to_geom(self, coordinates, type):
"""Convert a coordinates string from GML or GeoRSS Simple to
a FeatureServer internal geometry."""
coords = coordinates.strip().replace(",", " ").split()
if type == "LineString":
coords = [[float(coords[i+1]), float(coords[i])] for i in xrange(0, len(coords), 2)]
return {'type':'LineString', 'coordinates':coords}
elif type == "Polygon":
coords = [[float(coords[i+1]), float(coords[i])] for i in xrange(0, len(coords), 2)]
return {'type':'Polygon', 'coordinates':[coords]}
elif type == "Point":
coords.reverse()
return {'type':'Point', 'coordinates':map(float,coords)}
elif type == "Box":
coords = [[[float(coords[1]), float(coords[0])],
[float(coords[3]), float(coords[0])],
[float(coords[3]), float(coords[2])],
[float(coords[1]), float(coords[2])],
[float(coords[1]), float(coords[0])]]]
return {'type':'Polygon', 'coordinates':coords}
def extract_entry_geometry(self, entry_dom):
"""Given an entry, do our best to extract its geometry. This has been
designed to maximize the potential of finding geometries, but may
not work on some features, since everyone seems to do geometries
differently."""
points = entry_dom.getElementsByTagName("georss:point")
lines = entry_dom.getElementsByTagName("georss:line")
polys = entry_dom.getElementsByTagName("georss:polygon")
box = entry_dom.getElementsByTagName("georss:box")
type = None
element = None
for geom_type in ['Point', 'LineString', 'Polygon']:
geom = entry_dom.getElementsByTagName("gml:%s" % geom_type)
if len(geom):
type = geom_type
element = geom[0]
if type == "Point":
points = element.getElementsByTagName("gml:pos")
elif type == "LineString":
lines = element.getElementsByTagName("gml:posList")
elif type == "Polygon":
polys = element.getElementsByTagName("gml:posList")
if len(points):
coords = points[0].firstChild.nodeValue
geometry = self.coordinates_to_geom(coords, "Point")
elif len(lines):
coords = lines[0].firstChild.nodeValue
geometry = self.coordinates_to_geom(coords, "LineString")
elif len(polys):
coords = polys[0].firstChild.nodeValue
geometry = self.coordinates_to_geom(coords, "Polygon")
elif len(box):
coords = box[0].firstChild.nodeValue
geometry = self.coordinates_to_geom(coords, "Box")
else:
error = "Could not find geometry in Feature. XML was: \n\n%s" % entry_dom.toxml()
if hasattr(self.debug):
raise Exception(error)
return None
return geometry
def entry_to_feature(self, entry_dom):
id = 1
try:
id = entry_dom.getElementsByTagName("id")[0].firstChild.nodeValue
except:
id = 1
feature = Feature(str(id))
geometry = self.extract_entry_geometry(entry_dom)
if not geometry: return None
feature.geometry = geometry
for node in entry_dom.childNodes:
try:
attr_name = node.tagName.split(":")[-1]
if attr_name not in ['point', 'line', 'polygon', 'id', 'where']:
try:
feature.properties[attr_name] = node.firstChild.nodeValue
except:
pass
except:
pass
return feature