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

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

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

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

  1. นำเข้า geocoding_for_kml.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. เข้ารหัสพิกัดภูมิศาสตร์ของที่อยู่โดยใช้โค้ด 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

โค้ด 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" แต่ก็ควรกล่าวซ้ำอีกครั้ง คำขอ Geocoding ของคุณจะขึ้นอยู่กับอัตราการค้นหาสูงสุดของ Geocoder และคำค้นหา 15,000 รายการต่อวันตาม IP ของคุณ นอกจากนี้ ตัวเข้ารหัสพิกัดภูมิศาสตร์จะแสดงรหัสสถานะ 620 หากคุณส่งคำค้นหาเร็วกว่าที่ตัวเข้ารหัสพิกัดภูมิศาสตร์จะ จัดการได้ (ดูรายการรหัสสถานะทั้งหมดได้ที่นี่) คุณสามารถ ระบุการหน่วงเวลาระหว่างคำขอ Geocode แต่ละรายการได้เพื่อให้มั่นใจว่าคุณจะไม่ส่งคำค้นหาไปยัง Geocoder เร็วเกินไป คุณสามารถเพิ่ม การหน่วงเวลานี้ได้ทุกครั้งที่ได้รับสถานะ 620 และใช้ลูป while เพื่อให้แน่ใจว่าคุณได้ เข้ารหัสพิกัดภูมิศาสตร์ของที่อยู่เรียบร้อยแล้วก่อนที่จะไปยังที่อยู่ถัดไป ซึ่งหมายความว่าหากไฟล์ CSV มีขนาดใหญ่มาก คุณอาจต้อง แก้ไขโค้ดการแปลงพิกัดภูมิศาสตร์ หรือติดตามความเร็วในการสร้าง หมุด และลดความเร็วลงหากเร็วเกินไป

บทสรุป

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

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

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