株式会社シスアナコム

情報システムに関することなら、どんなことでも適切に助言いたします!

この投稿は1年以上前に公開されました。
現在では状況や内容が変わっている可能性があります。
ご注意下さい。m(_ _)m

VBAでXMLをRDBに変換。国土数値情報都市公園データを例に。

   

国土数値情報とXML

国土数値情報とは、日本の国土に関する様々な情報を、国土交通省の国土制作局国土情報課という部署が担当して、電子地図などで利用できるように数値化して提供しているものです。

国が提供してくれる情報なので信頼性が高く、誰でも利用することができます。

ちょっとした事情により、この情報を使ってみることになりました。

提供されている情報はJPGIS2.1という形式で提供されています。

電子地図ソフトで利用しやすいように設計されたデータ形式なのですが、電子地図ソフト以外でも利用することは可能。

基本的にはテキスト形式のXMLファイルで、このファイルの中に多数のデータが記述されています。

その中身は、ダウンロードしてブラウザで表示させれば簡単に見ることができます。

ただし、この形式のファイルを直接プログラムで扱うのは少し難しい。

最近はXMLファイルを直接扱うことができるXMLデータベースという製品もあるのですが、まだまだリレーショナルデータベースの方が主流だと思います。

そこで、国土数値情報のXMLファイルをマイクロソフトACCESSのRDBに変換してみます。

都市公園データをダウンロード方法

まずは国土数値情報ダウンロードサービスのトップページへアクセス。
KSJ01
様々なデータがあるので、どれをサンプルにしようか迷いましたが、都市公園データにしてみました。

家の近くの小さな公園も、ちゃんと情報化されているのか興味があったからです。

都市公園のリンクをクリック。
KSJ02
データ作成年度は平成23年なので4年前の情報みたい。

少し古いですが使えないことはありません。

このページの中段あたりにデータをダウンロードするボタンがあります。
KSJ03
都道府県別にファイルが分かれているようなので、地元の埼玉県をダウンロードしてみました。

確認画面が表示されます。
KSJ04
チェックを付けて「次へ」

アンケートの画面が表示されます。
KSJ05
選択肢や入力欄に回答を選択・記入して「回答する」ボタンを押します。

約款が表示されます。
KSJ06
「同意する」

これで、やっとファイルをダウンロードできるようになります。
KSJ07
「ダウンロード」ボタンを押すとファイルがダウンロードできます。

XMLファイルの標準インポートは失敗

マイクロソフトACCESSには標準でXMLファイルのインポート機能があります。

これで簡単に変換できれば、VBAでプログラムを作る必要がないのですが、残念ながらうまくいきませんでした。

Parkというテーブルに公園の基本的な情報が入り、PointというテーブルにGPSの位置情報が入るのですが、この2つの情報をリンクするための情報がどこにもありません。

テーブルを2つ作成

標準のインポート機能を使ったことで、2つテーブルが必要だという事が分かりました。

ParkとPointは1対1の関係なのに、なんで記述する場所が違っているのかはよく分かりません

XMLファイルの中身をブラウザで確認しながら、必要になりそうな項目を限定して、こんなテーブルを作成しました。

T_MS_公園

  • 公園コード   数値型(長整数型)
  • 所在地都道府県 テキスト型
  • 所在地市区町村 テキスト型
  • 公園名     テキスト型
  • 公園種別コード 数値型(バイト型)

T_MS_公園_位置

  • 公園コード   数値型(長整数型)
  • lon       数値型(倍精度浮動小数点型)
  • lat       数値型(倍精度浮動小数点型)

DOMについて

マイクロソフトACCESSのVBAでXMLファイルを扱うためには、DOMを利用するのが簡単。

DOMは「Document Object Model」の略で、HTMLやXMLをプログラムから扱いやすくするための手法。

VBAからXMLやHTMLファイルをオブジェクトとして扱うことができるようになります。

単なるテキストファイルなので、ヤフーファイナンスから株式の情報を取得するように、文字列操作関数を使って必要な部分を取り出すという方法でも可能。

ただし、HTMLと比べるとXMLは書式がきっちりしている場合が多いので、DOMの方が扱いやすいと思います。

DOMを使うためには、VBAの参照設定を行う必要があります。

メニューからツール→参照設定を選択。
XML01
Microsoft XML, v6.0を選択してOK。

これで準備完了です。

VBAでXMLをRDBに変換するプログラム

国土数値情報の都市公園データは以下のようなXMLファイルになっています。

<?xml version="1.0" encoding="UTF-8"?>
<ksj:Dataset xmlns:schemaLocation=...>
  <gml:description>国土数値情報...</gml:description>
  ...
  ...
  <gml:Point gml:id="pt1">
    <gml:pos>35.70152582 138.66560482</gml:pos>
  </gml:Point>
  ...
  ...
  <ksj:Park gml:id="pk1">
    <ksj:loc xlink:href="#pt1"/>
    <ksj:adm>○○県</ksj:adm>
    <ksj:lgn/>
    <ksj:nop>○○公園</ksj:nop>
    <ksj:kdp>4</ksj:kdp>
    <ksj:pop>○○県</ksj:pop>
    <ksj:cop>○○市</ksj:cop>
    <ksj:opd>
      <gml:TimeInstant gml:id="pk1_TI1">
        <gml:timePosition>1995</gml:timePosition>
      </gml:TimeInstant>
    </ksj:opd>
    <ksj:opa>195000</ksj:opa>
    <ksj:cpd>1</ksj:cpd>
    <ksj:rmk/>
  </ksj:Park>
  ...
  ...
</ksj:Dataset>

必要な所のみ抜粋しました。

このXMLファイルは、以下のように要素が構成されているようです。

  • 公園情報と位置情報は「pt+シリアル番号」というidで関連づけ。
  • 位置情報は緯度、経度の順で半角スペースで区切られている。
  • 公園情報の0番目の要素の0番目の属性がid。
  • 公園情報の3番目の要素が公園名。
  • 公園情報の4番目の要素が公園の種別コード。
  • 公園情報の5番目の要素が所在地の都道府県名。
  • 公園情報の6番目の要素が所在地の市区町村名。
  • ファイル名は「P13-11_+都道府県コード+.xml」

XMLの構成要素が分かれば、あとはプログラムを作成するだけです。

Option Compare Database
Option Explicit

Const PATH = "ファイルが存在するパスをここへ記述"

Sub ConvXMLtoRDB(FNUM As String)

    Dim DB As DAO.Database
    Dim RS1 As DAO.Recordset
    Dim RS2 As DAO.Recordset
    Dim XDoc As MSXML2.DOMDocument
    Dim Node As MSXML2.IXMLDOMNode
    Dim PCD As Long
    Dim S As String
    Dim POS As Integer
    Dim LGT As Integer

    Set DB = CurrentDb
    Set RS1 = DB.OpenRecordset("T_MS_公園_位置", dbOpenTable)
    Set RS2 = DB.OpenRecordset("T_MS_公園", dbOpenTable)

    RS1.Index = "PrimaryKey"
    RS2.Index = "PrimaryKey"

    Set XDoc = New MSXML2.DOMDocument

    If XDoc.Load(PATH & "P13-11_" & FNUM & ".xml") = False Then Exit Sub

    For Each Node In XDoc.selectNodes("ksj:Dataset/gml:Point")
        S = Node.Attributes(0).Text
        LGT = Len(S)
        PCD = CLng(Mid(S, 3, LGT)) + CLng(FNUM) * 100000
        RS1.Seek "=", PCD
        If RS1.NoMatch Then
            RS1.AddNew
            RS1![公園コード] = PCD
        Else
            RS1.Edit
        End If
        POS = InStr(1, Node.Text, " ")
        LGT = Len(Node.Text)
        RS1![lat] = CDbl(Left(Node.Text, POS))
        RS1![lon] = CDbl(Mid(Node.Text, POS, LGT))
        RS1.Update
    Next

    For Each Node In XDoc.selectNodes("ksj:Dataset/ksj:Park")
        S = Node.childNodes(0).Attributes(0).Text
        LGT = Len(S)
        PCD = CLng(Mid(S, 4, LGT)) + CLng(FNUM) * 100000
        RS2.Seek "=", PCD
        If RS2.NoMatch Then
            RS2.AddNew
            RS2![公園コード] = PCD
        Else
            RS2.Edit
        End If
        RS2![公園名] = Node.childNodes(3).Text
        RS2![公園種別コード] = CByte(Node.childNodes(4).Text)
        RS2![所在地都道府県] = Node.childNodes(5).Text
        RS2![所在地市区町村] = Node.childNodes(6).Text
        RS2.Update
    Next

End Sub

このプログラムを使えば、XMLで記述された都市公園データからRDBの2つのテーブルに変換できるはずです。

2つのテーブルを公園コードで1対1でつなげるクエリーを作れば、公園情報と位置情報を一緒に一覧できると思います。

全国の都市公園データを変換したら、全部で84822件でした。

こんなに多くの公園があるんですね。

変換後の都市公園データをチェック

変換した都市公園データが正しいかどうかチェックしてみました。

家の近くにある、埼玉県所沢市の春の台公園の位置が正しいかどうか地図上に表示させてみます。

「Simple Map」というプラグインを使って表示させています。

<br /> 埼玉県所沢市春の台公園<br />

位置は正しい。

小さな公園だとグーグルマップには公園として表示されないのか。

知らなかった。

 - ACCESSデータベース, ひとこと, ひとこと(情報化), 週末プログラマー

↓ブログランキングに参加しています!


ネット・PC(全般) ブログランキングへ
にほんブログ村 IT技術ブログ ITコンサルティングへ
にほんブログ村

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です