آذار (مارس) 2008
الغرض
توضح هذه الدورة التعليمية أساسيات إنشاء KML من بيانات قيم مفصولة بفواصل (CSV) باستخدام Python. بيانات CSV هي أحد تنسيقات الملفات الأكثر انتشارًا المستخدمة اليوم. يمكن لمعظم جداول البيانات وقواعد البيانات قراءة ملفات CSV وكتابتها على حد سواء. ويمكن تعديل تنسيقه البسيط في محرر نصوص. يتوفر للعديد من لغات البرمجة، مثل Python، مكتبات خاصة لقراءة ملفات CSV وكتابتها. ولذلك فهو يوفّر وسيلة رائعة لتبادل كميات كبيرة من البيانات.
على الرغم من أن نماذج التعليمات البرمجية في هذا البرنامج التعليمي متوفرة بلغة Python، إلا أنه يمكن تطويعها لتتناسب مع معظم لغات البرمجة الأخرى. يستخدم هذا البرنامج التعليمي شفرة من عناوين الترميز الجغرافي للاستخدام في KML لتحويل العنوان إلى إحداثيات خطوط الطول/العرض. كما يستخدم أيضًا عنصر <ExtendedData>
الجديد في KML
2.2، كما يستفيد من نماذج البالون الموضحة في إضافة
البيانات المخصصة. وبناءً على ذلك، فإن ملف KML الذي تم إنتاجه غير معتمد حاليًا في خرائط Google أو التطبيقات الأخرى التي تستخدم ملفات KML، ولكن يمكن تهيئة الشفرة لإنتاج ملف KML متوافق مع الخرائط.
نموذج البيانات
بالنسبة إلى هذا البرنامج التعليمي، استخدم ملف 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,
لاحظ كيف أن كل سطر عبارة عن سلسلة من السلاسل النصية مفصولة بفواصل.
تُحدِّد كل فاصلة حقلاً؛ ويكون لكل سطر العدد نفسه من الفواصل.
يحتوي السطر الأول على أسماء الحقول بالترتيب. على سبيل المثال، الجزء الأول من النص في كل صف هو حقل "Office" والحقل الثاني "Address1" وما إلى ذلك. يمكن لـ Python تحويل هذا النص إلى مجموعة من ملفات dicts
تُسمى DictReader
، وتسمح لك بالتنقل في كل صف. يعتمد نموذج الشفرة هذا على معرفة بنية بياناتك مسبقًا، ولكن يمكنك إضافة بعض المعالجات الأساسية لتمرير بنية الحقل ديناميكيًا.
تحليل ملف CSV
تقدم وحدة xml.dom.minidom
بيثون
أدوات رائعة لإنشاء مستندات 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"، لكن الأمر يتطلب تكرارًا. وستخضع طلبات الترميز الجغرافي
لمعدل طلب البحث الأقصى في أداة
الترميز الجغرافي و15000 طلب بحث في اليوم الواحد استنادًا إلى عنوان 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، وإضافة بيانات مخصصة.