「地図データをどうするか/国土地理院の基盤地図情報を読んでみる」の続編です.
(その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ファイルを読み込みます.allRailCL
にRailCL
とその子が入るので,個々のRailCLからデータを抽出していきます.
16行目~49行目で子ノードをサーチし,”fid”は文字列で,”loc”から座標値(緯度,経度)をdoubleにパースして格納しています.
53行目~63行目はデータ格納用のクラスです.
このプログラムを実行すると,座標値がPosのリストとして格納されます.あとは,この座標値をプロット等に活用していけます.下の図は,適当な原点を決めて,ざっくりと緯度1秒を30m,経度1秒を25mで換算して読み取った座標値を直線で繋いだものです.横軸が東西,縦軸が南北方向になります.かなり適当な換算ですが,データはちゃんと読めていそうです.