{"id":375,"date":"2009-09-16T08:51:20","date_gmt":"2009-09-16T13:51:20","guid":{"rendered":"http:\/\/www.kralidis.ca\/blog\/?p=375"},"modified":"2009-09-16T09:37:31","modified_gmt":"2009-09-16T14:37:31","slug":"python-kml-and-parishes","status":"publish","type":"post","link":"https:\/\/www.kralidis.ca\/blog\/2009\/09\/16\/python-kml-and-parishes\/","title":{"rendered":"Python, KML and Parishes"},"content":{"rendered":"<p>When looking for phone numbers for various <a title=\"churches\" href=\"http:\/\/www.gocanada.org\/parishdirectory\/index.htm\">churches<\/a>, I thought wouldn&#8217;t it be neat to put the locations on a map?<\/p>\n<p>Python to the rescue.\u00a0 After some scraping to generate a CSV listing, I geocoded the addresses, then I used the OGR to convert into a KML document, using the same approach I previously <a title=\"blogged\" href=\"\/blog\/2007\/12\/28\/two-milk-no-sugar\/\">blogged<\/a> about.\u00a0 Nice!<\/p>\n<p>Looking deeper, I wanted to have more exhaustive content within the &lt;description&gt; element.\u00a0 Turns out ogr2ogr has a -dsco DescriptionField=fieldname option, but I wanted more than that.\u00a0 So I decided to hack the original CSV:<\/p>\n<pre>#!\/usr\/bin\/python\r\n\r\nimport csv\r\nimport urllib2\r\nimport urllib\r\nfrom lxml import etree\r\n\r\nr = csv.reader(open('greek_churches_canada.csv'))\r\n\r\nnode = etree.Element('kml', nsmap={None: 'http:\/\/www.opengis.net\/kml\/2.2'})\r\n\r\nr.next()\r\n\r\nfor row in r:\r\n    params = '%s,%s,%s,%s' % (row[1], row[2], row[3], row[4])\r\n    url = 'http:\/\/maps.google.com\/maps\/geo?output=csv&amp;q=%s' % urllib.quote_plus(params)\r\n    #print url\r\n    content = urllib2.urlopen(url)\r\n    status, accuracy, lat, lon = content.read().split(',')\r\n    #print status, accuracy, lat, lon\r\n    if status == '200':\r\n        row.append(lat)\r\n        row.append(lon)\r\n        subnode = etree.Element('Placemark')\r\n        subsubnode = etree.Element('name')\r\n        subsubnode.text = row[0]\r\n        subsubnode2 = etree.Element('description')\r\n        description = '&lt;p&gt;'\r\n        description += '%s&lt;br\/&gt;' % row[1]\r\n        description += '%s, %s&lt;br\/&gt;' % (row[2], row[3])\r\n        description += '%s&lt;br\/&gt;' % row[4]\r\n        if row[5] != 'none':\r\n            description += '%s&lt;br\/&gt;' % row[5]\r\n        if row[6] != 'none':\r\n            description += '%s&lt;br\/&gt;' % row[6]\r\n        if row[7] != 'none':\r\n            description += '&lt;a href=\"%s\"&gt;Website&lt;\/a&gt;&lt;br\/&gt;' % row[7]\r\n        if row[8] != 'none':\r\n            description += '&lt;a href=\"mailto:%s\"&gt;Email&lt;\/a&gt;&lt;br\/&gt;' % row[8]\r\n        description += '%s&lt;br\/&gt;' % row[9]\r\n        description += '&lt;\/p&gt;'\r\n        subsubnode2.text = etree.CDATA(description)\r\n        subsubnode3 = etree.Element('Point')\r\n        subsubsubnode = etree.Element('coordinates')\r\n        subsubsubnode.text = '%s, %s' %(lon, lat)\r\n        subsubnode3.append(subsubsubnode)\r\n        subnode.append(subsubnode)\r\n        subnode.append(subsubnode2)\r\n        subnode.append(subsubnode3)\r\n        node.append(subnode)\r\nprint etree.tostring(node, xml_declaration=True, encoding='UTF-8', pretty_print=True)<\/pre>\n<p>I wonder whether an OGR -dsco DescriptionTemplate=foo.txt, where foo.txt would look like:<\/p>\n<pre>&lt;table&gt;<\/pre>\n<pre>\u00a0&lt;tr&gt;<\/pre>\n<pre>\u00a0 &lt;th&gt;City&lt;\/th&gt;<\/pre>\n<pre>\u00a0 &lt;td&gt;[city]&lt;\/td&gt;<\/pre>\n<pre>\u00a0 &lt;th&gt;Province&lt;\/th&gt;<\/pre>\n<pre>\u00a0 &lt;td&gt;[province]&lt;\/td&gt;<\/pre>\n<pre>\u00a0&lt;\/tr&gt;<\/pre>\n<pre>&lt;\/table&gt;<\/pre>\n<p>Or anything the user specified, for that matter.\u00a0 Then OGR would then use for each feature&#8217;s &lt;description&gt; element.<\/p>\n<p>Anyways, here&#8217;s the resulting <a title=\"map\" href=\"http:\/\/maps.google.com\/?q=http:\/\/www.kralidis.ca\/gocanada\/parishdirectory2.kml\">map<\/a>.\u00a0 Cool!<\/p>\n<link rel=\"stylesheet\" href=\"http:\/\/cdn.leafletjs.com\/leaflet-0.5\/leaflet.css\" \/>\n<!--[if lte IE 8]>\n  <link rel=\"stylesheet\" href=\"http:\/\/cdn.leafletjs.com\/leaflet-0.5\/leaflet.ie.css\" \/>\n<![endif]-->\n<script src=\"http:\/\/cdn.leafletjs.com\/leaflet-0.5\/leaflet.js\"><\/script>\n<style type=\"text\/css\">#map375 { width: 300px; height: 200px; }<\/style>\n\n<div id=\"map375\"><\/div>\n<script type=\"text\/javascript\">\n  var map375 = L.map('map375').setView([43.620495, -79.513198], 10);\n  L.tileLayer('http:\/\/{s}.tile.osm.org\/{z}\/{x}\/{y}.png', {\n      attribution: '&copy; <a href=\"http:\/\/osm.org\/copyright\">OpenStreetMap<\/a> contributors'\n  }).addTo(map375);\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>When looking for phone numbers for various churches, I thought wouldn&#8217;t it be neat to put the locations on a map? Python to the rescue.\u00a0 After some scraping to generate a CSV listing, I geocoded the addresses, then I used the OGR to convert into a KML document, using the same approach I previously blogged [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,7,3,11],"tags":[],"class_list":["post-375","post","type-post","status-publish","format-standard","hentry","category-geospatial","category-open-source","category-technology","category-web"],"_links":{"self":[{"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/posts\/375","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/comments?post=375"}],"version-history":[{"count":6,"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/posts\/375\/revisions"}],"predecessor-version":[{"id":380,"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/posts\/375\/revisions\/380"}],"wp:attachment":[{"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/media?parent=375"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/categories?post=375"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kralidis.ca\/blog\/wp-json\/wp\/v2\/tags?post=375"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}