การแปลงไฟล์ CSV เป็น KML

Mano Marks จากทีม Google Geo API
มีนาคม 2008

วัตถุประสงค์

บทแนะนํานี้จะพูดถึงพื้นฐานวิธีสร้าง KML จากข้อมูลค่าที่คั่นด้วยคอมมา (CSV) โดยใช้ Python ข้อมูล CSV เป็นรูปแบบหนึ่งที่ใช้กันอย่างแพร่หลายที่สุดในทุกวันนี้ สเปรดชีตและฐานข้อมูลส่วนใหญ่จะอ่านและเขียนไฟล์ CSV ได้ รูปแบบง่ายๆ นี้สามารถแก้ไขได้ในเครื่องมือแก้ไขข้อความ ภาษาโปรแกรมจํานวนมาก เช่น Python มีไลบรารีพิเศษสําหรับอ่านและเขียนไฟล์ CSV วิธีนี้เป็นสื่อที่ยอดเยี่ยมในการแลกเปลี่ยนข้อมูลจํานวนมาก

แม้ว่าตัวอย่างโค้ดในบทแนะนํานี้จะเป็น Python แต่ก็สามารถปรับให้เข้ากับภาษาโปรแกรมอื่นๆ ส่วนใหญ่ได้ บทแนะนํานี้จะใช้รหัสจากที่อยู่แบบเข้ารหัสภูมิศาสตร์เพื่อใช้ใน KML เพื่อเปลี่ยนที่อยู่เป็นพิกัดลองจิจูด/ละติจูด และยังใช้องค์ประกอบ <ExtendedData> ใหม่ของ KML 2.2 และใช้ประโยชน์จากเทมเพลตลูกโป่งบอลลูนที่ระบุไว้ในการเพิ่มข้อมูลที่กําหนดเอง ด้วยเหตุนี้ KML ที่ยังไม่รองรับการใช้งานใน Google Maps หรือแอปพลิเคชันอื่นๆ ที่ใช้ KML ในปัจจุบัน แต่ก็สามารถปรับเปลี่ยนโค้ดเพื่อสร้าง KML ที่เข้ากันได้กับ Maps ได้

ข้อมูลตัวอย่าง

ดูบทแนะนํานี้ได้โดยใช้ไฟล์ 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" รายการที่ 2 "ที่อยู่1" เป็นต้น Python สามารถเปลี่ยนเป็นคอลเล็กชันของ dicts ที่เรียกว่า DictReader ซึ่งช่วยให้คุณเลื่อนดูแต่ละแถวได้ ตัวอย่างโค้ดนี้อาศัยการทราบล่วงหน้าว่าโครงสร้างข้อมูลคืออะไร แต่คุณสามารถเพิ่มตัวแฮนเดิลพื้นฐานบางอย่างเพื่อส่งโครงสร้างช่องแบบไดนามิกได้

การแยกวิเคราะห์ไฟล์ CSV

โมดูล xml.dom.minidom ของ Python มีเครื่องมือที่ยอดเยี่ยมสําหรับการสร้างเอกสาร XML และเนื่องจาก KML เป็น XML คุณจึงต้องใช้โค้ดนี้ค่อนข้างมากในบทแนะนํานี้ คุณสร้างองค์ประกอบด้วย createElement หรือ createElementNS และต่อท้ายองค์ประกอบอื่นด้วย appendChild ขั้นตอนการแยกวิเคราะห์ไฟล์ CSV และสร้างไฟล์ KML มีดังนี้

  1. นําเข้า Geocode_for_chromebook.py ลงในโมดูลของคุณ
  2. สร้าง DictReader สําหรับไฟล์ CSV DictReader คือคอลเล็กชันของ dicts 1 แถวต่อแถว
  3. สร้างเอกสารโดยใช้ xml.dom.minidom.Document() ของ Python
  4. สร้างเอลิเมนต์ <kml> ระดับรูทโดยใช้ createElementNS.
  5. เพิ่มต่อท้ายเอกสาร
  6. สร้างเอลิเมนต์ <Document> โดยใช้ createElement
  7. ต่อท้ายองค์ประกอบ <kml> โดยใช้ appendChild
  8. สําหรับแต่ละแถว ให้สร้างองค์ประกอบ <Placemark> และต่อท้ายองค์ประกอบ <Document>
  9. สําหรับแต่ละคอลัมน์ในแต่ละแถว ให้สร้างองค์ประกอบ <ExtendedData> และต่อท้ายองค์ประกอบ <Placemark> ที่คุณสร้างขึ้นในขั้นตอนที่ 8
  10. สร้างเอลิเมนต์ <Data> แล้วต่อท้ายเอลิเมนต์ <ExtendedData> มอบแอตทริบิวต์ชื่อให้กับองค์ประกอบ <Data> และกําหนดค่าของชื่อคอลัมน์โดยใช้ setAttribute
  11. สร้างเอลิเมนต์ <value> แล้วต่อท้ายเอลิเมนต์ <Data> สร้างโหนดข้อความ แล้วกําหนดค่าของคอลัมน์โดยใช้ createTextNode เพิ่มโหนดข้อความต่อท้ายองค์ประกอบ <value>
  12. สร้างเอลิเมนต์ <Point> แล้วต่อท้ายเอลิเมนต์ <Placemark> สร้างเอลิเมนต์ <coordinates> แล้วต่อท้ายเอลิเมนต์ <Point>
  13. ดึงที่อยู่ออกจากแถวเพื่อให้เป็นสตริงเดียวในรูปแบบนี้ ได้แก่ ที่อยู่1,ที่อยู่2,เมือง,รัฐ,รหัสไปรษณีย์ แถวแรกคือ 1600 Amphitheater Parkway,,Mountain View,CA,94043 แต่หากมีเครื่องหมายจุลภาคอยู่ข้างๆ กันก็ไม่เป็นไร โปรดทราบว่าคุณต้องรู้ก่อนว่าไฟล์ CSV มีคอลัมน์ใดและคอลัมน์ใดประกอบด้วยที่อยู่ดังกล่าว
  14. ใส่รหัสภูมิศาสตร์ให้กับที่อยู่โดยใช้โค้ด geocode_for_ KML.py อธิบายใน Geosetting Address for Use in KML ซึ่งจะแสดงผลสตริงที่เป็นลองจิจูดและละติจูดของสถานที่
  15. สร้างโหนดข้อความและกําหนดค่าของพิกัดในขั้นตอนที่ 14 แล้วนําไปต่อท้ายองค์ประกอบ <coordinates>
  16. เขียนเอกสาร KML ลงในไฟล์
  17. หากคุณส่งชื่อคอลัมน์เป็นอาร์กิวเมนต์ไปยังสคริปต์ สคริปต์จะเพิ่มองค์ประกอบตามลําดับนั้น หากไม่สนใจลําดับขององค์ประกอบ เราอาจใช้ 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 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> แต่ละรายการไม่มีองค์ประกอบ <BalloonStyle><text> และไม่มีองค์ประกอบ <description> บอลลูนจึงมีค่าเริ่มต้นเป็นรูปแบบตาราง ทําให้อยู่บนองค์ประกอบ <Data>

ภาพหน้าจอของ KML ที่สร้างโดยสคริปต์นี้

ข้อควรพิจารณาเกี่ยวกับการเข้ารหัสพิกัดภูมิศาสตร์

มีการพูดถึงเรื่องนี้ใน "ที่อยู่ทางภูมิศาสตร์สําหรับการใช้งานใน KML" แต่มีการกล่าวซ้ําๆ คําขอการเข้ารหัสพิกัดภูมิศาสตร์ของคุณจะขึ้นอยู่กับอัตราคําค้นหาสูงสุดของผู้จดทะเบียนโดเมน และคําค้นหา 15,000 ครั้งต่อวันโดยขึ้นอยู่กับ IP ของคุณ นอกจากนี้ ตัวระบุตําแหน่งจะแสดงผลรหัสสถานะ 620 หากคุณค้นหาเร็วกว่าที่มือจับได้ (ดูรายการรหัสสถานะทั้งหมดได้ ที่นี่) โปรดระบุความล่าช้าระหว่างคําขอไวลด์การ์ดแต่ละคําขอเพื่อให้แน่ใจว่าไม่ได้ส่งการค้นหาเร็วเกินไปไปยังไวลด์การ์ด คุณสามารถเพิ่มความล่าช้านี้ทุกครั้งที่ได้รับสถานะ 620 และใช้วนซ้ํา while เพื่อให้แน่ใจว่าได้เข้ารหัสที่อยู่ลงในโดเมนต่างๆ แล้วก่อนที่จะย้ายไปยังอีเมลถัดไป ซึ่งหมายความว่าหากไฟล์ CSV ของคุณมีขนาดใหญ่มาก คุณอาจต้องแก้ไขโค้ดพิกัดภูมิศาสตร์ หรือติดตามความเร็วในการสร้างหมุด และชะลอความเร็วหากคุณดําเนินการเร็วเกินไป

บทสรุป

ตอนนี้คุณสามารถใช้ Python เพื่อสร้างไฟล์ KML จากไฟล์ CSV ได้แล้ว โดยใช้โค้ดที่ให้มา ไฟล์ KML จะใช้งานได้ใน Google Earth เท่านั้น คุณสามารถแก้ไขเพื่อใช้งานได้ทั้งใน Maps และ Earth โดยใช้ <description> แทน <ExtendedData> และยังแปลงโค้ดตัวอย่างนี้เป็นภาษาโปรแกรมอื่นๆ ที่รองรับ XML ได้ง่ายด้วย

เมื่อคุณแปลงไฟล์ CSV ทั้งหมดเป็น KML เสร็จเรียบร้อยแล้ว คุณอาจต้องการดูบทความอื่นๆ เกี่ยวกับ KML เช่น การใช้ PHP และ MySQL เพื่อสร้าง KML และบทความคู่มือสําหรับนักพัฒนาซอฟต์แวร์ Google เกี่ยวกับ ExtendedData หัวข้อการเพิ่มข้อมูลที่กําหนดเอง

กลับไปด้านบน