آذار (مارس) 2008
الهدف
يوضّح هذا البرنامج التعليمي الأساسيات المتعلقة بكيفية إنشاء ملف KML من بيانات القيم المفصولة بفواصل (CSV) باستخدام Python. تُعد بيانات CSV من أكثر تنسيقات الملفات شيوعًا المستخدمة اليوم. يمكن لمعظم جداول البيانات وقواعد البيانات قراءة ملفات CSV وكتابتها. ويمكن تعديل تنسيقه البسيط في محرِّر نصوص. تتضمّن العديد من لغات البرمجة، مثل Python، مكتبات خاصة لقراءة ملفات CSV وكتابتها. لذلك، تُعدّ وسيلة رائعة لتبادل كميات كبيرة من البيانات.
مع أنّ عيّنات الرموز البرمجية في هذا البرنامج التعليمي مكتوبة بلغة Python، يمكن تكييفها لتناسب معظم لغات البرمجة الأخرى. يستخدم هذا البرنامج التعليمي الرمز من الترميز الجغرافي
للعناوين لاستخدامها في KML لتحويل
عنوان إلى إحداثيات خطوط الطول والعرض. يستخدم هذا المثال أيضًا عنصر <ExtendedData>
الجديد في KML 2.2، ويستفيد من نماذج البالونات الموضّحة في إضافة بيانات مخصّصة. وبالتالي، لا تتوافق ملفات KML التي يتم إنتاجها حاليًا مع "خرائط Google" أو التطبيقات الأخرى التي تستخدم ملفات KML، ولكن يمكن تعديل الرمز البرمجي لإنتاج ملفات KML متوافقة مع "خرائط Google".
عيّنات البيانات
في هذا البرنامج التعليمي، استخدِم الملف google-addresses.csv كنموذج لملف CSV. يحتوي هذا الملف على جميع العناوين وأرقام الهواتف وأرقام الفاكس الخاصة بمختلف مكاتب Google في الولايات المتحدة. في ما يلي نص الملف:
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,
لاحظ كيف أنّ كل سطر هو سلسلة من سلاسل النصوص مفصولة بفواصل.
يفصل كل فاصلة حقلًا، ويحتوي كل سطر على العدد نفسه من الفواصل.
يحتوي السطر الأول على أسماء الحقول بالترتيب. على سبيل المثال،
تمثّل
كتلة النص الأولى في كل صف حقل "المكتب"، والثانية حقل "العنوان1"، وما إلى ذلك. يمكن أن يحوّل Python ذلك إلى مجموعة من dicts
تُسمى DictReader
تتيح لك
التنقّل بين الصفوف. يعتمد نموذج الرمز هذا على معرفتك مسبقًا ببنية بياناتك، ولكن يمكنك إضافة بعض المعالجات الأساسية لتمرير بنية الحقل بشكل ديناميكي.
تحليل ملف CSV
يوفّر نموذج xml.dom.minidom
في Python أدوات رائعة لإنشاء مستندات XML، وبما أنّ KML هي XML، ستستخدمها بشكل كبير في هذا البرنامج التعليمي. يمكنك إنشاء عنصر باستخدام createElement
أو createElementNS
، وإلحاقه بعنصر آخر باستخدام appendChild
.
في ما يلي خطوات تحليل ملف CSV وإنشاء ملف KML.
- استورِد geocoding_for_kml.py إلى الوحدة.
- أنشئ
DictReader
لملفات CSV.DictReader
هي مجموعة منdicts
، واحدة لكل صف. - أنشئ المستند باستخدام
xml.dom.minidom.Document()
في Python. - إنشاء عنصر الجذر
<kml>
باستخدامcreateElementNS.
- إلحاقها بالمستند
- أنشئ عنصر
<Document>
باستخدامcreateElement
. - أضِفها إلى عنصر
<kml>
باستخدامappendChild
. - لكل صف، أنشئ عنصر
<Placemark>
وأضِفه إلى عنصر<Document>
. - لكل عمود في كل صف، أنشئ عنصر
<ExtendedData>
وأضِفه إلى عنصر<Placemark>
الذي أنشأته في الخطوة 8. - أنشئ عنصر
<Data>
وأضِفه إلى عنصر<ExtendedData>
. امنح العنصر<Data>
سمة اسم، وعيِّن له قيمة اسم العمود باستخدامsetAttribute
. - أنشئ عنصر
<value>
وأضِفه إلى عنصر<Data>
. أنشئ عقدة نصية، وأسنِد إليها قيمة العمود باستخدامcreateTextNode
. ألحِق عقدة النص بعنصر<value>
. - أنشئ عنصر
<Point>
وأضِفه إلى عنصر<Placemark>
. أنشئ عنصر<coordinates>
وأضِفه إلى العنصر<Point>
. - استخرِج العنوان من الصف ليكون سلسلة واحدة بالتنسيق التالي: Address1,Address2,City,State,Zip. إذًا، سيكون الصف الأول
1600 Amphitheater Parkway,,Mountain View,CA,94043
. لا بأس إذا كانت هناك فواصل بجانب بعضها البعض. يُرجى العِلم أنّ تنفيذ ذلك يتطلّب معرفة مسبقة ببنية ملف CSV والأعمدة التي تشكّل العنوان. - ترميز العنوان جغرافيًا باستخدام الرمز geocoding_for_kml.py الموضّح في الترميز الجغرافي للعناوين لاستخدامها في KML تعرض هذه السمة سلسلة تمثّل خط الطول وخط العرض للموقع الجغرافي.
- أنشئ عقدة نصية وأسنِد إليها قيمة الإحداثيات في الخطوة 14، ثم ألحِقها بالعنصر
<coordinates>
. - اكتب مستند KML في ملف.
- إذا مرّرت قائمة بأسماء الأعمدة كمعلمات إلى البرنامج النصي، سيضيف البرنامج النصي العناصر بهذا الترتيب. إذا لم يكن ترتيب العناصر مهمًا، يمكننا استخدام
dict.keys()
لإنشاءlist
. ومع ذلك، لا تحتفظdict.keys()
بالترتيب الأصلي من المستند. لاستخدام هذه الوسيطة، مرِّر أسماء الحقول في قائمة مفصولة بفواصل، على النحو التالي:python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax
نموذج لرمز Python البرمجي
في ما يلي نموذج رمز لإنشاء ملف KML من ملف CSV باستخدام Python 2.2. يمكنك أيضًا تنزيله من هنا.
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()
تم إنشاء نموذج ملف KML
في ما يلي نموذج لملف KML الذي ينشئه هذا النص البرمجي.
لاحظ كيف أنّ بعض<value>
العناصر تحتوي على مسافات بيضاء فقط. ويرجع ذلك إلى أنّ الحقل لم يتضمّن أي بيانات. يمكنك أيضًا تنزيل العيّنة الكاملة هنا.
<?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>
...
لقطة شاشة
في ما يلي لقطة شاشة توضّح شكل ملف KML هذا في Google Earth.
بما أنّ كل عنصر <Placemark>
لا يحتوي على <BalloonStyle><text>
ولا على عنصر <description>
، يتم تلقائيًا عرض البالون بنمط جدول، مع الاستفادة من عناصر <Data>
.

اعتبارات الترميز الجغرافي
وقد تم ذكر ذلك في "ترميز العناوين الجغرافية لاستخدامها في ملفات KML"،
ولكن من المهم تكرار هذه المعلومة. ستخضع طلبات الترميز الجغرافي للحد الأقصى لمعدّل طلبات البحث في أداة الترميز الجغرافي و15,000 طلب بحث في اليوم استنادًا إلى عنوان IP. بالإضافة إلى ذلك، سيعرض برنامج الترميز الجغرافي رمز الحالة 620
إذا أرسلت إليه طلبات بحث أسرع من قدرته على معالجتها. (يمكنك الاطّلاع على قائمة كاملة برموز الحالة هنا).
لضمان عدم إرسال طلبات بحث بسرعة كبيرة إلى أداة الترميز الجغرافي، يمكنك تحديد فترة تأخير بين كل طلب ترميز جغرافي. يمكنك زيادة هذا التأخير في كل مرة تتلقّى فيها حالة 620
، واستخدام حلقة while
لضمان ترميز عنوان جغرافيًا بنجاح قبل الانتقال إلى العنوان التالي. هذا يعني أنّه إذا كان ملف CSV كبيرًا جدًا، قد تحتاج إلى تعديل رمز الترميز الجغرافي أو تتبُّع سرعة إنشاء العلامات المكانية وإبطائها إذا كانت السرعة كبيرة جدًا.
الخاتمة
يمكنك الآن استخدام Python لإنشاء ملف KML من ملف CSV. باستخدام الرمز البرمجي المقدَّم، لن يعمل ملف KML إلا في Google Earth. يمكنك تعديلها لتتمكّن من استخدامها في كل من "خرائط Google" وGoogle Earth من خلال استخدام <description>
بدلاً من <ExtendedData>
.
من السهل أيضًا تحويل عيّنة الرمز هذه إلى أي لغة برمجة أخرى تتيح استخدام XML.
بعد الانتهاء من تحويل جميع ملفات CSV إلى KML، يمكنك الاطّلاع على مقالات أخرى حول KML، مثل استخدام PHP وMySQL لإنشاء KML ومقالة "دليل مطوّري Google" حول ExtendedData، إضافة بيانات مخصّصة.