地図データをどうするか/国土地理院の基盤地図情報を読んでみる(その3)

「地図データをどうするか/国土地理院の基盤地図情報を読んでみる」の続編です.
(その2)でダウンロードしたファイル(FG-GML-523547-RailCL-20210401-0001.xml)から軌道中心の座標を読み出してみます.この点を直線で繋いで描画すれば線路の地図になるはずです.もう一度,データ例を見てみます.

<RailCL gml:id="K21_4891512600_2">
<fid>48915-12600-s-22252</fid>
<lfSpanFr gml:id="K21_4891512600_2-1">
<gml:timePosition>2018-12-19</gml:timePosition>
</lfSpanFr>
<devDate gml:id="K21_4891512600_2-2">
<gml:timePosition>2021-03-09</gml:timePosition>
</devDate>
<orgGILvl>2500</orgGILvl>
<vis>表示</vis>
<loc>
<gml:Curve gml:id="K21_4891512600_2-g" srsName="fguuid:jgd2011.bl">
<gml:segments>
<gml:LineStringSegment>
<gml:posList>
35.005340139 135.875000000
35.005292722 135.875052250
35.005121917 135.875234917
35.004918639 135.875431778
35.004705833 135.875627556
35.004320056 135.875950806
35.003846361 135.876320389
35.003208611 135.876820056
35.002768250 135.877164306
35.002509806 135.877361444
</gml:posList>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
</loc>
<type>普通鉄道</type>
</RailCL>

データの読み出しには,サクッとDOMパーサXmlDocumentを利用することにします.XmlDocumentオブジェクトを作成し,Load()メソッドを用いてXMLファイルを読み込みます.パーシングされた結果の木構造がDocumentElementをルートノードとして格納されるので,DocumentElementから子ノードをたどって各要素にアクセスできます.

今回は,<RailCL>~</RailCL>の子ノード<fid>~</fid>と,<loc>~</loc>を読み取れば良いので,GetElementsByTagName メソッドで<RailCL>,とその子を取り出していくことにします.

コード例

using System;
using System.Collections.Generic;
using System.Xml;

namespace kiban
{
    class Program
    {
        static void Main(string[] args)
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load("FG-GML-523547-RailCL-20210401-0001.xml");
            var allRailCL = xmlDocument.GetElementsByTagName("RailCL");

            List<RailCLData> railCLDatas = new List<RailCLData>();
            foreach(XmlNode cl in allRailCL)
            {
                if (cl.HasChildNodes)
                {
                    RailCLData clData = new();
                    foreach(XmlNode node in cl.ChildNodes)
                    {
                        if(node.Name == "fid")
                        {
                            clData.Fid = node.InnerText;
                        }
                        else if(node.Name == "loc")
                        {
                            string locStr = node.InnerText;
                            string[] poslist = locStr.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
                            foreach (var s in poslist)
                            {
                                string[] lat_lon_str = s.Split(" ", StringSplitOptions.RemoveEmptyEntries);
                                double[] latlon = new double[2];
                                bool latOK = double.TryParse(lat_lon_str[0], out latlon[0]);
                                bool lonOK = double.TryParse(lat_lon_str[1], out latlon[1]);
                                if (latOK && lonOK)
                                {
                                    Pos pos = new Pos();
                                    pos.Lat = latlon[0];
                                    pos.Lon = latlon[1];
                                    clData.Pos.Add(pos);
                                }
                            }
                        }
                    }
                    railCLDatas.Add(clData);
                }
            }
        }
    }

    public class RailCLData
    {
        public string Fid { get; set; }
        public List<Pos> Pos { get; set; } = new List<Pos>();
    }

    public class Pos
    {
        public double Lat { get; set; }
        public double Lon { get; set; }
    }
}

内容

XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("FG-GML-523547-RailCL-20210401-0001.xml");
var allRailCL = xmlDocument.GetElementsByTagName("RailCL");

11-13行目.XmlDocumentオブジェクトを作成し,Load()メソッドを用いてXMLファイルを読み込みます.allRailCLRailCLとその子が入るので,個々のRailCLからデータを抽出していきます.

16行目~49行目で子ノードをサーチし,”fid”は文字列で,”loc”から座標値(緯度,経度)をdoubleにパースして格納しています.

53行目~63行目はデータ格納用のクラスです.

このプログラムを実行すると,座標値がPosのリストとして格納されます.あとは,この座標値をプロット等に活用していけます.下の図は,適当な原点を決めて,ざっくりと緯度1秒を30m,経度1秒を25mで換算して読み取った座標値を直線で繋いだものです.横軸が東西,縦軸が南北方向になります.かなり適当な換算ですが,データはちゃんと読めていそうです.

草津駅付近を拡大して表示

タイトルとURLをコピーしました