تبدیل فایل های CSV به KML

Mano Marks، تیم Google Geo APIs
مارس 2008

هدف، واقعگرایانه

این آموزش اصول اولیه نحوه ایجاد KML از داده های ارزش جدا شده با کاما (CSV) با استفاده از پایتون را تشریح می کند. داده‌های CSV یکی از رایج‌ترین فرمت‌های فایلی است که امروزه مورد استفاده قرار می‌گیرد. اکثر صفحات گسترده و پایگاه داده ها می توانند فایل های CSV را بخوانند و بنویسند. فرمت ساده آن را می توان در یک ویرایشگر متن ویرایش کرد. بسیاری از زبان های برنامه نویسی مانند پایتون دارای کتابخانه های خاصی برای خواندن و نوشتن فایل های CSV هستند. بنابراین یک رسانه عالی برای تبادل مقادیر زیاد داده است.

در حالی که نمونه کدهای موجود در این آموزش در پایتون هستند، اما می توان آنها را با اکثر زبان های برنامه نویسی دیگر تطبیق داد. این آموزش از کد آدرس‌های جغرافیایی برای استفاده در KML استفاده می‌کند تا یک آدرس را به مختصات طول و عرض جغرافیایی تبدیل کند. همچنین از عنصر جدید <ExtendedData> KML 2.2 استفاده می کند و از الگوی بالون که در افزودن داده های سفارشی مشخص شده است، بهره می برد. به این ترتیب، KML تولید شده در حال حاضر در Google Maps یا سایر برنامه های کاربردی مصرف کننده KML پشتیبانی نمی شود، اما کد را می توان برای تولید KML سازگار با Maps تطبیق داد.

داده های نمونه

برای این آموزش، از فایل google-addresses.csv به عنوان نمونه فایل CSV استفاده کنید. این فایل دارای تمام آدرس ها، شماره تلفن ها و شماره فکس دفاتر مختلف گوگل در ایالات متحده است. اینم متن فایل:

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" و غیره است. پایتون می‌تواند آن را به مجموعه‌ای از dicts به نام DictReader که به شما امکان می‌دهد از هر ردیف عبور کنید. این نمونه کد متکی است که شما از قبل ساختار داده‌های خود را می‌دانید، اما می‌توانید برخی از کنترل‌کننده‌های اصلی را اضافه کنید تا ساختار فیلد را به صورت پویا منتقل کنید.

تجزیه فایل CSV

ماژول xml.dom.minidom پایتون ابزارهای عالی برای ایجاد اسناد XML فراهم می کند، و از آنجایی که KML XML است، در این آموزش به شدت از آن استفاده خواهید کرد. شما یک عنصر را با createElement یا createElementNS ایجاد می کنید و با appendChild به عنصر دیگری اضافه می کنید. این مراحل برای تجزیه فایل CSV و ایجاد یک فایل KML است.

  1. geocoding_for_kml.py را به ماژول خود وارد کنید.
  2. یک DictReader برای فایل های CSV ایجاد کنید. DictReader مجموعه ای از dicts ها است که برای هر سطر یکی است.
  3. سند را با استفاده از xml.dom.minidom.Document() پایتون ایجاد کنید.
  4. عنصر ریشه <kml> را با استفاده از createElementNS.
  5. آن را به سند اضافه کنید .
  6. با استفاده از createElement یک عنصر <Document> ایجاد کنید.
  7. آن را با استفاده از appendChild به عنصر <kml> اضافه کنید.
  8. برای هر ردیف، یک عنصر <Placemark> ایجاد کنید و آن را به عنصر <Document> اضافه کنید.
  9. برای هر ستون در هر ردیف، یک عنصر <ExtendedData> ایجاد کنید و آن را به عنصر <Placemark> که در مرحله 8 ایجاد کردید اضافه کنید.
  10. یک عنصر <Data> ایجاد کنید و آن را به عنصر <ExtendedData> اضافه کنید. به عنصر <Data> یک ویژگی نام بدهید و با استفاده از setAttribute مقدار نام ستون را به آن اختصاص دهید.
  11. یک عنصر <value> ایجاد کنید و آن را به عنصر <Data> اضافه کنید. یک گره متنی ایجاد کنید و با استفاده از createTextNode مقدار ستون را به آن اختصاص دهید. گره متن را به عنصر <value> اضافه کنید.
  12. یک عنصر <Point> ایجاد کنید و آن را به عنصر <Placemark> اضافه کنید. یک عنصر <coordinates> ایجاد کنید و آن را به عنصر <Point> اضافه کنید.
  13. آدرس را از ردیف خارج کنید تا یک رشته در این قالب باشد: Address1, Address2, City, State, Zip. بنابراین ردیف اول 1600 Amphitheater Parkway,,Mountain View,CA,94043 خواهد بود. اگر کاما در کنار هم باشد اشکالی ندارد. توجه داشته باشید، برای انجام این کار نیاز به دانش قبلی از ساختار فایل CSV و اینکه کدام ستون ها آدرس را تشکیل می دهند، است.
  14. آدرس را با استفاده از کد geocoding_for_kml.py که در آدرس های جغرافیایی برای استفاده در KML توضیح داده شده است، کدگذاری کنید. این یک رشته را برمی گرداند که طول و عرض جغرافیایی مکان است.
  15. یک گره متن ایجاد کنید و مقدار مختصات را در مرحله 14 به آن اختصاص دهید، سپس آن را به عنصر <coordinates> اضافه کنید.
  16. سند KML را در یک فایل بنویسید.
  17. اگر لیستی از نام ستون ها را به عنوان آرگومان به اسکریپت ارسال کنید، اسکریپت عناصر را به ترتیب اضافه می کند. اگر به ترتیب عناصر اهمیت نمی‌دادیم، می‌توانیم از dict.keys() برای تولید یک list استفاده کنیم. با این حال، dict.keys() نظم اصلی را از سند حفظ نمی کند. برای استفاده از این آرگومان، لیست نام فیلدها را به عنوان یک لیست جدا شده با کاما ارسال کنید، مانند این:
    python csvtokml.py Office,Address1,Address2,Address3,City,State,Zip,Phone,Fax

نمونه کد پایتون

کد نمونه برای ایجاد یک فایل 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 a  element 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 <Placemark> هیچ عنصر <BalloonStyle><text> و <description> ندارد، بالون به طور پیش‌فرض به یک سبک جدول می‌پردازد که بر روی عناصر <Data> طراحی می‌شود.

تصویری از KML ایجاد شده توسط این اسکریپت

در نظر گرفتن ژئوکدینگ

این مورد در «آدرس‌های کدگذاری جغرافیایی برای استفاده در KML» ذکر شده است، اما باید تکرار شود. درخواست‌های کدگذاری جغرافیایی شما مشمول حداکثر نرخ پرس و جو و 15000 درخواست در روز بر اساس IP شما خواهد بود. به‌علاوه، اگر سریع‌تر از آنچه که می‌تواند آن را پرس و جو کنید، کد وضعیت 620 توسط geocoder بازگردانده می‌شود. (لیست کامل کدهای وضعیت در اینجا موجود است .) برای اطمینان از اینکه درخواست ها را خیلی سریع به geocoder ارسال نمی کنید، می توانید یک تاخیر بین هر درخواست geocode تعیین کنید. می‌توانید هر بار که وضعیت 620 را دریافت می‌کنید، این تأخیر را افزایش دهید و از حلقه while استفاده کنید تا اطمینان حاصل کنید که یک آدرس را قبل از تکرار به آدرس بعدی با موفقیت رمزگذاری جغرافیایی کرده‌اید. این به این معنی است که اگر فایل CSV شما بسیار بزرگ است، ممکن است مجبور شوید کد جغرافیایی را تغییر دهید یا سرعت ایجاد Placemarks را پیگیری کنید و اگر خیلی سریع پیش می‌روید سرعت آن را کاهش دهید.

نتیجه

اکنون می توانید از پایتون برای ایجاد یک فایل KML از یک فایل CSV استفاده کنید. با استفاده از کد ارائه شده، فایل KML فقط در Google Earth کار می کند. می‌توانید با استفاده از <description> به جای <ExtendedData> آن را تغییر دهید تا در Maps و Earth کار کند. همچنین تبدیل این نمونه کد به هر زبان برنامه نویسی دیگری که از XML پشتیبانی می کند آسان است.

اکنون که تبدیل همه فایل‌های CSV خود به KML را تمام کرده‌اید، ممکن است بخواهید سایر مقالات KML مانند استفاده از PHP و MySQL برای ایجاد KML و مقاله راهنمای توسعه‌دهنده Google در ExtendedData، افزودن داده‌های سفارشی را بررسی کنید.

بازگشت به بالا