Mars 2008
Objectif
Ce tutoriel présente les principes de base de la création de fichiers KML à partir de données CSV (valeurs séparées par une virgule) à l'aide de Python. Les données CSV sont l'un des formats de fichier les plus omniprésents actuellement. La plupart des feuilles de calcul et des bases de données peuvent lire et écrire des fichiers CSV. Vous pouvez le modifier dans un éditeur de texte. De nombreux langages de programmation, tels que Python, possèdent des bibliothèques spéciales pour lire et écrire des fichiers CSV. Par conséquent, il constitue un excellent support pour l'échange 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 geocoding des adresses à utiliser dans KML pour transformer 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 d'info-bulles décrits dans Ajouter des données personnalisées. Par conséquent, le fichier KML généré n'est actuellement pas compatible avec Google Maps ni dans d'autres applications utilisant KML, mais le code peut être adapté pour produire des fichiers KML compatibles avec Maps.
Exemple 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 américains. 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,
Notez que chaque ligne est une série de chaînes de texte séparées par une virgule.
Chaque virgule délimite un champ. Chaque ligne contient 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 dans chaque ligne est le champ "Office", le second "Address1", etc. Python peut le transformer en collection de dicts
appelée DictReader
, ce qui vous permet de parcourir chaque ligne. Cet exemple de code repose sur la 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. Étant donné que KML est au format XML, vous l'utiliserez assez largement dans ce tutoriel. Vous devez créer un élément avec createElement
ou createElementNS
, puis l'ajouter à 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 fichier
DictReader
pour les fichiers CSV.DictReader
est une collection dedicts
, une pour chaque ligne. - Créez le document à l'aide de l'
xml.dom.minidom.Document()
de Python. - Créez l'élément racine
<kml>
à 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>
. Attribuez un nom à l'élément<Data>
, puis 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 afin qu'il s'agisse d'une chaîne unique au format suivant: Address1,Address2,City,State,Zip. La première ligne correspond donc à
1600 Amphitheater Parkway,,Mountain View,CA,94043
. Ne pas ajouter de virgules l'une à côté de l'autre Notez que cela nécessite de connaître au préalable 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. Cette opération renvoie une chaîne correspondant à la longitude et à la latitude du lieu.
- Créez un nœud de texte et attribuez-lui la valeur des coordonnées à 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 ajoute des éléments dans cet ordre. Si l'ordre des éléments ne nous intéresse pas, nous pourrions utiliser
dict.keys()
pour produire unlist
. Toutefois,dict.keys()
ne conserve pas l'ordre d'origine dans le document. Pour utiliser cet argument, transmettez la liste des noms de champs sous la forme d'une liste d'éléments séparés par une virgule, comme ceci :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 la 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 code KML créé
Vous trouverez ci-dessous un exemple de code 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
Voici une capture d'écran de ce fichier KML dans Google Earth.
Comme chaque élément <Placemark>
n'a pas d'élément <BalloonStyle><text>
ni d'élément <description>
, l'info-bulle utilise un style de tableau par défaut, utilisant les éléments <Data>
.
Décision d'achat dans le geocoding
Cela a été mentionné dans "Geocoding Addresses for Use in KML" (Géocoder des adresses pour une utilisation dans KML), mais il n'est pas rare de le répéter. Vos requêtes de geocoding seront soumises au taux de requête maximal du geocoder 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 traiter. (Une liste complète des codes d'état est disponible ici.)
Pour vous assurer que vous n'envoyez pas de requêtes trop rapidement au geocoder, vous pouvez spécifier un délai entre chaque requête de geocode. Vous pouvez augmenter ce délai chaque fois que vous recevez l'état 620
et utiliser une boucle while
pour vous assurer d'avoir géocodé une adresse avant de créer une itération pour 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 ralentir si vous allez trop vite.
Conclusion
Vous pouvez maintenant utiliser Python pour créer un fichier KML à partir d'un fichier CSV. Avec le code fourni, le fichier KML ne fonctionnera que dans Google Earth. Vous pouvez le modifier pour qu'il fonctionne à la fois dans Maps et Earth à l'aide de <description>
au lieu de <ExtendedData>
.
Vous pouvez facilement convertir cet exemple de code dans tout autre langage de programmation compatible XML.
Maintenant que vous avez fini de convertir tous vos fichiers CSV au format KML, vous pouvez consulter d'autres articles sur KML, tels que Utiliser PHP et MySQL pour créer un fichier KML, et l'article du guide du développeur Google sur ExtendedData, Ajouter des données personnalisées.