法務局備付地図XMLの地番リストファイルの新旧比較で地番の変化を見つける（Rで比較）

# はじめに
日本全国に土地がたくさんあり、毎年分筆・合筆などをしていると思います。どこの地番が消えたとか、どこの地番ができたとか、そのような基本的な情報をリストしているものでオープンソースのものはあまり知りません。

今回、オープンデータとして公開された法務局備付地図XMLのデータのうちの、地番のリストファイルを新旧比較することで、土地の地番（公共座標と任意座標のもの両方）の変化をリストする方法を検討してみました。

以下のような感じで、地番ができたところとか、消えたところとか、筆界が確定したところなどをリストすることができたので方法をメモします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/62dc2094-153c-9f11-3339-209e008cdb71.png)


# 今回の実験環境
* Windows 11 Home
* R 4.3.2

# 手順
## Step 1. データのダウンロード
G空間情報センターのページから、地図XMLファイルをダウンロードします。サーチリストファイルを使うので、データ変換をしていないXMLファイル一式の入ったZIPファイルがいいでしょうか。
新旧2時期をダウンロードします。

今回は例として、つくば市の２０２３年と２０２４年のデータを使うことにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/54bd7422-7abc-d3b1-8a7d-fd37ca01707a.png)

## Step 2. 解析の準備
ダウンロードしたZIPファイルには多数のZIPファイルが入っていますが、今回使うのは一番上のCSVファイルだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/5c454a4b-1c9f-c40c-d07d-6cd3a32fe911.png)

２０２３年と２０２４年が同じ名前なので、年のフォルダを作って入れておきます。

* 2023/08220-0524-search-list.csv
* 2024/08220-0524-search-list.csv

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/4cf48f15-21f0-2394-4265-3bec70df54d4.png)

サーチリストのファイルはこんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/4762d64b-784d-67bd-fc86-a4767f3b59f2.png)

## Step 3. 地番リストの処理
### 基本的な方針
地図XMLの地番リストは公共座標のものも任意座標のものも含んでいます。これをつかうと公共座標に限らず任意座標系のところの地番の変化も追うことができます。

基本的には古い年度のデータを新しい年度のデータに比べることで消失地番をみつけ、逆に新しい年度のデータを古い年度のデータを比較して新規地番を見つけるアプローチをとります。ただし、リストの４カラム目には地番が入りますが、筆界未定地だと筆界見てポリゴンの番号がそこに入り、当該筆の地番は６カラム目に入ることになるので、ちょっと注意が必要です。筆の出現・消失の観点に比べ、筆界未定の変化の仕方にも注意が必要です。

なお、登記簿に地図がないケースはその地番を見つけられません。また、リストでは面積の増減などはわからないので例えば地籍調査で面積が更新されたところ、地番はそのままで分筆や合筆の影響をうけているところなどはこの方法では見つけられません。


このあたりはトライアンドエラーで、Rを使って以下のようなスクリプトを書きました。


```R
#######################################
# 地図XMLの地番リストから差のある地番を探す
# December 2024
# By T-ubu
#######################################

########################
#Step 0: Rの準備（パッケージのインストール）
#install.packages('dplyr')　#初回のみ（最初の時はコメントアウト（＃）を外してインストールすること）
#install.packages('stringr') #初回のみ（最初の時はコメントアウト（＃）を外してインストールすること）
library("dplyr") #データベースの操作をするためのパッケージ（filterなど）
library("stringr") #文字列処理のパッケージ


########################
#Step 1: パラメータの設定
#files <- read.csv("files.csv",fileEncoding="utf16")
#files <- files[,1]
files <- c("08220-0524-search-list.csv","testtest")
outputDir <- 'output' # 出力用フォルダ

# 出力用フォルダがなければ作成する。
if(!dir.exists(outputDir)){
   dir.create(outputDir)
}

####「市区町村-法務局」の処理開始（「市区町村-法務局」のセットが複数あるときはfilesを入力してここをループ。iをつかう）##############
#for (i in 1:length(files)){
  #file <- files[i]
  file <- files[1]
  #file <- "08220-0524-search-list.csv" #対象の市区町村コード、法務局コードの地番リスト

  oldSrc <- paste("2023/",file,sep="") 
  newSrc <- paste("2024/",file,sep="") 
  outfile <- paste(outputDir,"/",substr(file,1,10),"-diff_machiAza(utf8).txt",sep="")
  outfile2 <- paste(outputDir,"/",substr(file,1,10),"-diff_chiban(utf8).csv",sep="")
  outfile3 <- paste(outputDir,"/",substr(file,1,10),"-diff_chiban(sjis).csv",sep="")

  ########################
  #Step 1: データ入力

  #入力データがない場合にはメッセージ
  if(!file.exists(oldSrc)){
    write(paste(oldSrc,"がありません。",sep=" "),file=outfile,append=TRUE)
  }
  if(!file.exists(newSrc)){
    write(paste(newSrc,"がありません。",sep=" "),file=outfile,append=TRUE) 
  }

  # 新旧ファイルの読み込み
  if(exists("oldOne")){rm(oldOne)}
  if(exists("newOne")){rm(newOne)}
  oldOne <- read.csv(oldSrc,fileEncoding="cp932",header=TRUE,colClasses=rep("character",6))
  newOne <- read.csv(newSrc,fileEncoding="cp932",header=TRUE,colClasses=rep("character",6))

  #地番地区の比較（増減チェック）
  oldChibanchiku <- unique(oldOne[,3])
  newChibanchiku <- unique(newOne[,3])

  if(length(setdiff(oldChibanchiku,newChibanchiku)) == 0){
    #print("地番地区に変更はありません。")
    write("地番地区に変更はありません。",file=outfile,append=TRUE)
  } else {
    #print(paste(files[i]," 次の地番地区が変わっています",setdiff(oldChibanchiku,newChibanchiku),sep=":"))
    write(paste(files[i]," 次の地番地区が変わっています",setdiff(oldChibanchiku,newChibanchiku),sep=":"),file=outfile,append=TRUE)
  }

  #各地番地区ごとに、①旧の地番で新にないもの（消失）、②新の地番で旧にないもの（新規）を見つける
  if(exists("hikakuResult")){rm(hikakuResult)}

  for(j in 1:length(newChibanchiku)){

    if(exists("machiBanchiOld")){rm(machiBanchiOld)}
    if(exists("machiBanchiNew")){rm(machiBanchiNew)}
  
    machiBanchOld <- filter(oldOne,地番区域==newChibanchiku[j])
    machiBanchNew <- filter(newOne,地番区域==newChibanchiku[j])

    #古い地番からのチェック
    if(nrow(machiBanchOld)!= 0){
　　    for(k in 1:nrow(machiBanchOld)){
        if(grepl("筆界未定", machiBanchOld[k,4] )){ #古い地番が筆界未定のケース
          if(machiBanchOld[k,6] %in% machiBanchNew[,4]){#筆界未定の地番が新しい筆界に移動　→筆界設定された
            if(exists("hikakuResult")){
               hikakuResult <- rbind(hikakuResult,c(machiBanchOld[k,3],machiBanchOld[k,6],"筆界確定"))
            }else{
               hikakuResult <- c(machiBanchOld[k,3],machiBanchOld[k,6],"筆界確定")
            }
          } else if (machiBanchOld[k,6] %in% machiBanchNew[,6]){#ふるい筆界未定が筆界未定のまま
　　          #print("Yes. Aruyo^^")
          } else {
            if(exists("hikakuResult")){ #古い筆界未定が筆界未定にも通常地番にもない→筆として消失
               hikakuResult <- rbind(hikakuResult,c(machiBanchOld[k,3],machiBanchOld[k,6],"地番消失（もと筆界未定）"))
            }else{
               hikakuResult <- c(machiBanchOld[k,3],machiBanchOld[k,6],"地番消失（もと筆界未定）")
            }
          }
        } else if(machiBanchOld[k,4] %in% machiBanchNew[,4]){ #古い地番（筆界未定でないもの）がそのまま筆界未定ではない地番としてある
          #print("Yes. Aruyo^^")
        } else { #古い地番（筆界未定でないもの）で筆界の決まった地番がなくなった
          if(machiBanchOld[k,4] %in% machiBanchNew[,6]){#なくても筆界未定側にあるもの
            if(exists("hikakuResult")){
               hikakuResult <- rbind(hikakuResult,c(machiBanchOld[k,3],machiBanchOld[k,4],"筆界未定になった"))
            }else{
               hikakuResult <- c(machiBanchOld[k,3],machiBanchOld[k,4],"筆界未定になった")
            }
          }else{ #筆界未定側にもない
            if(exists("hikakuResult")){
               hikakuResult <- rbind(hikakuResult,c(machiBanchOld[k,3],machiBanchOld[k,4],"地番消失"))
            }else{
               hikakuResult <- c(machiBanchOld[k,3],machiBanchOld[k,4],"地番消失")
            }
          }
        }
      }
    }

    if(nrow(machiBanchNew) !=0){
　     for(k in 1:nrow(machiBanchNew)){
        if(grepl("筆界未定", machiBanchNew[k,4] )){ #新しいもので筆界未定
          if((machiBanchNew[k,6] %in% machiBanchOld[,4])|(machiBanchNew[k,6] %in% machiBanchOld[,6]) ){ #古い方になんらかある
             #print("Yes. Aruyo^^")
          }else{
            if(exists("hikakuResult")){
               hikakuResult <- rbind(hikakuResult,c(machiBanchNew[k,3],machiBanchNew[k,6],"地番出現（ただし筆界未定）"))
            }else{
               hikakuResult <- c(machiBanchNew[k,3],machiBanchNew[k,6],"地番出現（ただし筆界未定）")
            }
          }
        } else if(machiBanchNew[k,4] %in% machiBanchOld[,4]){
          #print("Yes. Aruyo^^")
        } else if(machiBanchNew[k,4] %in% machiBanchOld[,6]){
          #print("筆界未定から筆界が設定されたケース（計上済み）")
        } else {
          #write(paste(machiBanchNew[k,3],machiBanchNew[k,4],",地番出現", sep=""),file=outfile,append=TRUE)
          if(exists("hikakuResult")){
             hikakuResult <- rbind(hikakuResult,c(machiBanchNew[k,3],machiBanchNew[k,4],"地番出現"))
          }else{
             hikakuResult <- c(machiBanchNew[k,3],machiBanchNew[k,4],"地番出現")
          }
        }
      }
    }
  }
  write.csv(hikakuResult,outfile2,fileEncoding="utf8")
  write.csv(hikakuResult,outfile3,fileEncoding="cp932")

#} #（「市区町村-法務局」のセットが複数あるときはここをループ。iをつかう）##############
#######################################################################################

```

このスクリプトをRで実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/5e2e148b-19a2-8a1d-4379-66a02e8ee9f7.png)


# 結果

今回テストとして茨城県のつくば市のデータ（2024年と2023年で比較しています。）でおこないました。得られたファイルは３つ、町字レベルでの変更有無の情報、地番の変更（utf8とSJISそれぞれ）です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/f5d19edd-7830-b89a-2477-0e2eeb2c8bd5.png)

町字の増減をメモしたテキストファイル（ここでは2023～2024にかけて地番地区レベルでの変更はなさそうです。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/6b181571-f5ba-9ae0-46b5-2779eeef5106.png)

地番の変化をメモしたUTF-8のCSVファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/7883d58e-b5e5-366c-f874-3b1acd5dba53.png)

同じ地番の変化をメモしたものですが、SJISで出力したもの。（エクセルでもすぐ開いて雰囲気を見られる。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/7dd662f0-e6bc-d5cf-3bcf-3084d2901b72.png)



エクセルのデータフィルタでみても何パターンかの変化は拾えていると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/cf3b64c5-e3b9-8efd-bdae-ab5d97e518a8.png)

# まとめ
地図XMLの地番リストをつかって土地の変化を少し把握する方法を検討しました。ある程度制限はあるものの、それなりに参考になりそうな情報が得られるかもしれません。

登記簿に地図がないケースはその地番を見つけられません。また、リストでは面積の増減などはわからないので例えば地籍調査で面積が更新されたところ、地番はそのままで分筆や合筆の影響をうけているところなどはこの方法では見つけられません。

# 謝辞
地図XMLを公開してくれた法務省さんに感謝します。

# 参考ページ
https://front.geospatial.jp/