[C#][SQLite][LINQ to XML] DBから取得したデータをXMLで返し、受け取ったXMLを解析する

  

DBに保存されているデータをXML形式で受け取り、
LINQ to XMLの技術を用いて、そのXMLを簡単に解析するためのコードです。
(DB → XML → 解析)

手軽さから、DBはSQLiteを使いました。
なので、nugetでSQLiteのパッケージを導入します。

DBに格納するテスト用のデータは、大阪環状線の駅情報です。
「[駅データ.jp](http://www.ekidata.jp/)」で公開している駅情報をそのままDBに保存して使わせて頂きました。

- DBからデータ取得
- 取得したデータをXMLに変更
- そのXMLを解析

## 1．DBからデータを取得

DBは以下の様な構造です。(stationテーブル)


| station_name | lon | lat |
|:-:|:-:|:-:|
| 天王寺  | 135.514124  | 34.647243  |
| 新今宮  | 135.501076  |  34.650149 |
|  ... | ...  | ...  |
|  寺田町 | 135.523437  | 34.647957 |

以下のようなクラスを作成しました。

```C#:SQLiteIF.css
    public class SQLiteIF
    {
        /// <summary>
        /// 駅情報一覧をXML形式で取得
        /// </summary>
        /// <param name="dbFilePath">.dbファイルのフルパス</param>
        static public string GetStations( string dbFilePath )
        {
            // 取得したレコードをListで保持します。
            // 取得したデータはすべてstring型とする。
            List<Dictionary<string, string>> stationRecords = new List<Dictionary<string, string>>();

            // DBに接続して、クエリを実行する。
            using ( var sqliteConn = new SQLiteConnection( "Data Source=" + dbFilePath ) )
            {
                sqliteConn.Open();
                using ( SQLiteCommand command = sqliteConn.CreateCommand() )
                {
                    // クエリ実行
                    command.CommandText = "SELECT * from station";
                    using ( SQLiteDataReader reader = command.ExecuteReader() )
                    {
                        // 一行一行読み込んでいく
                        while ( reader.Read() )
                        {
                            // Listに追加
                            Dictionary<string, string> record = new Dictionary<string, string>() {
                                { "stationName", reader["station_name"].ToString() },
                                { "longitude", reader["lon"].ToString() },
                                { "latitude",  reader["lat"].ToString()}
                            };
                            stationRecords.Add( record );
                        }
                    }
                }
                sqliteConn.Close();
            }

            // ルート部分のエレメントオブジェクト作成
            XElement rootElement = new XElement( "records" );
            // ルートに対して子のエレメントを追加していく
            foreach ( var record in stationRecords )
            {
                XElement el = new XElement( "record",
                    from keyValue in record
                    select new XElement( keyValue.Key, keyValue.Value )
                    );
                rootElement.Add( el );
            }
            return rootElement.ToString();
        }
    }
```

取得したレコード情報は、一時的に全てDictionaryに格納しています。

```C#:SQLiteIF.css
Dictionary<string, string> record = new Dictionary<string, string>() {
    { "stationName", reader["station_name"].ToString() },
    { "longitude", reader["lon"].ToString() },
    { "latitude",  reader["lat"].ToString()}
};
```
上記DictionaryをListにAddして、複数のレコード情報を保持しました。

## 2．取得したデータをXMLに変換
LINQ to XMLを使えば、簡単にXML形式の文字列が作成出来ます。

```C#:SQLiteIF.css
// ルート部分のエレメントオブジェクト作成
XElement rootElement = new XElement( "records" );
// ルートに対して子のエレメントを追加していく
foreach ( var record in stationRecords )
{
    XElement el = new XElement( "record",
        from keyValue in record
        select new XElement( keyValue.Key, keyValue.Value )
        );
    rootElement.Add( el );
}
return rootElement.ToString();
```

LINQのクエリを使うと、簡単にXElementオブジェクトの作成が行えます。
もしかしたら、foreachしなくても一発でXElementオブジェクトが作成出来るかもしれません。
偉い人教えてください……。

XElementオブジェクトさえ出来てしまえば、
後は、ToString()を行うだけでXMLのストリームが作成出来ます。

>&nbsp;\<records>
>&nbsp;&nbsp;&nbsp;\<record>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<stationName>天王寺\</stationName>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<longitude>135.514124\</longitude>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<latitude>34.647243\</latitude>
>&nbsp;&nbsp;&nbsp;\</record>
>&nbsp;&nbsp;&nbsp;\<record>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<stationName>新今宮\</stationName>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<longitude>135.501076\</longitude>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<latitude>34.650149\</latitude>
>&nbsp;&nbsp;&nbsp;\</record>
>&nbsp;&nbsp;&nbsp;
>&nbsp;&nbsp;&nbsp;……
>&nbsp;&nbsp;&nbsp;
>&nbsp;&nbsp;&nbsp;\<record>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<stationName>寺田町\</stationName>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<longitude>135.523437\</longitude>
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<latitude>34.647957\</latitude>
>&nbsp;&nbsp;&nbsp;\</record>
>&nbsp;\</records>

ちなみにXElementを使うには、以下のusing宣言が必要です。
`using System.Xml.Linq;`

## 3．そのXMLを解析
DictionaryからXMLを作成するためにXElementを使用しましたが、
解析する場合もXElementを使用します。

```C#:SQLiteIF.css
    class Program
    {
        static void Main( string[] args )
        {
            // XMLストリームを取得
            string xmlStream = SQLiteIF.GetStations( ".dbファイルのフルパスを指定" );

            // XMLストリームからXElementオブジェクトを作成する場合は、
            // LoadではなくParseを使うこと。
            XElement stationsElement = XElement.Parse( xmlStream );

            // <record>要素のコレクションを取得
            IEnumerable<XElement> stations = stationsElement.Elements( "record" );
            // <record>に属している要素から、必要な情報を取得する
            foreach ( var stationElement in stations )
            {
                Console.WriteLine( string.Format( "駅名: {0}", stationElement.Element( "stationName" ).Value ) );
                Console.WriteLine( string.Format( "緯度: {0}", stationElement.Element( "latitude" ).Value ) );
                Console.WriteLine( string.Format( "経度: {0}", stationElement.Element( "longitude" ).Value ) );
                Console.WriteLine();
            }
        }
    }
```
  

**■ 実行結果**
> 駅名: 天王寺
> 緯度: 34.647243
> 経度: 135.514124
> 
> 駅名: 新今宮
> 緯度: 34.650149
> 経度: 135.501076
> 
> ……
> 
> 駅名: 寺田町
> 緯度: 34.647957
> 経度: 135.523437

##関連サイト
- 駅データ.jp
<br>
http://www.ekidata.jp/
- LINQ to XML を使用してディクショナリを操作する (C#)
<br>
https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/concepts/linq/how-to-work-with-dictionaries-using-linq-to-xml
- SQLite
<br>
https://www.sqlite.org/