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('&','&')
desc = desc.replace('&','&')
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.
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\’
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.
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
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?
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. 🙂
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 :-).
Didn’t know about that Google Earth fix! Interesting.
Hi,
When trying to use your script as posted above, I received the following error:
I fixed this by updating line 23:
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!
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”. 😉
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.
I wasn’t planning any further development on this project, but feel free to put your versions on a blog of your own. 😉
OK, the script paste didn’t work properly even though I used “code” tags. WordPress clearly doesn’t like code.
Really appreciate this script. The resulting kml is missing the node, however. Peace out.
“Document” node is missing from result.kml and my previous comment 🙂
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.
Sorry, but I haven’t got a clue! Don’t even know what this “shape file” you’re talking about is!
Ditto about the “Document” part missing.
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!
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
Hmm… that’s unfortunate. Could you provide me with the CSV data that results inthat error?