pykml

      在〈pykml〉中尚無留言

kml 是 Google Earth 標示圖標的副檔名,其格式其實就是 xml。

但 Google Earth 自創一些標籤,如 Placemark, StyleMap 等標籤,所以在Python中,就有 pykml 這套件將所有Google Earth的所有標籤包裝起來,而且包含了 html 的所有標籤,方便我們撰寫 kml 檔案。

使用pykml 前,請先 pip install pykml

kml標籤

.kml 檔案的最頂層標籤(tag) 為 <kml>,然後是 <Document> 標籤。<Document>標籤的一開始會有 <StyleMap> 及 <Style> 等標籤記錄<Icon>的來源。正確格式如下

<kml ......>
<Document>
<name>111年台北市346分隊坑洞案件</name>
<StyleMap id="pothole">
</StyleMap>
<Style id="pothole">
pass
</Style>
<Folder>
<Placemark>
<Point>
<coordinates>經度, 緯度, 0</coordinates>
</Point>
</Placemark>
</Folder>
</Document>
</kml>

原始碼為 makestyle.py檔,如下

from pykml.factory import KML_ElementMaker as KML
def makestyle():
    kml = KML.kml()
    doc = KML.Document(
        KML.name("111年台北市346分隊坑洞案件"),
        KML.StyleMap(
            KML.Pair(
                KML.key("normal"),
                KML.styleUrl("#pothole_h0")
            ),
            KML.Pair(
                KML.key("highlight"),
                KML.styleUrl("#pothole_h1")
            ),
            id="pothole",
        ),
        KML.StyleMap(
            KML.Pair(
                KML.key("normal"),
                KML.styleUrl("#hot_h0")
            ),
            KML.Pair(
                KML.key("highlight"),
                KML.styleUrl("#hot_h1")
            ),
            id="hot",
        ),
        KML.StyleMap(
            KML.Pair(
                KML.key("normal"),
                KML.styleUrl("#finish_h0")
            ),
            KML.Pair(
                KML.key("highlight"),
                KML.styleUrl("#finish_h1")
            ),
            id="finish",
        ),
        KML.Style(
            KML.IconStyle(
                KML.scale(1.3),
                KML.Icon(
                    KML.href("http://ip/mapicons/ticon4.png"),
                ),
            ),
            KML.hotSpot(x="20", y="2", xunits="pixels", yunits="pixels", xuints="pixels"),
            id="pothole_h0",
        ),

        KML.Style(
            KML.IconStyle(
                KML.scale(1.3),
                KML.Icon(
                    KML.href("http://ip/mapicons/ticon3.png"),
                ),
            ),
            KML.hotSpot(x="20", y="2", xunits="pixels", yunits="pixels", xuints="pixels"),
            id="hot_h0",
        ),
        KML.Style(
            KML.IconStyle(
                KML.scale(1.3),
                KML.Icon(
                    KML.href("http://ip/mapicons/ticon2.png"),
                ),
            ),
            KML.hotSpot(x="20", y="2", xunits="pixels", yunits="pixels", xuints="pixels"),
            id="finish_h0",
        ),
        KML.Style(
            KML.IconStyle(
                KML.scale(1.3),
                KML.Icon(
                    KML.href("http://ip/mapicons/ticon4.png"),
                ),
            ),
            KML.hotSpot(x="20", y="2", xunits="pixels", yunits="pixels", xuints="pixels"),
            id="pothole_h1",
        ),
        KML.Style(
            KML.IconStyle(
                KML.scale(1.3),
                KML.Icon(
                    KML.href("http://ip/mapicons/ticon3.png"),
                ),
            ),
            KML.hotSpot(x="20", y="2", xunits="pixels", yunits="pixels", xuints="pixels"),
            id="hot_h1",
        ),
        KML.Style(
            KML.IconStyle(
                KML.scale(1.3),
                KML.Icon(
                    KML.href("http://ip/mapicons/ticon2.png"),
                ),
            ),
            KML.hotSpot(x="20", y="2", xunits="pixels", yunits="pixels", xuints="pixels"),
            id="finish_h1",
        )
    )
    kml.append(doc)
    return kml, doc

todo

主檔

主檔的工作是查詢資料庫,取得資料後轉成 DataFrame格式,方便後面的存取。然後將資料傳入 makenode函數,製作 Placemaker標籤。最後將整個 kml 樹儲存到硬碟檔案中。

from pykml.factory import KML_ElementMaker as KML
from lxml import etree
from makenode import makenode
from makestyle import makestyle
import datetime
import mysql.connector as mysql
import pandas as pd

kml, doc=makestyle()
conn = mysql.connect(host="ip", user="帳號", password="密碼", database="資料庫")
cmd = f"SELECT * FROM table where 條件"
cursor = conn.cursor()
cursor.execute(cmd)
rs = cursor.fetchall()
descriptions = cursor.description
columns = []
for d in descriptions:
    columns.append(d[0])
data = []
for r in rs:
    data.append(list(r))
df = pd.DataFrame(data=data, columns=columns)
rs = df[["經度", "緯度", "巡查案號", "損壞類別", "地址","日期","地區", "完工日期", "道管編號"]]

areas=['中正區','萬華區','內湖區','南港區','大安區','文山區']
for area in areas:
    f1=KML.Folder(KML.name(area))
    doc.append(f1)
    f_ok = KML.Folder(KML.name("已完成"))
    f1.append(f_ok)
    rs_areas=rs[rs['地區']==f'{area}']
    currentDay = datetime.datetime.now().strftime('%Y-%m-%d')
    dates = pd.date_range(start="2022-01-01", end=currentDay)
    for d in dates.values:
        d=str(d).split("T")[0]
        yyyy=int(d.split("-")[0])
        mm=int(d.split("-")[1])
        dd=int(d.split("-")[2])
        rs_day=rs_areas[rs_areas['日期']==datetime.date(yyyy,mm,dd)]
        if len(rs_day)>0:
            f_no=KML.Folder(KML.name(d))
            f1.append(f_no)
            for r in rs_day.values:
                lng = r[0]
                lat = r[1]
                address = r[4]
                patrol_no=r[2]
                finishDay=r[7]
                manager_no=r[8]
                makenode(f_no, f_ok, area, d, address, lng, lat, patrol_no, finishDay, manager_no)
file="111年台北市346分隊坑洞案件"
with open(f'{file}.kml', 'wb') as output:
    output.write(etree.tostring(kml, pretty_print=True, encoding='utf-8'))

上述藍色部份 etree.tostring(kml, pretty_print=True)是為了完美列印字串用的,可以讓xml有換行,縮排的效果,讓人更容易閱讀。

makenode.py

makenode函數主要是製作 Placemark標籤

from pykml.factory import KML_ElementMaker as KML
import requests
def makenode(f_no, f_ok, area, caseday, address, lng, lat, patrol_no, finishDay, manager_no):
    ip="自已指定"
placemark = KML.Placemark(KML.name(patrol_no)) r1 = requests.get(f"http://{ip}/photo/finish/{manager_no}_1.png") r2 = requests.get(f"http://{ip}/photo/finish/{manager_no}_2.png") if "404" in str(r1): finish = False folder=f_no else: finish = True folder=f_ok if "熱燙" in address: type = "#hot" elif finish: type = "#finish" else: type = "#pothole" styleurl=KML.styleUrl(type) folder.append(styleurl) point=KML.Point( KML.coordinates(f"{lng}, {lat}, 0") ) if finish and finishDay is None: fd = "無完工資料" elif finishDay is not None: fd = f"{finishDay}" else: fd = f"尚未完工" yyy = int(caseday.split("-")[0]) - 1911 mm = caseday.split("-")[1] dd = caseday.split("-")[2] description=KML.description() table=KML.table( KML.tr( KML.td(f"巡查案號 : {patrol_no}", width="50%"), KML.td(f"道管編號 : {manager_no}", width="50%"), ), KML.tr( KML.td(f"查報時間 : {caseday}", width="50%"), KML.td(f"完工日期 : {fd}", width="50%"), ), KML.tr( KML.td("報案種類 : 坑洞", width="50%"), KML.td(f"案件地點 : {address.split('_')[0]}", width="50%"), ), KML.tr( KML.td("施工前照片", colspan="2", bgcolor="#ffff00", align="center", height="30"), ), KML.tr( KML.td( KML.a( KML.img( src=f"http://{ip}/photo/photos/{area}/{yyy}{mm}{dd}/{address}_far.png", width="640", height="480" ), href=f"http://{ip}/photo/photos/{area}/{yyy}{mm}{dd}/{address}_far.png", ), colspan="2", align="center" ), ), border="1", cellspacing="0", cellpadding="0", width="650" ) if "404" not in str(r1): tr=KML.tr( KML.td("施工後照片", colspan="2", bgcolor="#00ff00", align="center", height="30"), ) table.append(tr) tr= KML.tr( KML.td( KML.a( KML.img( src=f"http://{ip}/photo/finish/{manager_no}_1.png", width="640", height="480" ), href=f"http://{ip}/photo/finish/{manager_no}_1.png", ), colspan="2", align="center" ), ) table.append(tr) if "404" not in str(r2): tr= KML.tr( KML.td( KML.a( KML.img( src=f"http://{ip}/photo/finish/{manager_no}_2.png", width="640", height="480" ), href=f"http://{ip}/photo/finish/{manager_no}_2.png", ), colspan="2", align="center" ), ) table.append(tr) description.append(table) placemark.append(styleurl) placemark.append(point) placemark.append(description) folder.append(placemark)

todo

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *