22 June 2019

国土交通省地図・Google MapsのKMLからPlacemarkの緯度・経度を抽出するPerlスクリプト

国土地理院地図Webサイト、またはGoogle Mapsマイマップで作成したKMLファイルから、Placemarkとして作成した地点の緯度・経度を抽出するスクリプト

Placemark以外の図形データ(直線など)は抽出出力されないようにしている

#!/usr/bin/perl
#
# 国土交通省地図またはGoogle Mapsマイマップで作成したKMLファイルより
# 地点座標(Placemarkの緯度・軽度)を抜き出すスクリプト
 
use strict;
use warnings;
use XML::Simple;
use Encode;
use utf8;
 
# 処理対象ファイルのユーザ入力と存在確認
print "kml placemark parseer\ninput KML filename ? : ";
my $filename = <STDIN>;
chomp($filename);
if ( !-f $filename ) {
    print "error: file $filename does not exist\.n";
    exit;
}
print $filename . " exist.\n";
 
my $xs = new XML::Simple( NoSort => 1 );
my $myFile = $xs->XMLin($filename);
 
# 国土地理院地図 KML
{
    while ( my ( $key, $folder ) = each %{ $myFile->{Document}{Placemark} } ) {
        $key =~ s/[\r\n]//;    # 改行を削除
        my $coord = $folder->{Point}->{coordinates};
 
        # Placemark以外の図形などのとき、その行の表示を省略する場合 次の行を有効化
        if ( !$coord ) { next; }
 
        # Placemarkが未定義または空白のとき、画面出力エラーを回避するためダミー文字を設定
        $coord = ( !$coord || $coord eq '' ) ? "undefined" : $coord;
        $coord =~ s/[\r\n ]+//g;    # 改行と空白文字を削除
 
        # 画面表示
        print Encode::encode( 'utf-8', $key ) . "," . $coord . "\n";
    }
}
 
# Google Maps KML (Folderタグでグループ分けされている場合)
{
    while ( my ( $key0, $folder0 ) = each %{ $myFile->{Document}{Folder} } ) {
        $key0 =~ s/[\r\n]//;        # 改行を削除
        if ( ref $folder0 ne ref {} ) {
        # $folder0がハッシュのリファレンスでない場合は処理スキップ
            next;
        }
        while ( my ( $key1, $folder1 ) = each %{ $folder0->{Placemark} } ) {
            $key1 =~ s/[\r\n]//;    # 改行を削除
            my $coord = $folder1->{Point}->{coordinates};
 
            # Placemark以外の図形などのとき、その行の表示を省略する場合 次の行を有効化
            if ( !$coord ) { next; }
 
            # Placemarkが未定義または空白のとき、画面出力エラーを回避するためダミー文字を設定
            $coord = $coord ? $coord : "undefined";
            $coord =~ s/[\r\n ]+//g;    # 改行と空白文字を削除
 
            # 画面表示
            print Encode::encode( 'utf-8', $key0 ) . ","
              . Encode::encode( 'utf-8', $key1 ) . ","
              . $coord . "\n";
        }
    }
}
 
# Google Maps KML
{
    while ( my ( $key, $folder ) =
            each %{ $myFile->{Document}{Folder}{Placemark} } )
    {
        $key =~ s/[\r\n]//;    # 改行を削除
        my $coord = $folder->{Point}->{coordinates};
 
        # Placemark以外の図形などのとき、その行の表示を省略する場合 次の行を有効化
        if ( !$coord ) { next; }
 
        # Placemarkが未定義または空白のとき、画面出力エラーを回避するためダミー文字を設定
        $coord = ( !$coord || $coord eq '' ) ? "undefined" : $coord;
        $coord =~ s/[\r\n ]+//g;    # 改行と空白文字を削除
 
        # 画面表示
        print Encode::encode( 'utf-8', $key ) . "," . $coord . "\n";
    }
}

入力KMLファイルの例

検証したサンプルKMLファイルは次のようなもの

Google Mapsのマイマップで作成したKMLファイルの例
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
  <Document>
    <name>テスト地図</name>
    <description/>
    <Style id="icon-1899-0288D1-nodesc-normal">
      <IconStyle>
        <color>ffd18802</color>
        <scale>1</scale>
        <Icon>
          <href>http://www.gstatic.com/mapspro/images/stock/503-wht-blank_maps.png</href>
        </Icon>
        <hotSpot x="32" xunits="pixels" y="64" yunits="insetPixels"/>
      </IconStyle>
      <LabelStyle>
        <scale>0</scale>
      </LabelStyle>
      <BalloonStyle>
        <text><![CDATA[<h3>$[name]</h3>]]></text>
      </BalloonStyle>
    </Style>
    <Style id="icon-1899-0288D1-nodesc-highlight">
      <IconStyle>
        <color>ffd18802</color>
        <scale>1</scale>
        <Icon>
          <href>http://www.gstatic.com/mapspro/images/stock/503-wht-blank_maps.png</href>
        </Icon>
        <hotSpot x="32" xunits="pixels" y="64" yunits="insetPixels"/>
      </IconStyle>
      <LabelStyle>
        <scale>1</scale>
      </LabelStyle>
      <BalloonStyle>
        <text><![CDATA[<h3>$[name]</h3>]]></text>
      </BalloonStyle>
    </Style>
    <StyleMap id="icon-1899-0288D1-nodesc">
      <Pair>
        <key>normal</key>
        <styleUrl>#icon-1899-0288D1-nodesc-normal</styleUrl>
      </Pair>
      <Pair>
        <key>highlight</key>
        <styleUrl>#icon-1899-0288D1-nodesc-highlight</styleUrl>
      </Pair>
    </StyleMap>
    <Style id="line-000000-1200-nodesc-normal">
      <LineStyle>
        <color>ff000000</color>
        <width>1.2</width>
      </LineStyle>
      <BalloonStyle>
        <text><![CDATA[<h3>$[name]</h3>]]></text>
      </BalloonStyle>
    </Style>
    <Style id="line-000000-1200-nodesc-highlight">
      <LineStyle>
        <color>ff000000</color>
        <width>1.8</width>
      </LineStyle>
      <BalloonStyle>
        <text><![CDATA[<h3>$[name]</h3>]]></text>
      </BalloonStyle>
    </Style>
    <StyleMap id="line-000000-1200-nodesc">
      <Pair>
        <key>normal</key>
        <styleUrl>#line-000000-1200-nodesc-normal</styleUrl>
      </Pair>
      <Pair>
        <key>highlight</key>
        <styleUrl>#line-000000-1200-nodesc-highlight</styleUrl>
      </Pair>
    </StyleMap>
    <Folder>
      <name>無題のレイヤ</name>
      <Placemark>
        <name>六甲山</name>
        <styleUrl>#icon-1899-0288D1-nodesc</styleUrl>
        <Point>
          <coordinates>
            135.2637017,34.7782377,0
          </coordinates>
        </Point>
      </Placemark>
      <Placemark>
        <name>生駒山</name>
        <styleUrl>#icon-1899-0288D1-nodesc</styleUrl>
        <Point>
          <coordinates>
            135.6788864,34.6786909,0
          </coordinates>
        </Point>
      </Placemark>
      <Placemark>
        <name>愛宕山</name>
        <styleUrl>#icon-1899-0288D1-nodesc</styleUrl>
        <Point>
          <coordinates>
            135.6323964,35.062002,0
          </coordinates>
        </Point>
      </Placemark>
      <Placemark>
        <name>京阪神</name>
        <styleUrl>#line-000000-1200-nodesc</styleUrl>
        <LineString>
          <tessellate>1</tessellate>
          <coordinates>
            135.7684394,35.011648,0
            135.1964637,34.6898955,0
            135.502021,34.693283,0
            135.7663795,35.006024,0
          </coordinates>
        </LineString>
      </Placemark>
    </Folder>
  </Document>
</kml>
国土地理院地図Webサイトで作成したKMLファイルの例
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Style id="PolyStyle1">
  <IconStyle>
  <Icon>
  <href>https://maps.gsi.go.jp/portal/sys/v4/symbols/080.png</href>
  </Icon>
  <scale>1</scale>
  </IconStyle>
</Style>
<Style id="LineStyle2">
  <LineStyle>
  <color>7f000000</color>
  <width>3</width>
  </LineStyle>
</Style>
<Placemark>
<name>六甲山</name>
<styleUrl>#PolyStyle1</styleUrl>
<Point>
<coordinates>135.26371479034427,34.7779272998788</coordinates>
</Point>
</Placemark>
<Placemark>
<name>生駒山</name>
<styleUrl>#PolyStyle1</styleUrl>
<Point>
<coordinates>135.678985118866,34.67847314663942</coordinates>
</Point>
</Placemark>
<Placemark>
<name>愛宕山</name>
<styleUrl>#PolyStyle1</styleUrl>
<Point>
<coordinates>135.63432633876803,35.06001031133523</coordinates>
</Point>
</Placemark>
<Placemark>
<name>京阪神</name>
<styleUrl>#LineStyle2</styleUrl>
<LineString>
<coordinates>135.7566833496094,35.0209997011147 135.1847076416016,34.69081552362161 135.5204772949219,34.68573411017608 135.75462341308597,35.01481391761678</coordinates>
</LineString>
</Placemark>
</Document>
</kml>

スクリプトの出力例

kml placemark parseer
input KML filename ? : gmap2.kml
gmap2.kml exist.
六甲山,135.2637017,34.7782377,0
愛宕山,135.6323964,35.062002,0
生駒山,135.6788864,34.6786909,0