User:Konat/ksj2osm-river.pl

From OpenStreetMap Wiki
Jump to: navigation, search

主たる用途

国土数値情報(河川データ)XMLをOpenStreetMapのXMLに変換するために用います。

説明

変換元データファイルの入手先

このスクリプトでできること

  • 変換元の都道府県別河川データ丸ごと大きなOSM向けXMLデータを生成できます。
  • 特定の河川指定でOSM向けXMLデータを生成できます。

生成するOSMデータについて

  • 情報ソースを示すタグはWayにのみ付与しノードには付与しません。
  • 水域ラベルは現時点[1]では殆ど提供されていないため生成しません(水域コードのみ生成)。
  • Wayは基本的に waterway:riverで生成します。ただし、下記条件に一致する場合は、waterway:stream で生成します。
    • 名称不明 は 一律 stream。
    • COPが4(指定区間外),8(指定区間外かつ湖沼区間を兼ねる),0(不明)の何れかで、かつ、河川名称の末尾が 沢、谷、ヤツ、クボ、窪、入、俣、タルの何れかの場合。
  • Wayにレイヤタグを一律設定します(デフォルト -1)
  • 名称不明のwaterwayにname関連タグは付与しません。
  • 一括変換の場合にはnameタグのみ付与します。他のname関連タグ(name:enなど)は付与しません。

実行環境について

  • ksj2osm-river.pl と ksj2osm-river-rebuild.pl の2本セットで機能します。
  • WindowsXP Pro環境でのみ動作確認を行っています。尚、Windows環境でのPerlおよび必要となるプラグインについては他のインポータスクリプトの要件と同等です。

スクリプトの使い方について

  • ksj2osm-river.pl のヘッダを参照してください。

インポート作業について

とある「わたし」のやりかた
  • 分割されたウェイの重複ノードの排除。
  • 隣接都道府県中のウェイに接続すべきウェイの重複ノードの排除。
  1. JOSMでValidationプラグインを利用可能にしておきます。
  2. JOSMに読み込みます。(都道府県別データを一括で読み込む場合は環境により時間が掛かります。)
  3. 「妥当性検証エラー」レイヤーをOFFにします。(おすすめ)
  4. "データの妥当性を検証"を実行します。
  5. レポートされるノードの複製を"エラー">"ノードの複製"から"修正"ボタンを押下して一括修正します。
  6. (ここで念のためデータを保存)
  7. OSMにアップロードします。(チャンクサイズ500とか1000とか・・・進捗を把握しやすいです)
  8. アップロードしたデータが隣接する他都道府県の境界周辺データをOSMよりダウンロードします。
  9. 境界周辺オブジェクトをマメに矩形選択して、都度、前掲と同様にノードの複製を修正し是正していきます。
  10. この変更をアップロード。
アップロード中は作業マシンが自動的にrebootしたり電源が落ちないように配慮しましょう・・・changesetのrevertスクリプトを学ぶことになってしまいます。

コード

ksj2osm-river.pl

#! /usr/bin/perl


use strict;
use warnings;
# use encoding "utf8";
use encoding "utf8", STDIN => "shiftjis",  STDOUT => "shiftjis", STDERR => "shiftjis"; # for Windows
use Encode;
use open IO => "utf8";
use XML::LibXML;

#####
#
# KSJ2 River Data
#
# National-Land Numerical Information (River) 2006, MLIT Japan
# 国土数値情報(河川データ)平成18年 国土交通省
#
#       ・河川Wayは上流→下流でデータを生成します。
#       ・情報ソースを示すタグはWayにのみ付与しノードには付与しません。
#       ・水域ラベルは現状殆ど提供されていないため生成しません(水域コードのみ生成)
#       ・Wayは基本的に waterway:riverで生成します。
#         ただし、下記条件に一致する場合は、waterway:stream で生成します。
#          - 名称不明 は 一律 stream。
#               - $unknown_is_stream = "no" とすることで riverで出力可能。
#          - COPが4(指定区間外),8(指定区間外かつ湖沼),0(不明)の何れかで、
#            かつ、河川名称の末尾が 沢、谷、ヤツ、クボ、窪、入、俣、タルの何れかの場合。
#               - $stream_on = "no" とすることで riverで出力可能。
#       ・Wayにレイヤタグを一律設定します(デフォルト -1)
#       
# 使い方
#       ・UTF-8で保存した変換対象の国土数値情報(河川データ)のXMLファイルを
#         本スクリプトと同じフォルダに配置します。
#       ・ksj2osm-revier-rebuild.pl を同じディレクトリに配置してください。
#       ・スクリプトはすべて必ずUTF-8で保存してください。
#       ・用途に応じて下記のパラメータを書き換えて本スクリプトを保存し実行します。
#          - file_in                       : 変換対象河川情報XMLデータ(必須)
#          - selected_river_name           : 特定河川のみ変換する場合設定 例. 多摩川
#          - selected_river_name_en        : 特定河川のみ変換する場合設定 例. Tama-River
#          - selected_river_name_jprm      : 特定河川のみ変換する場合設定 例. Tamagawa
#          - force_write_node              : 特定河川のみ変換の際に全ノードを出力するか
#          - need_to_write_node_detail_tag : ノードに詳細タグを付与して生成するか
#          - layer                         : レイヤ・タグの数値(デフォルト:-1)
#
# 実行方法
#
#    <用例.1> 河川データXML中のwaterwayを全変換する場合(つまり都道府県ごと一括)
#
#       ksj2osm-river.pl 引数なし
#
#         但し、スクリプト内の下記のパラメータを予めすべて""(空文字)に設定しておくこと。
#
#        ・$selected_river_name      = "";
#        ・$selected_river_name_en   = "";
#        ・$selected_river_name_jprm = "";
#
#    <用例.2> 特定河川のみ変換する 
#             - 変換対象河川をスクリプト呼び出しパラメータで指定したい場合
#
#             ※但し、Windows実行環境でのみ有効。Windows実行環境ではない場合は、用例3を参照のこと。
#
#       ksj2osm-river.pl [変換対象河川名(日本語)] [ローマ字表記河川名] [英語表示河川名]
#
#        ・変換対象河川名(日本語) : $selected_river_name相当
#        ・ローマ字表記河川名       : $selected_river_name_jprm相当
#        ・英語表示河川名           : $selected_river_name_en相当
#
#       例. ksj2osm-river.pl 多摩川 Tamagawa Tama-River
#
#    <用例.3> 特定河川のみ変換する
#             - 変換したい河川をスクリプト内埋め込み定義パラメータで指定したい場合
#
#       ksj2osm-river.pl 引数なし
#
#        ・selected_river_name      : 特定河川のみ変換する場合設定 例. 多摩川
#        ・selected_river_name_en   : 特定河川のみ変換する場合設定 例. Tama-River
#        ・selected_river_name_jprm : 特定河川のみ変換する場合設定 例. Tamagawa
#
# Files
#   Input
#     XML file : W05-08_*.xml
#   Output
#     Osm file : ksj2osm-river-nn[name:en]00n.osm
#            または
#                ksj2osm-river-nn-[name:en]-all.osm
#
# 本スクリプトについて
#   miyabi氏公開の ksj2osm-coastline.pl をベースとし改造して作成したものです。
#   公開を前提にコードを修正してこなかったため、私しか読めないこんなものに仕上がりましたw
#
#
#####

#our $file_in = "W05-07_47";                    # target file 沖縄
our $file_in = "W05-08_11";                     # target file 埼玉
#our $file_in = "W05-08_13";                     # target file 東京
#our $file_in = "W05-08_14";                    # target file 神奈川
#our $file_in = "W05-07_17";                    # target file 石川
#our $file_in = "W05-07_02";                    # target file 青森
#our $file_in = "W05-07_42";                    # target file 長崎
#our $file_in = "W05-07_41";                    # target file 佐賀
#our $file_in = "W05-07_18";                    # target file 福井
#our $file_in = "W05-07_16";                    # target file 富山


# 特定の河川のみ変換したい場合、河川名をUTF-8で定義する。
# 全てのデータを変換したい場合、""を定義する。
# ※特定河川変換の場合、基本動作として生成するOSMファイルを分割しません。
# 但し、$force_write_node = "yes" とした場合は分割します。
#our $selected_river_name = "琴沢";
#our $selected_river_name = "野川";
#our $selected_river_name = "石神井川";
#our $selected_river_name = "北川";
our $selected_river_name = "";

# 特定の河川のみ変換したい場合、河川名ローマ字読みを定義する。
# 全てのデータを変換したい場合、""を定義する。
# ※このローマ字を定義した場合のみ、変換ファイル名(jprmを引用)と各タグ(name:en,name:jp_rm)に反映される。
#     スペース入れないでね
#our $selected_river_name_jprm = "Tamagawa";
#our $selected_river_name_en = "Tama River";
our $selected_river_name_jprm = "";
our $selected_river_name_en = "";
#our $selected_river_name_jprm = "Shakujiigawa";
#our $selected_river_name_en = "Shakujii River";
#our $selected_river_name_jprm = "Nogawa";
#our $selected_river_name_en = "Ochisawa";
#our $selected_river_name_jprm = "Kita-Gawa";
#our $selected_river_name_en = "Kitagawa-River";


# ノード情報に詳細タグを付与しないで出力したい場合"no"
# ※但しWayには詳細タグを強制付与します。
our $need_to_write_node_detail_tag = "no" ;

# ※いろいろ書いてますがもはや yes のままで良いです。
# 特定河川変換の際にはノード情報も河川名を参照してマッチする
# ノード情報のみ出力しますが、Wayで参照するノード情報に河川名が
# 設定されておらず、ノード参照エラーとなる場合に"yes”と
# 定義することで、無関係なノードも出力しますがエラーには
# ならないようにします。
# この場合は出力OSMファイルを強制的に分割することで余計なノード数を減らします。
our $force_write_node = "yes" ;

# 特定の河川のみ変換した際に、分割されたOSMファイルを1つにまとめるか
# yes = まとめる  ファイル名は ksj2osm-river-nn[name:en]-all.osm として出力。
# yes以外 = まとめない
# ※yesでまとめる指定をしても分割ファイルも出力されます。不要ですので手動で削除してください。
our $combine_all = "yes";

# 沢 などを waterway=stream で出力する場合は yes
# 条件は、COPが4(指定区間外),8指定区間外でか湖沼(),0(不明)の何れかで、
# かつ、河川名称の末尾が 沢、谷、ヤツ、クボ、窪、入、俣、タルの何れかの場合に適用する。
our $stream_on = "yes";
# さらに、COPは上記と同一条件で、「名称不明」をstreamで出力する場合
our $unknown_is_stream = "yes";

# レイヤ・タグ埋め込み数値
our $layer = -1 ;

# デバッグ用情報出力レベル
our $dbg_level = 98;

###################################################### you dont need to change
our $max_ways = 30;  # for splitting output files.
#our $max_ways = 9999999;  # for splitting output files.
our $max_nodes_per_file = 1500;  # max nodes per a file
#our $max_nodes_per_file = 9999999;  # max nodes per a file

our $file_name = "ksj2osm-river";
our $max_nodes_per_way = 1500;  # max nodes per a way


our $current_osmfn;
our $any_valid_data_in_osmfile;
our @osm_ndref;
our $all_osmfn;
###################################################### you dont need to change



sub open_log() {

 my $time = localtime(time);
 open(LOG, ">$file_name.log"); 
 print LOG "***** KSJ2 River Data 2006 : Start $time\n"; 
 print "***** KSJ2 River Data 2006 : Start $time\n";

}  # end sub open_log()


sub close_log() {

 my $time = localtime(time);
 print LOG "***** Done!: End $time\n"; 
 close LOG; 
 print "***** Done!: End $time\n";

}  # end sub close_log()


################# rebuild_osm_file が うまく動かない。。。 #################

sub is_print_node() {

 my $id = $_[0];
 foreach my $ndref ( @osm_ndref ) {
   if ( $id eq $ndref->getAttribute('ref') ) { return (1 ); }
 }
 return ( 0 ) ;
}


sub rebuild_osm_file() {

 my ($count_files) = @_;

 my $osmfn = sprintf("%s-%s%s-%03d.osm", $file_name, substr($file_in,7,2),$selected_river_name_jprm,$count_files);
 my $osmtempfn = ">__tempfile__$count_files.xml";

 open(OSMTMP, $osmtempfn);

 my $xml = XML::LibXML->new();

#                my $osm_doc1 = $xml->parse_string($osmfn);
#               print Dumper($osm_doc1)."\n";

 my $osm_doc1 = $xml->parse_file("$osmfn") or die "can't parse $osmfn: $@";
 my @osm_node = $osm_doc1->getElementsByTagName('node')->get_nodelist();
 my @osm_way = $osm_doc1->getElementsByTagName('way')->get_nodelist();
 @osm_ndref = $osm_doc1->getElementsByTagName('nd')->get_nodelist();

 print OSMTMP "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
 print OSMTMP "<osm version=\"0.5\" generator=\"KSJ2OSM\">\n";

 foreach my $way ( @osm_way ) {
   printf OSMTMP ("%s\n",$way->toString(1));
 }

 foreach my $node ( @osm_node ) {
   my $id = $node->getAttribute('id');
   if ( &is_print_node( $id ) ne 0 ) { printf OSMTMP ("%s\n",$node->toString(1)); }
 }

 print OSMTMP "</osm>";
 close OSMTMP;

} # end of rebuild_osm_file()

################# rebuild_osm_file が うまく動かない。。。 #################


sub open_osm_file() {

 my ($count_files) = @_;
 my $osmfn = ">";

 $current_osmfn = sprintf("%s-%s%s-%03d.osm", $file_name, substr($file_in,7,2),$selected_river_name_jprm,$count_files);
 $any_valid_data_in_osmfile = "no";

 $osmfn .= $current_osmfn;

 open(OSM, $osmfn);
 print OSM "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
 print OSM "<osm version=\"0.5\" generator=\"KSJ2OSM\">\n";


}  # end sub open_osm_file()


sub close_osm_file(){

 my ($count_files) = @_;

 print OSM "</osm>";
 close OSM;

 if ( $any_valid_data_in_osmfile eq "no" ) {
   my $status_unlink = unlink( $current_osmfn );
 } else {
##    if ( $selected_river_name ne "" ) { &rebuild_osm_file($count_files); }
   if ( $selected_river_name ne "" ) {
     if ( $combine_all eq "yes" || $combine_all eq "yesopened" ) {
       if ( $combine_all ne "yesopened" ) {
         $combine_all = "yesopened";
         $all_osmfn = sprintf("%s-%s-%s-all.osm", $file_name, substr($file_in,7,2),$selected_river_name_jprm);
         print "FILENAME is ".$all_osmfn."\n";
         open ALLOSM, ">"."$all_osmfn";
         print ALLOSM "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
         print ALLOSM "<osm version=\"0.5\" generator=\"KSJ2OSM\">\n";
         close ALLOSM;
       }
       system("ksj2osm-river-rebuild.pl $current_osmfn $all_osmfn");
     } else {
       system("ksj2osm-river-rebuild.pl $current_osmfn");
     }
   }
 }

}  # end sub close_osm_file()


# get AAC label in AdminAreaCd.xml from ASL code
sub get_aac_label(){

 my $aac_code = $_[0];

 my $aac_label = "no use";

 ### my $xml_aac = XML::LibXML->new();
 ### my $aac_doc = $xml_aac->parse_file("AdminAreaCd_090101.xml");
 ### my @aac_list = $aac_doc->getElementsByTagName('codelabel');

 ### foreach my $aac_list (@aac_list){

   ### my $aac_list_code = $aac_list->getAttribute('code');
   ### if($aac_code eq $aac_list_code){
     ### $aac_label = $aac_list->getAttribute('label');
     ### last;
   ### }

 ### }
 return $aac_label;

}  # end sub get_aac_label()



sub get_cop_label() {

 my %hash = (
   "1" => "1級直轄区間",
   "2" => "1級指定区間",
   "3" => "2級河川区間",
   "4" => "指定区間外",
   "5" => "1級直轄区間でかつ湖沼区間を兼ねる",
   "6" => "1級指定区間でかつ湖沼区間を兼ねる",
   "7" => "2級河川区間でかつ湖沼区間を兼ねる",
   "8" => "指定区間外でかつ湖沼区間を兼ねる",
   "0" => "不明"
 );

 return $hash{$_[0]};

}  # end sub get_cop_label()


# set tag data for writing OSM file
sub write_osm_constant_tag(){

 my $tags;

 my %hash = (
   "created_by" => "National-Land-Numerical-Information_MLIT_Japan",
   "note" => "National-Land Numerical Information (River) 2006, MLIT Japan",
   "note:ja" => "国土数値情報(河川データ)平成18年国土交通省",
   "source" => "KSJ2",
   "source_ref" => "http://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-W05.html",
   "KSJ2:filename" => $file_in . ".xml",
 );

 foreach my $key ( keys( %hash ) ){

   $tags .= "<tag k=\"$key\" v=\"$hash{$key}\"/>";

 }

 return $tags;

}  # end sub write_osm_constant_tag()


# create nd-tab data for write way to OSM file
sub create_nd_tag() {

 my ($nd_tag_ref) = @_;
 my $node_ref = "";

 # for write way data to OSM file
 foreach my $nd_tag ( @{$nd_tag_ref} ){

    $node_ref .= $nd_tag;

 }  # end foreach my $nd_tag ( @node_ref )

 return $node_ref;

}


# write way data to OSM file
sub write_osm_way_tag() {

 my ($tag_id, $tag_data, $nd_data) = @_;

 my $tags = sprintf("<way id=\"%d\" action=\"modify\" visible=\"true\">", $tag_id);

 my $need_to_write = "no" ;


 $tags .= &create_nd_tag($nd_data);

 $tags .= &write_osm_constant_tag();
#  $tags .= "<tag k=\"waterway\" v=\"river\"/>";
 $tags .= "<tag k=\"layer\" v=\"$layer\"/>";

   foreach my $key ( keys( %{$tag_data} ) ){

     unless( $key eq "KSJ2:coordinate"
       || $key eq "KSJ2:lat"
       || $key eq "KSJ2:long"
       || $key eq "KSJ2:SOR"
       || $key eq "KSJ2:EOR"
       || $key eq "KSJ2:SOS"
       || $key eq "KSJ2:EOS"
       || $key eq "KSJ2:COP"
       || $key eq "KSJ2:ODC"
       || $key eq "KSJ2:ODC_label"
       || $key eq "KSJ2:WSC_label"
       || $key eq "KSJ2:RIC_label"
        ){

       $tags .= "<tag k=\"$key\" v=\"$tag_data->{$key}\"/>";

       if( $key eq "KSJ2:RIN" && !($tag_data->{$key} eq "名称不明") ){
         if( $selected_river_name_jprm ne "" ) {
           $tags .= "<tag k=\"name\" v=\"$tag_data->{$key} ($selected_river_name_jprm)\"/>";
         } else {
           $tags .= "<tag k=\"name\" v=\"$tag_data->{$key}\"/>";
         }
         if( $selected_river_name_en ne "" ) {
           $tags .= "<tag k=\"name:en\" v=\"$selected_river_name_en\"/>";
         }
         $tags .= "<tag k=\"name:ja\" v=\"$tag_data->{$key}\"/>";
         if( $selected_river_name_jprm ne "" ) {
           $tags .= "<tag k=\"name:ja_rm\" v=\"$selected_river_name_jprm\"/>";
         }
       }

       if( $key eq "KSJ2:RIN" && ( $tag_data->{$key} eq $selected_river_name || $selected_river_name eq "") ){
         $need_to_write = "yes";
         $any_valid_data_in_osmfile = "yes"
       }

     }

   }

 $tags .= "</way>";

 if( $need_to_write eq "yes" ) {
   print OSM $tags;
 }

}  # end sub write_osm_way_tag()


# write node data to OSM file
sub write_osm_node_tag() {

 my $need_to_write = "no" ;

 my ($tag_id, $hash, $coodinate) = @_;

 # if $cordinate have data
 if( defined( $coodinate ) ){
   $hash->{"KSJ2:coordinate"} = $coodinate;
   ($hash->{"KSJ2:lat"}, $hash->{"KSJ2:long"}) = split(/\s/, $hash->{"KSJ2:coordinate"});
   if ( $dbg_level >= 99 ) {
     printf "pos = lat: %s / long: %s\n", $hash->{"KSJ2:lat"}, $hash->{"KSJ2:long"};
   }

 }

 my $tags = sprintf("<node id=\"%d\" visible=\"true\" lat=\"%0.6f\" lon=\"%0.6f\">", $tag_id, $hash->{"KSJ2:lat"}, $hash->{"KSJ2:long"});



 if ( $need_to_write_node_detail_tag eq "yes" ) { $tags .= &write_osm_constant_tag(); }

 foreach my $key ( keys( %{$hash} ) ){

   if ($key eq "KSJ2:river_id"
       || $key eq "KSJ2:curve_id"
       || $key eq "KSJ2:RIN"
       || $key eq "KSJ2:lat"
       || $key eq "KSJ2:long"
       || $key eq "KSJ2:coordinate" ){

       if ( $need_to_write_node_detail_tag eq "yes" ) { $tags .= "<tag k=\"$key\" v=\"$hash->{$key}\"/>"; }

       if( $key eq "KSJ2:RIN" && ( $hash->{$key} eq $selected_river_name || $selected_river_name eq "") ){
         $need_to_write = "yes";
       }

   }

 }

 $tags .= "</node>";

 if( $need_to_write eq "yes" || $force_write_node eq "yes" ) {  print OSM $tags; }

 return %{$hash};

}  # end sub write_osm_node_tag()


# get the data of Attribute
sub get_attr_data() {

 my $ksj_attr = $_[0];
 my $tmp;
 my %hash;

=pod
 my %hash = (
   "KSJ2:river_id" => $GB02_id
   "KSJ2:WSC" => $wsc_code,
   "KSJ2:WSC_label"  => $wsc_label,
   "KSJ2:LOC" => $LOC_idref,
   "KSJ2:RIC" => $ric_code,
   "KSJ2:RIC_label"  => $ric_label,
   "KSJ2:COP" => $cop_id,
   "KSJ2:COP_label"  => $cop_label,
   "KSJ2:RIN" => $rin,
   "KSJ2:SOS" => $sos_ref,
   "KSJ2:EOS" => $eos_ref,
   "KSJ2:ODC" => $odc_code,
   "KSJ2:ODC_label"  => $odc_label,
   "KSJ2:DFD" => $dfd
   "KSJ2:SOR" => $sor_ref,
   "KSJ2:EOR" => $eor_ref,
   "waterway" => $river_type
 );
=cut

 # get the Data of CP-id
 $hash{"KSJ2:river_id"} = $ksj_attr->getAttribute('id');

 # get code & label of WaterSystemCodeCd
 $hash{"KSJ2:WSC"} = $ksj_attr->getChildrenByTagName('ksj:WSC')->get_node(0)->textContent;
 $hash{"KSJ2:WSC_label"} = &get_aac_label( $hash{"KSJ2:WSC"} );     #+++ NO ACTION

 # get the Data of LOC-idref
 $hash{"KSJ2:LOC"} = $ksj_attr->getChildrenByTagName('ksj:LOC')->get_node(0)->getAttribute('idref');

 # get code & label of RiverCodeCd
 $hash{"KSJ2:RIC"} = $ksj_attr->getChildrenByTagName('ksj:RIC')->get_node(0)->textContent;
 $hash{"KSJ2:RIC_label"} = &get_aac_label( $hash{"KSJ2:RIC"} );     #+++ NO ACTION

 $hash{"KSJ2:COP"} = $ksj_attr->getChildrenByTagName('ksj:COP')->get_node(0)->textContent;
 $hash{"KSJ2:COP_label"} = &get_cop_label( $hash{"KSJ2:COP"} );     #--- added

 # get Name of river
 if($ksj_attr->find('ksj:RIN')){
   $hash{"KSJ2:RIN"} = $ksj_attr->getChildrenByTagName('ksj:RIN')->get_node(0)->textContent;
   if( $hash{"KSJ2:RIN"} eq "不明" ){
     $hash{"KSJ2:RIN"} = "名称不明";
   }
 }

 $hash{"KSJ2:SOS"} = $ksj_attr->getChildrenByTagName('ksj:SOS')->get_node(0)->getAttribute('idref');
 $hash{"KSJ2:EOS"} = $ksj_attr->getChildrenByTagName('ksj:EOS')->get_node(0)->getAttribute('idref');


 # get code & label of OriginalDataCodeCd
 $hash{"KSJ2:ODC"} = $ksj_attr->getChildrenByTagName('ksj:ODC')->get_node(0)->textContent;
 $hash{"KSJ2:ODC_label"} = &get_aac_label( $hash{"KSJ2:ODC"} );     #+++ NO ACTION


 # get Direction of the River
 my $dfd_bool = $ksj_attr->getChildrenByTagName('ksj:DFD')->get_node(0)->textContent;

 if ($dfd_bool eq 1){
   $hash{"KSJ2:DFD"} = "流下方向判明";
 }else{
   $hash{"KSJ2:DFD"} = "流下方向不明";
 }

 $hash{"KSJ2:SOR"} = $ksj_attr->getChildrenByTagName('ksj:SOR')->get_node(0)->getAttribute('idref');
 $hash{"KSJ2:EOR"} = $ksj_attr->getChildrenByTagName('ksj:EOR')->get_node(0)->getAttribute('idref');

 $hash{"waterway"} = "river";
 if ( $stream_on eq "yes" ) {
   if ( $hash{"KSJ2:COP"} eq "4" ||
        $hash{"KSJ2:COP"} eq "8" ||
        $hash{"KSJ2:COP"} eq "0" )  {
     if ( $hash{"KSJ2:RIN"} =~ /谷$/ ||
          $hash{"KSJ2:RIN"} =~ /沢$/ ||
          $hash{"KSJ2:RIN"} =~ /俣$/ ||
          $hash{"KSJ2:RIN"} =~ /ヤツ$/ ||
          $hash{"KSJ2:RIN"} =~ /タル$/ ||
          $hash{"KSJ2:RIN"} =~ /窪$/ ||
          $hash{"KSJ2:RIN"} =~ /クボ$/ ||
          $hash{"KSJ2:RIN"} =~ /入$/ ||
          ( $unknown_is_stream eq "yes" && $hash{"KSJ2:RIN"} eq "名称不明" ) ) {
        $hash{"waterway"} = "stream";
     }
   }
 }


 if ( $dbg_level >= 99 ) {
       printf "---------------------------\n";
       printf "GB02_id: %s\n", $hash{"KSJ2:river_id"};
       printf "WSC: %d %s\n",$hash{"KSJ2:WSC"},$hash{"KSJ2:WSC_label"};
       printf "LOC: %s\n", $hash{"KSJ2:LOC"};
       printf "RIC: %d %s\n", $hash{"KSJ2:RIC"},$hash{"KSJ2:RIC_label"};
       printf "COP: %d %s\n", $hash{"KSJ2:COP"},$hash{"KSJ2:COP_label"};
       printf "RIN: %s\n", $hash{"KSJ2:RIN"};
       printf "SOS-EOS: %s %s\n",$hash{"KSJ2:SOS"},$hash{"KSJ2:EOS"};
       printf "DFD: %s\n", $hash{"KSJ2:DFD"};
       printf "SOR-EOR: %s %s\n",$hash{"KSJ2:SOR"},$hash{"KSJ2:EOR"};
 }

 return %hash;

}  # sub get_attr_data()


# get point data from KSJ file
sub get_ksj_point_data() {

 my ($ksj_node) = @_ ;
 my %hash;

 my $coordinate = $ksj_node->getElementsByTagName('DirectPosition.coordinate')->get_node(0)->textContent;
 return $coordinate;

}  #end sub get_ksj_point_data()



sub main (){

 if ( $#ARGV eq 2 ) {
   $selected_river_name = decode 'Shiftjis', $ARGV[0];
   $selected_river_name_jprm = $ARGV[1];
   $selected_river_name_en = $ARGV[2];
 }
 printf ( "[NAME]:%s [Roman]:%s [Eng]:%s\n", $selected_river_name, $selected_river_name_jprm, $selected_river_name_en );

 # for creating Element ID
 my $negative_id = 0;
 my $node_id;
 my %node_ref_id = ();

 my $node_per_file = 0;  # nodes per a file

 my $xml = XML::LibXML->new();
 my $ksj_doc = $xml->parse_file("$file_in.xml");

 # for sepalate files
 my $count_files = 0;
 my $count_way = 0;
 my $file_start_id = 0;

 &open_log();
 &open_osm_file($count_files);

 # この4行もはやどうでもいい
		 if ( $selected_river_name ne "" && !$force_write_node eq "yes" ) {
		   $max_ways = 9999999;  # for splitting output files.
		   $max_nodes_per_file = 9999999;  # max nodes per a file
		 }

 if ( $selected_river_name eq "" ) {
   $max_ways = 9999999;  # for splitting output files.
   $max_nodes_per_file = 9999999;  # max nodes per a file
 }



 my @ksj_attr = $ksj_doc->getElementsByTagName('ksj:GB02')->get_nodelist();
 my @ksj_way = $ksj_doc->getElementsByTagName('jps:GM_Curve')->get_nodelist();
 my @ksj_node = $ksj_doc->getElementsByTagName('jps:GM_Point')->get_nodelist();

 # get the data of Attribute
 foreach my $ksj_attr (@ksj_attr){

   # get the data of Attribute
   my %ksj_tag = &get_attr_data($ksj_attr);

   # write the ways only the selected river when the order river,
   #  or the all ways when no the selected river
   if( $ksj_tag{"KSJ2:RIN"} eq $selected_river_name || $selected_river_name eq "" ){

=pod
 my %hash = (
   "KSJ2:river_id" => $GB02_id
   "KSJ2:WSC" => $wsc_code,
   "KSJ2:WSC_label"  => $wsc_label,
   "KSJ2:LOC" => $LOC_idref,
   "KSJ2:RIC" => $ric_code,
   "KSJ2:RIC_label"  => $ric_label,
   "KSJ2:COP" => $cop_id,
   "KSJ2:COP_label"  => $cop_label,
   "KSJ2:RIN" => $rin,
   "KSJ2:SOS" => $sos_ref,
   "KSJ2:EOS" => $eos_ref,
   "KSJ2:ODC" => $odc_code,
   "KSJ2:ODC_label"  => $odc_label,
   "KSJ2:DFD" => $dfd,
   "KSJ2:SOR" => $sor_ref,
   "KSJ2:EOR" => $eor_ref,
   "waterway" => $river_type
 );
=cut

   if ( $dbg_level >= 99 ) {
       printf "  -------------(%d)--------------\n",$count_files;
       printf "  GB02_id: %s\n", $ksj_tag{"KSJ2:river_id"};
       printf "  WSC: %d %s\n",$ksj_tag{"KSJ2:WSC"},$ksj_tag{"KSJ2:WSC_label"};
       printf "  LOC: %s\n", $ksj_tag{"KSJ2:LOC"};
       printf "  RIC: %d %s\n", $ksj_tag{"KSJ2:RIC"},$ksj_tag{"KSJ2:RIC_label"};
       printf "  COP: %d %s\n", $ksj_tag{"KSJ2:COP"},$ksj_tag{"KSJ2:COP_label"};
       printf "  RIN: %s\n", $ksj_tag{"KSJ2:RIN"};
       printf "  SOS-EOS: %s %s\n",$ksj_tag{"KSJ2:SOS"},$ksj_tag{"KSJ2:EOS"};
       printf "  DFD: %s\n", $ksj_tag{"KSJ2:DFD"};
       printf "  SOR-EOR: %s %s\n",$ksj_tag{"KSJ2:SOR"},$ksj_tag{"KSJ2:EOR"};
   }


   # get the data of Line
   foreach my $ksj_way (@ksj_way){

     # for create "<nd>" tag
     my $node_ref = "";
     my @nd_tag = ();
     my $node_count = 0;

     my %temp_node_data = ();

     my $gm_curve_id = $ksj_way->getAttribute('id');

     # Routine when agreeing to information that data of acquired line targets.
     if($gm_curve_id eq $ksj_tag{"KSJ2:LOC"}){

       $ksj_tag{"KSJ2:curve_id"} = $gm_curve_id;

       # write way data to OSM file
####        &write_osm_way_tag($negative_id, \%ksj_tag);

       # get the data of Point
       my @ksj_way_node = $ksj_way->getElementsByTagName('GM_PointArray.column')->get_nodelist();

       foreach my $ksj_way_node (@ksj_way_node){

         $node_count++;

         # sequence for sepalate file
         if( ($count_way >= $max_ways) || ( $node_per_file >=$max_nodes_per_file)){

           &close_osm_file($count_files);
           $count_way = 0;
           $node_per_file = 0;

           $count_files++;
           &open_osm_file($count_files);
           $file_start_id = $negative_id;

           $negative_id--;

           # setting nt-tag for conect ways between separate files
           if( keys(%temp_node_data) ){
             &write_osm_node_tag($negative_id, \%temp_node_data);
             @nd_tag = sprintf("<nd ref=\"%d\" />", $negative_id );
           }

         }

         $negative_id--;
         $node_id = $negative_id;

         # Routine when acquired point is reference data.
         if($ksj_way_node->find('jps:GM_Position.indirect')){

           my $ksj_point_ref = $ksj_way_node->getElementsByTagName('GM_PointRef.point')->get_node(0)->getAttribute('idref');

           foreach my $ksj_node (@ksj_node){

             my $ksj_point_id = $ksj_node->getAttribute('id');

             # Routine when it is point in line that data of acquired point targets.
             if ( ($ksj_point_id eq $ksj_point_ref) ){

               if( !exists($node_ref_id{"$ksj_point_id"}) || ($node_ref_id{"$ksj_point_id"} > $file_start_id) ){
                 # get Point data & write node to OSM file
                 my $pos_coodinate = &get_ksj_point_data($ksj_node);
                 %temp_node_data = &write_osm_node_tag($node_id, \%ksj_tag, $pos_coodinate);

                 $node_ref_id{"$ksj_point_id"} = $node_id;

               }else{
                 $node_id = $node_ref_id{"$ksj_point_id"};
               }

               last;
             }  # end if ($ksj_point_id eq $ksj_point_ref)


           }  # end foreach my $ksj_node (@ksj_node)

         }  # end if($ksj_way_node->find('jps:GM_Position.indirect'))

         # Routine when acquired point is direct data.
         elsif($ksj_way_node->find('jps:GM_Position.direct')){

            # get Point data & write node to OSM file
            my $direct_pos_coodinate = &get_ksj_point_data($ksj_way_node);
            %temp_node_data = &write_osm_node_tag($node_id, \%ksj_tag, $direct_pos_coodinate);

         }  # end elsif($ksj_way_node->find('jps:GM_Position.direct'))

         # for write way data to OSM file
         push( @nd_tag, sprintf("<nd ref=\"%d\" />", $node_id ) );

         if( $node_count >= $max_nodes_per_way ){

           $negative_id--;


           # write way data to OSM file
           &write_osm_way_tag($negative_id, \%ksj_tag, \@nd_tag);
           $node_ref = "";

           # setting nt-tag for conect ways
           @nd_tag = sprintf("<nd ref=\"%d\" />", $node_id );

           $count_way++;  # count ways for separating OSM file
           $node_per_file += $node_count;

           $node_count = 0;

         }

       }  # end foreach my $ksj_way_node (@ksj_way_node)

       $negative_id--;

       # write way data to OSM file
       &write_osm_way_tag($negative_id, \%ksj_tag, \@nd_tag);
       $node_ref = "";

       $count_way++;  # count ways for separating OSM file
       $node_per_file += $node_count;

     }  # end if($gm_curve_id eq $ksj_tag{"KSJ2:LOC"})

   }  # end foreach my $ksj_way (@ksj_way)

   }  # end if( $ksj_tag{"KSJ2:RIN"} eq $selected_river_name || $selected_river_name eq "" )

 }  # end foreach my $ksj_attr (@ksj_attr)

 &close_osm_file($count_files);
 &close_log();

 if ( $combine_all eq "yesopened" ) {
   open ALLOSM, ">>".$all_osmfn;
   print ALLOSM "</osm>";
   close ALLOSM;
 }

}  # end main()

main();

ksj2osm-river-rebuild.pl

#! /usr/bin/perl


use strict;
use warnings;
# use encoding "utf8";
use encoding "utf8", STDOUT => "shiftjis", STDERR => "shiftjis"; # for Windows
use Encode;
use open IO => "utf8";
use XML::LibXML;

our @osm_ndref;

sub is_print_node() {

 my $id = $_[0];
 foreach my $ndref ( @osm_ndref ) {
   if ( $id eq $ndref->getAttribute('ref') ) { return (1 ); }
 }
 return ( 0 ) ;
}

sub main() {

 my $osmfilein = $ARGV[0];

 my $osmtempfn = "__tempfile__.xml";

 open(OSM, ">".$osmtempfn);

 my $xml = XML::LibXML->new();
#  my $osm_doc = $xml->parse_file("ksj2osm-river-13Kuromegawa-025.osm");
#  my $osm_doc = $xml->parse_file("ksj2osm-river-13Shakujiigawa-016.osm");
 my $osm_doc = $xml->parse_file("$osmfilein");

 my @osm_node = $osm_doc->getElementsByTagName('node')->get_nodelist();
 my @osm_way = $osm_doc->getElementsByTagName('way')->get_nodelist();
 @osm_ndref = $osm_doc->getElementsByTagName('nd')->get_nodelist();

 printf OSM ("<osm version=\"0.5\" generator=\"KSJ2OSM\">\n");
 if ( $#ARGV gt 0 ) { my $allsomfn = $ARGV[1]; open(ALLOSM, ">>".$allsomfn ); }

 foreach my $way ( @osm_way ) {
   printf OSM ("%s\n",$way->toString(1));
   if ( $#ARGV gt 0 ) { printf ALLOSM ("%s\n",$way->toString(1)); }
 }


 foreach my $node ( @osm_node ) {
   my $id = $node->getAttribute('id');
   if ( &is_print_node( $id ) ne 0 ) {
     printf OSM ("%s\n",$node->toString(1));
     if ( $#ARGV gt 0 ) { printf ALLOSM ("%s\n",$node->toString(1)); }
   }
 }

 printf OSM ("</osm>\n");

 close OSM;
 if ( $#ARGV gt 0 ) { close ALLOSM; }

 my $rm_stat = unlink ( $osmfilein );
 ##printf( "unlink:%d - %s\n",$rm_stat, $osmfilein );

 my $mv_stat = rename ( "$osmtempfn" , "$osmfilein" );
 ##printf( "rename:%d - %s -> %s\n",$mv_stat, $osmtempfn, $osmfilein );

}

main();


ksj2osm-river-getriver.pl

  • おまけスクリプト
    • 同一フォルダ中に配置されたすべての国土数値情報(河川データ)XMLファイルから、河川名一覧(水域コード6桁+河川名でsort | uniq)を標準出力にリストします。
      • 例えば、W05-08_11.xml(埼玉)、W05-08_13.xml(東京)、W05-08_14.xml(神奈川)があれば、それらを総ナメしてリストします。
      • 河川名一覧をテキストファイルに保存するようにコードを追加しました。 (2010.09.23)
#! /usr/bin/perl


use strict;
use warnings;
# use encoding "utf8";
use encoding "utf8", STDOUT => "shiftjis", STDERR => "shiftjis"; # for Windows
use Encode;
use open IO => "utf8";
use XML::LibXML;

our @osm_ndref;

sub is_print_node() {

 my $id = $_[0];
 foreach my $ndref ( @osm_ndref ) {
   if ( $id eq $ndref->getAttribute('ref') ) { return (1 ); }
 }
 return ( 0 ) ;
}

sub main() {
 my %river_hash;
 my $total_GB02 = 0;
 my $count_GB02;
 my @river_array;
 my @river_array_sorted;

 my $dir = ".";
 opendir(DIR, "$dir");
 my @files = readdir(DIR);
 closedir(DIR);

 open(RIVER_LST, '>', "River-List.txt");

 foreach my $osmfile ( @files ) {
   next if ( ! ( $osmfile =~ /W[0-9][0-9]-[0-9][0-9]_[0-9][0-9]\.xml$/ )  ) ;
   print "$osmfile\n";
   print RIVER_LST "$osmfile\n";

   my $xml = XML::LibXML->new();
   my $osm_doc = $xml->parse_file("$osmfile");

   my @osm_GB02 = $osm_doc->getElementsByTagName('ksj:GB02')->get_nodelist();
   $count_GB02 = 0;
   foreach my $GB02 ( @osm_GB02 ) {
     push ( @river_array, 
            $GB02->getChildrenByTagName('ksj:WSC')->get_node(0)->textContent . " "
              . $GB02->getChildrenByTagName('ksj:RIN')->get_node(0)->textContent) ;
     $count_GB02 ++;
   }
   $total_GB02 += $count_GB02;
   print "  $count_GB02 GB02 - total $total_GB02\n";
   print RIVER_LST "  $count_GB02 GB02 - total $total_GB02\n";

 }

###    foreach my $key ( sort @river_array ) {
###      print "$key\n";
###    }

 @river_array_sorted = sort @river_array;

 print $river_array_sorted[0]."\n";
 for ( my $i = 1; $i < $total_GB02; $i++ ) {
   if ( $river_array_sorted[$i] ne $river_array_sorted[$i-1] ) {
     print $river_array_sorted[$i]."\n";
     print RIVER_LST $river_array_sorted[$i]."\n";
   }
 }

 close RIVER_LST;

}

main();

最後に

本スクリプトは、miyabi氏公開の ksj2osm-coastline.pl [1] をベースとし改造して作成したものです。 公開を前提にコードを修正してこなかったため、私しか読めないこんなものに仕上がりました。ご了承ください。無論、改良大歓迎です。

「このコードを読み解く時間があるのなら、野に出てロギングしてきたほうがマシだ」 -- マッパー・ダッカー

脚注

  1. 2010/5時点