PostGISからKML出力

GDALのogr2ogrコマンドでテーブル全体をkmlにすることはできますが、
PostGISの関数にもST_AsKml()というのがあります。
この関数の引数にgeometryを渡すとkml形式で出力してくれます。

kmlは経緯度しか扱わないので、SRIDが設定されていなければなりません。
SRIDが設定されていれば、平面直角座標系の値でも経緯度に変換して出力されます。
ただし、図形要素部分しか出力しないので、
その他の必要なタグはこちらで用意する必要があります。

なので、完成形のkmlにするには結構手間はかかります。
psql-tオプションをつけて
-cオプションでSQLを指定して、リダイレクトでテキストに書き出して
編集するか、スクリプトを作るかになるかと思われます。

以下の例はPythonで、psycopg2でSQLを発行してkmlファイルに書き出す例です。
せっかくなのでついでに、ファイルに書き出した後、
作成されたkmlを引数にしてGoogle Earthを起動します。
ファイル名なんかはとりあえず適当です。
また、SQLの結果何も該当しなかったときなどのエラー処理なんかは省略しています。

import sys
import os
import psycopg2
# 日本語が出てくるようなら
import codecs

from xml.dom import getDOMImplementation
from xml.dom.minidom import parseString
from subprocess import *

def main(argv):
    impl = getDOMImplementation()
    dom = impl.createDocument(None, 'kml', None)
    root = dom.documentElement
    root.setAttribute("xmlns", "http://www.opengis.net/kml/2.2")
    doc = dom.createElement("Document")
    root.appendChild(doc)
    folder = dom.createElement("Folder")
    doc.appendChild(folder)
    name = dom.createElement("name")
    text = dom.createTextNode("test placemarks")
    name.appendChild(text)
    folder.appendChild(name)
    
    conn = psycopg2.connect("dbname='データベース名' user='ユーザ名'
    	host='ホスト名' password='パスワード'")
    cur = conn.cursor()
    cur.execute("select ST_AsKml(the_geom) from テーブル名 where 何か条件")
    rows = cur.fetchall()
    
    i = 0
    for r in rows:
        point = parseString(r[0])

        placemark = dom.createElement("Placemark")
        folder.appendChild(placemark)
        name = dom.createElement("name")
        text = dom.createTextNode("test_mark" + str(i))
        name.appendChild(text)
        placemark.appendChild(name)
        placemark.appendChild(point.documentElement)
        i = i + 1

    file = codecs.open("c:\temp\test_out.kml", "w", encoding="utf-8")

    dom.writexml(file, "", "t", "n", encoding="utf-8")

    conn.close()
    dom.unlink()

    Popen(["C:\Program Files\Google\Google Earth\client\googleearth.exe", 
    	"c:\temp\test_out.kml"])

if __name__ == "__main__":
    main(sys.argv)
アーカイブ