Sign in

Google Cookbook - Google App Engine

appengine service for google maps/earth (kml)
Posted by paul.marrington.net on Sat 07 Nov 2009 in Mashups with App Engine
User ratings:
This example is called TripKML. It reads pre-recorded GeoPt records and generates KML for Google Maps/Earth. The basic webapp is as normal:

class TripKML(webapp.RequestHandler):
def get(self):
try:
...
except DeadlineExceededError:
self.response.clear()
self.response.set_status(500)
self.message("This operation could not be completed in time...")
application = webapp.WSGIApplication([('/service/tripKML', TripKML)], debug = True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()



First we parse the command line:

            self.traveller = User.fromId(int(self.request.get('traveller')))
trip = self.request.get('trip')



As the code creates KML, tell the browser what do do with it:

        self.response.headers['Content-Type'] = 'application/vnd.google-earth.kml+xml'



I have attached my lightweight class for generating XML. You give it the root XML tag name and attributes. Wrap everything in a folder for clarity in the tree. The last line is XML to be inserted (saved as http://…)

            rootElement = self.kml = xml('kml', xmlns = 'http://www.opengis.net/kml/2.2')
self.kml = rootElement.Folder
self.kml.name(trip)
self.kml.Style.IconStyle(id = 'noteStyle').Icon.href(iconUrl)



My style is to read the records and have factory code to call methods based on the record type. Because most records will be of one or two types, I have cached the parser method:

            parsers = dict()
query = Record.gql(
'WHERE userId=:1 AND trip=:2 ORDER BY time', self.traveller.id, trip)
for self.record in query:
try:
parser = parsers[self.record.type]
except KeyError:
method = self.record.type + "RecordProcessor";
parser = getattr(self, method, self.defaultRecordProcessor)
parsers[self.record.type] = parser
parser()



A record type called "notes" generates a note indicated by an icon on the map:

    def notesRecordProcessor(self):
self.kml.Placemark.name(self.record.title).styleUrl('noteStyle').\
description(self.record.notes).Point.coordinates(
"%f,%f" % (self.record.location.lon, self.record.location.lat))()



The “here” record processor does more work as it collects coordinates to make a line.

Back to the TripKml class, I also overlay kml generated by Picasa to display images:

            albums = Album.forTrip(self.traveller.id, trip)
for album in albums:
try:
self.kml.NetworkLink.name(trip).Link.refreshMode('onInterval').\
refreshInterval(3600).hreflang(\
album.feedUri + '(anpersand)amp;alt=kml(anpersand)amp;kind=photo')
except Exception, e:
logging.warning('Can\'t access Picasa album for trip %s: %s' % (trip.name, e.message))



The last thing we need to do is generate the KML and send it to the browser:

            self.response.out.write(str(self.kml))



I have attached TripKML.py as it is in use and xml.py for generating the XML.
Attached files
tripKML.pyViewDownload
xml.pyViewDownload

Comments (0)

Sign in to add comment.