Mars 2008
Objectif
Ce tutoriel explique les bases de la création de fichiers KML à partir de données CSV (Comma Separated Value) à l'aide de Python. Les données CSV sont l'un des formats de fichier les plus répandus aujourd'hui. La plupart des feuilles de calcul et des bases de données peuvent lire et écrire des fichiers CSV. Son format simple peut être modifié dans un éditeur de texte. De nombreux langages de programmation, comme Python, disposent de bibliothèques spéciales pour lire et écrire des fichiers CSV. Il constitue donc un excellent moyen d'échanger de grandes quantités de données.
Bien que les exemples de code de ce tutoriel soient en Python, ils peuvent être adaptés à la plupart des autres langages de programmation. Ce tutoriel utilise le code de Géocoder des adresses pour les utiliser dans KML afin de convertir une adresse en coordonnées de longitude/latitude. Il utilise également le nouvel élément <ExtendedData>
de KML 2.2 et tire parti des modèles de ballon décrits dans Ajouter des données personnalisées. Par conséquent, le fichier KML produit n'est actuellement pas compatible avec Google Maps ni avec d'autres applications utilisant le format KML. Toutefois, le code peut être adapté pour produire un fichier KML compatible avec Maps.
Exemples de données
Pour ce tutoriel, utilisez le fichier google-addresses.csv comme exemple de fichier CSV. Ce fichier contient toutes les adresses, numéros de téléphone et numéros de fax des différents bureaux Google aux États-Unis. Voici le texte du fichier :
Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax Headquarters,1600 Amphitheatre Parkway,,,Mountain View,CA,94043,650-253-0000,650-253-0001 New York Sales & Engineering Office,76 Ninth Avenue,,,New York,NY,10011,212-565-0000,212-565-0001 Ann Arbor Sales Office,201 South Division Street,,,Ann Arbor,MI,48104,734-332-6500,734-332-6501 Atlanta Sales & Engineering Office,10 10th Street NE,,,Atlanta,GA,30309,404-487-9000,404-487-9001 Boulder Sales & Engineering Office,2590 Pearl St.,,,Boulder,CO,80302,303-245-0086,303-535-5592 Cambridge Sales & Engineering Office,5 Cambridge Center,,,Cambridge,MA,02142,617-682-3635,617-249-0199 Chicago Sales & Engineering Office,20 West Kinzie St.,,,Chicago,IL,60610,312-840-4100,312-840-4101 Coppell Sales Office,701 Canyon Drive,,,Coppell,TX,75019,214-451-4000,214-451-4001 Detroit Sales Office,114 Willits Street,,,Birmingham,MI,48009,248-351-6220,248-351-6227 Irvine Sales & Engineering Office,19540 Jamboree Road,,,Irvine,CA,92612,949-794-1600,949-794-1601 Pittsburgh Engineering Office,4720 Forbes Avenue,,,Pittsburgh,PA,15213,, Santa Monica Sales & Engineering Office,604 Arizona Avenue,,,Santa Monica,CA,90401,310-460-4000,310-309-6840 Seattle Engineering Office,720 4th Avenue,,,Kirkland,WA,98033,425-739-5600,425-739-5601 Seattle Sales Office,501 N. 34th Street,,,Seattle,WA,98103,206-876-1500,206-876-1501 Washington D.C. Public Policy Office,1001 Pennsylvania Avenue NW,,,Washington,DC,20004,202-742-6520,
Remarquez que chaque ligne est une série de chaînes de texte séparées par des virgules.
Chaque virgule délimite un champ. Chaque ligne comporte le même nombre de virgules.
La première ligne contient les noms des champs dans l'ordre. Par exemple, le premier bloc de texte de chaque ligne correspond au champ "Office", le deuxième à "Address1", etc. Python peut transformer cela en une collection de dicts
appelée DictReader
, qui vous permet de parcourir chaque ligne. Cet exemple de code repose sur votre connaissance préalable de la structure de vos données, mais vous pouvez ajouter des gestionnaires de base pour transmettre la structure des champs de manière dynamique.
Analyser le fichier CSV
Le module xml.dom.minidom
de Python fournit d'excellents outils pour créer des documents XML. Comme KML est un langage XML, vous l'utiliserez beaucoup dans ce tutoriel. Vous créez un élément avec createElement
ou createElementNS
, et l'ajoutez à un autre élément avec appendChild
.
Voici les étapes à suivre pour analyser le fichier CSV et créer un fichier KML.
- Importez geocoding_for_kml.py dans votre module.
- Créez un
DictReader
pour les fichiers CSV.DictReader
est une collection dedicts
, une pour chaque ligne. - Créez le document à l'aide de
xml.dom.minidom.Document()
de Python. - Créez l'élément
<kml>
racine à l'aide decreateElementNS.
. - Ajoutez-le au document
.
- Créez un élément
<Document>
à l'aide decreateElement
. - Ajoutez-le à l'élément
<kml>
à l'aide deappendChild
. - Pour chaque ligne, créez un élément
<Placemark>
et ajoutez-le à l'élément<Document>
. - Pour chaque colonne de chaque ligne, créez un élément
<ExtendedData>
et ajoutez-le à l'élément<Placemark>
que vous avez créé à l'étape 8. - Créez un élément
<Data>
et ajoutez-le à l'élément<ExtendedData>
. Donnez à l'élément<Data>
un attribut de nom et attribuez-lui la valeur du nom de la colonne à l'aide desetAttribute
. - Créez un élément
<value>
et ajoutez-le à l'élément<Data>
. Créez un nœud de texte et attribuez-lui la valeur de la colonne à l'aide decreateTextNode
. Ajoutez le nœud de texte à l'élément<value>
. - Créez un élément
<Point>
et ajoutez-le à l'élément<Placemark>
. Créez un élément<coordinates>
et ajoutez-le à l'élément<Point>
. - Extrayez l'adresse de la ligne pour qu'elle soit une seule chaîne dans ce format : Address1,Address2,City,State,Zip. La première ligne serait donc
1600 Amphitheater Parkway,,Mountain View,CA,94043
. Ce n'est pas grave si des virgules sont côte à côte. Notez que pour ce faire, vous devez connaître la structure du fichier CSV et les colonnes qui constituent l'adresse. - Géocodez l'adresse à l'aide du code geocoding_for_kml.py expliqué dans Géocoder des adresses à utiliser dans KML. Cela renvoie une chaîne correspondant à la longitude et à la latitude de l'emplacement.
- Créez un nœud de texte et attribuez-lui la valeur des coordonnées de l'étape 14, puis ajoutez-le à l'élément
<coordinates>
. - Écrivez le document KML dans un fichier.
- Si vous transmettez une liste de noms de colonnes en tant qu'arguments au script, celui-ci ajoutera les éléments dans cet ordre. Si l'ordre des éléments ne nous intéressait pas, nous pourrions utiliser
dict.keys()
pour produire unlist
. Toutefois,dict.keys()
ne conserve pas l'ordre d'origine du document. Pour utiliser cet argument, transmettez la liste des noms de champs sous forme de liste séparée par des virgules, comme suit :python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax
Exemple de code Python
Vous trouverez ci-dessous un exemple de code permettant de créer un fichier KML à partir d'un fichier CSV à l'aide de Python 2.2. Vous pouvez également le télécharger ici.
import geocoding_for_kml
import csv
import xml.dom.minidom
import sys
def extractAddress(row):
# This extracts an address from a row and returns it as a string. This requires knowing
# ahead of time what the columns are that hold the address information.
return '%s,%s,%s,%s,%s' % (row['Address1'], row['Address2'], row['City'], row['State'], row['Zip'])
def createPlacemark(kmlDoc, row, order):
# This creates aelement for a row of data.
# A row is a dict.
placemarkElement = kmlDoc.createElement('Placemark')
extElement = kmlDoc.createElement('ExtendedData')
placemarkElement.appendChild(extElement)
# Loop through the columns and create a element for every field that has a value.
for key in order:
if row[key]:
dataElement = kmlDoc.createElement('Data')
dataElement.setAttribute('name', key)
valueElement = kmlDoc.createElement('value')
dataElement.appendChild(valueElement)
valueText = kmlDoc.createTextNode(row[key])
valueElement.appendChild(valueText)
extElement.appendChild(dataElement)
pointElement = kmlDoc.createElement('Point')
placemarkElement.appendChild(pointElement)
coordinates = geocoding_for_kml.geocode(extractAddress(row))
coorElement = kmlDoc.createElement('coordinates')
coorElement.appendChild(kmlDoc.createTextNode(coordinates))
pointElement.appendChild(coorElement)
return placemarkElement
def createKML(csvReader, fileName, order):
# This constructs the KML document from the CSV file.
kmlDoc = xml.dom.minidom.Document()
kmlElement = kmlDoc.createElementNS('http://earth.google.com/kml/2.2', 'kml')
kmlElement.setAttribute('xmlns','http://earth.google.com/kml/2.2')
kmlElement = kmlDoc.appendChild(kmlElement)
documentElement = kmlDoc.createElement('Document')
documentElement = kmlElement.appendChild(documentElement)
# Skip the header line.
csvReader.next()
for row in csvReader:
placemarkElement = createPlacemark(kmlDoc, row, order)
documentElement.appendChild(placemarkElement)
kmlFile = open(fileName, 'w')
kmlFile.write(kmlDoc.toprettyxml(' ', newl = '\n', encoding = 'utf-8'))
def main():
# This reader opens up 'google-addresses.csv', which should be replaced with your own.
# It creates a KML file called 'google.kml'.
# If an argument was passed to the script, it splits the argument on a comma
# and uses the resulting list to specify an order for when columns get added.
# Otherwise, it defaults to the order used in the sample.
if len(sys.argv) >1: order = sys.argv[1].split(',')
else: order = ['Office','Address1','Address2','Address3','City','State','Zip','Phone','Fax']
csvreader = csv.DictReader(open('google-addresses.csv'),order)
kml = createKML(csvreader, 'google-addresses.kml', order)
if __name__ == '__main__':
main()
Exemple de fichier KML créé
Vous trouverez ci-dessous un exemple du fichier KML créé par ce script.
Notez que certains éléments<value>
ne contiennent que des espaces. En effet, le champ ne contenait aucune donnée. Vous pouvez également télécharger l'exemple complet sur cette page.
<?xml version="1.0" encoding="utf-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<Placemark>
<ExtendedData>
<Data name="Office">
<value>
Headquarters
</value>
</Data>
<Data name="Address1">
<value>
1600 Amphitheater Parkway
</value>
</Data>
<Data name="City">
<value>
Mountain View
</value>
</Data>
<Data name="State">
<value>
CA
</value>
</Data>
<Data name="Zip">
<value>
94043
</value>
</Data>
<Data name="Phone">
<value>
650-253-0000
</value>
</Data>
<Data name="Fax">
<value>
650-253-0001
</value>
</Data>
</ExtendedData>
<Point>
<coordinates>
-122.081783,37.423111
</coordinates>
</Point>
</Placemark>
...
Capture d'écran
Vous trouverez ci-dessous une capture d'écran montrant à quoi ressemble ce fichier KML dans Google Earth.
Comme chaque élément<Placemark>
ne comporte aucun élément<BalloonStyle><text>
ni<description>
, la bulle adopte par défaut un style de tableau, en s'appuyant sur les éléments<Data>
.

Éléments à prendre en compte pour le geocoding
Cela a été mentionné dans "Géocoder des adresses à utiliser dans KML", mais il est important de le répéter. Vos demandes de géocodage seront soumises au taux de requêtes maximal du géocodeur et à 15 000 requêtes par jour en fonction de votre adresse IP. De plus, le geocoder renverra un code d'état 620
si vous l'interrogez plus rapidement qu'il ne peut le gérer. (Une liste complète des codes d'état est disponible ici.)
Pour vous assurer de ne pas envoyer de requêtes trop rapidement au géocodeur, vous pouvez spécifier un délai entre chaque requête de géocodage. Vous pouvez augmenter ce délai chaque fois que vous recevez un état 620
et utiliser une boucle while
pour vous assurer d'avoir correctement géocodé une adresse avant de passer à la suivante. Cela signifie que si votre fichier CSV est très volumineux, vous devrez peut-être modifier le code de géocodage ou suivre la vitesse à laquelle vous créez des repères et la ralentir si vous allez trop vite.
Conclusion
Vous pouvez désormais utiliser Python pour créer un fichier KML à partir d'un fichier CSV. Le fichier KML ne fonctionnera que dans Google Earth avec le code fourni. Vous pouvez le modifier pour qu'il fonctionne à la fois dans Maps et Earth en utilisant <description>
au lieu de <ExtendedData>
.
Il est également facile de convertir cet exemple de code dans n'importe quel autre langage de programmation compatible avec XML.
Maintenant que vous avez terminé de convertir tous vos fichiers CSV au format KML, vous pouvez consulter d'autres articles sur le format KML, comme Utiliser PHP et MySQL pour créer des fichiers KML et l'article du guide du développeur Google sur ExtendedData, Ajouter des données personnalisées.