Convert CSV to KML (for Google Maps)

Update: my CSV to KML python script is now available as an online converter, right here:

http://csv2kml.appspot.com

Woah! This means I went through all the trouble of developing a Google App Engine App just so some of you can convert their POI data files! (You can thank me later.) However, it uses the same core code as posted below (which is very basic), so some problems might arise. I’m not saying they will! It’s just a warning. If you have any problems with the convertor or remarks, please post them in the comment section of this post.

Update #2: I revised the code for this project. It now no longer needs to replace characters that are unsupported in certain encodings! Additionally, the online convertor now lets you choose what encoding the CSV file is in. It will assume ISO-Latin 1 if you don’t provide an encoding type.

Let’s say you have a CSV (Comma Separated Values) file with locations that you want to add to Google Maps. Tough luck! Google Maps only swallows KML files.

After fruitlessly googling for “csv2kml” etc. for a while, I frustratingly put on my robe and wizard hat and said: “I’ll do it myself. DAMMIT!”. And so I did. (Well, minus the robe, hat and talking to myself parts.)
The following Python script takes a CSV file ‘file.csv’ and generates a brand spanking new ‘file.kml’, ready to be parsed by Google Maps.
f = open('file.csv')
a = f.read()
f.close()
b = a.split('\n')
r = '<?xml version="1.0" encoding="UTF-8"?>\n<kml xmlns="http://www.opengis.net/kml/2.2">'
for x in b:
  x = x.replace(', ',',').decode('latin-1','ignore')
  y = x.split(',')
  if len(y) < 3:
    break
  elif len(y) > 3:
    desc = ' '.join(y[3:])
  else:
    desc = 'No description'

  # Replacing non-XML-allowed characters here (add more if needed)
  y[2] = y[2].replace('&','&amp;')

  desc = desc.replace('&','&amp;')

  r += '\n<Placemark><name>'+y[2].encode('utf-8','xmlcharrefreplace')+'</name>' \
    '\n<description>'+desc.encode('utf-8','xmlcharrefreplace')+'</description>\n' \
    '<Point><coordinates>'+y[0]+','+y[1]+',0</coordinates></Point>\n</Placemark>'

r += '\n</kml>'
f = open('file.kml','w')
f.write(r)
f.close()
In order to use the resulting KML file, select ‘Create new map’, then ‘import’ in the ‘My Maps’ section. Note that after importing, Google might cut off the list of landmarks after a certain number. However, if you save the map and return to it later, you’ll find that it indeed included all data points.
I used the KML tutorial on code.google.com as a reference for this project. It mentions that you can add additional fields to the ones mentioned here, but for this code to work, the CSV file should have a format like: “latitude, longitude, name [,description]” (description is optional). Everything after ‘name’ will just be lumped together in the description field. Feel free to add your own fields where necessary.
Note how I’m replacing some characters like ‘&’ and ‘ë’, ‘ö’, etc. You will want to check your own CSV file for any special characters unsupported in XML (or just KML?) fields and replace those as well. Otherwise, Google will present you with a delightfully uninformative ‘Upload of file failed’-alert.
An example of a successfully imported converted CSV file, can be found here. It was made with this parking space data from ANWB.nl (Netherlands-only, and still disappointingly limited).
Note: I’m well aware that this post is quite Google-centric, as was the previous. This is purely coincidental. Google is evil, etc. etc., but it is also quite useful sometimes.
This entry was posted in Geen categorie. Bookmark the permalink.

20 Responses to Convert CSV to KML (for Google Maps)

  1. Unknown says:

    Sounds great but doesn\’t work: File "csv2kml.py", line 5, in <module> c = b.decode(\’latin-1\’,\’ignore\’)AttributeError: \’list\’ object has no attribute \’decode\’

  2. Louis says:

    It still seems to work for me… If you have problems with a particular file, please post a link to it, so I can see what\’s going wrong.

  3. Konrad says:

    Looks like a great and simple script. Unfortunately, I also got the same error,

    Traceback (most recent call last):
    File “c2k.py”, line 5, in
    c = b.decode(‘latin-1′,’ignore’)
    AttributeError: ‘list’ object has no attribute ‘decode’

    With this csv file:

    63.463929,11.114269,Hegra,Hegra Tag
    63.430487,10.395061,Trondheim,Hegra Tag
    68.43838,17.427196,Narvik,Hegra Tag

  4. Konrad says:

    Could this be because “decode” works only on strings, now mutable lists? What about adding a loop that decodes on each item in the list?

    • Louis says:

      You’re completely right! I’m afraid I had sloppily altered the code in this post without testing…
      The Google App version (and the now corrected code above) indeed decodes the items in the list in the loop. 🙂

  5. Omblegurf says:

    Thanks, you probably just saved me at least an hour! One thing though: I found that when importing to Google Earth, only the first placemark would be imported. After reading this page I managed to fix it by wrapping all the placemarks in a (Document) element — that is, put a (Document) after the (kml) and a (/Document) before the (/kml). [Please replace all round brackets with angle brackets — not sure how to get real angle brackets through the comment box.] Apart from that, worked like a dream… well, expect that I transposed latitude and longitude on my first attempt and ended up in the Mariana trench, but I have only myself to blame for that :-).

  6. PhillC says:

    Hi,

    When trying to use your script as posted above, I received the following error:

    Traceback (most recent call last):
      File "csv2kml.py", line 23, in 
        ''+y[0]+','+y[1]+',0\n'
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 29: ordinal not in range(128)
    

    I fixed this by updating line 23:

        ''+y[0].encode('utf-8','xmlcharrefreplace')+','+y[1].encode('utf-8','xmlcharrefreplace')+',0\n'
    

    The exact same CSV file worked without a problem via your online tool. It was only by pure chance I found your blog (maybe worth a link from the online tool page) because I was looking for a script I could customise for additional KML field.

    Thanks!

    • Louis says:

      Glad it was of some help to you! I’m aware the Google App engine version works better than the script posted here, which is meant more as a sort of “look behind the scenes”. 😉

      • PhillC says:

        The script here is great though, because I can customise it to create a more detailed schema.

        For example, I wanted to include customer map icon styles. I also excaped some more non-XML characters so that a linked HTML url, or indeed any other code tag, could be used in the description column. This is done by adding another column to the csv, which now looks like:

        lat,long,name,style,description

        Your script, with just one pre-determined style looks like this:

        f = open('data.csv')
        a = f.read()
        f.close()
        b = a.split('\n')
        r = '\n\n\n\nhttp://www.earthpoint.us/Dots/GoogleEarth/pal2/icon56.png\n\n\n'
        for x in b:
        x = x.replace(', ',',').decode('utf-8','ignore')
        y = x.split(',')
        if len(y) 4:
        desc = ' '.join(y[4:])
        else:
        desc = 'No description'

        # Replacing non-XML-allowed characters here (add more if needed)
        y[2] = y[2].replace('&','&')

        desc = desc.replace('&','&')
        desc = desc.replace('>','>')
        desc = desc.replace('<','<')

        r += '\n'+y[2].encode('utf-8','xmlcharrefreplace')+'' \
        '\n'+desc.encode('utf-8','xmlcharrefreplace')+'' \
        '\n'+y[3].encode('utf-8','xmlcharrefreplace')+'\n' \
        ''+y[0].encode('utf-8','xmlcharrefreplace')+','+y[1].encode('utf-8','xmlcharrefreplace')+',0\n'

        r += '\n'
        f = open('output.kml','w')
        f.write(r)
        f.close()

        “style” column should contain “#style1” for a custom map marker to work. Add more “style IDs” in variable ‘r’ for more markers.

        I’m happy to continue sharing this script as I continue to update if you’re interested.

      • Louis says:

        I wasn’t planning any further development on this project, but feel free to put your versions on a blog of your own. 😉

  7. PhillC says:

    OK, the script paste didn’t work properly even though I used “code” tags. WordPress clearly doesn’t like code.

  8. JC says:

    Really appreciate this script. The resulting kml is missing the node, however. Peace out.

  9. Baby Sharma says:

    Hi there,

    I have a network xml file. I want to convert it to shape file. I have converted .xml file into nodes.csv and links.csv. I managed to convert nodes to shp but there is problem in converting links .csv to shp.
    Any clue would be great.

  10. Bryan says:

    Ditto about the “Document” part missing.

  11. Katrina J. says:

    In case you need to import Google Earth kml format to gpx or to make gpx files to kml, there’s a good converter free out there. It’s called http://gpx2kml.com/ , it’s free, easy to use and no installation required. Give it a try, maybe it’s useful!

  12. I received the following error.
    Traceback (most recent call last):
    File “”, line 28, in
    f.close()”’)
    File “”, line 4
    b = a.split(‘
    ^
    SyntaxError: EOL while scanning string literal

Leave a reply to Louis Cancel reply