2023-07-01

国交省の海岸線データをいい感じに整形する

Pythonアルゴ

国土交通省が提供する海岸線データのXMLファイルを使用するとき,データの整形に手間取ったのでメモ.

この前,日本の海岸線データが必要になることがあったので,その際にしたことを書き残しておく.

やったこと

XMLファイルをダウンロードする

日本の海岸線データは,国土交通省の提供する国土数値情報ダウンロードサイトの「海岸線データ」からダウンロードすることができる.

データは都道府県ごとにXML形式で保存されていたので,ためしに茨城県のファイルC23-06_08.xmlをダウンロードしてみた.

XMLファイルの中身を調べる

まずは適当なエディタでXMLファイルを開いてみると,こんな感じの構造になっている(一部省略・整形している).

<dataset>
    <ksj:object>
        <ksj:AA01>
            <ksj:RES idref="rs001" />
                <ksj:OBJ>
                    <jps:GM_Point id="p_00001">
                        <!-- GM_Pointの中身 -->
                    </jps:GM_Point>
                    <!-- ... -->
                    <jps:GM_Curve id="c_00001">
                        <!-- GM_Curveの中身 -->
                    </jps:GM_Curve>
                    <!-- ... -->
                </ksj:OBJ>
            </ksj:RES>
        </ksj:AA01>
    </ksj:object>
</dataset>

てっきり,海岸線データはひとつながりの折れ線で記述されていて,折れ線を構成する頂点の座標が順番に格納されていると思っていたが,どうやら違うらしい.

実際には次のようになっている.

このように,海岸線データは断片ごとに分かれて記述されているので,実際にデータを利用する際には,これをひとつながりの折れ線データに変換したほうが便利である.

困ったことに,断片の並び順はばらばらで,必ずしも実際の海岸線の順番に並んでいない.加えて,データの中には,本体の海岸線データのほかに島の海岸線データも含まれている.そんなわけで,データの整形はちょっと面倒そう.

海岸線データを整形する

書き慣れているPythonで書くことにした.

XMLファイルの読み込みとパースにはxml.etree.ElementTreeモジュールを使う.XMLのノードの子要素を検索するときにはfind, findallメソッドを使うとよいが,要素名に独自の名前空間ksj, jpsが使われているので少しはまった.調べてみると,namespacesプロパティに名前空間を定義するDictionaryを指定すれば解決するらしい.

import xml.etree.ElementTree as ET

namespaces = {
    'ksj': 'http://nlftp.mlit.go.jp/ksj/schemas/ksj-app',
    'jps': 'http://www.gsi.go.jp/GIS/jpgis/standardSchemas'
}

tree = ET.parse("C23-06_08.xml")
root = tree.getroot()

for child in root:
    if child.tag == "dataset":
        for gm_point in child.findall(
            path="ksj:object/ksj:AA01/ksj:OBJ/jps:GM_Point",
            namespaces=namespaces
        ):
            # 処理
            pass

XMLが読み込めたら,データを整形する(それぞれの断片をつなぎあわせる)作業に移る.

競プロ脳なのでグラフの問題に帰着させて考えてしまうのだけれど,要するにこういうことである:

実装する際には頂点を「代表点」のIDで管理すればよい.