[C# / LINQ to XML] すぱこーRSSフィードからデータを取得してみよう

こんにちはー！ニアです。

今回はC#とLINQ to XMLを使って「[すぱこー RSS フィード | プログラミング生放送](http://pronama.azurewebsites.net/spaco-feed/)」のRSSフィードから、チャンネル情報と各話のデータを取得していきます。


#1. すぱこーRSSフィードの構成

「[すぱこー RSS フィード | プログラミング生放送](http://pronama.azurewebsites.net/spaco-feed/)」にある要素の一覧より、RSSフィードの構成は以下のようになっています。

```xml:すぱこーRSSフィードの構成
<rss version="2.0" xmlns:p="http://pinga.mu/terms/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:dcndl="http://ndl.go.jp/dcndl/terms/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>作品タイトル</title>
    <link>作品の URL</link>
    <description>作品の説明</description>
    <pubDate>最新話の公開日（RFC 822規定の日付形式）</pubDate>
    <image>作品のバナー画像 URL</image>
    <dc:creator>作者名</dc:creator>
    <item>
      <title>タイトル</title>
      <dc:creator>作者名</dc:creator>
      <link>作品の URL</link>
      <pubDate>公開日（RFC 822規定の日付形式）</pubDate>
      <description>あらすじ</description>
      <dcndl:volume>話数</dcndl:volume>
      <dc:modified>投稿記事の更新日（RFC 822規定の日付形式）</dc:modified>
      <p:isAvailable>利用可能かどうか（通常はtrue）</p:isAvailable>
      <media:content url="漫画画像 URL"></media:content>
      <media:thumbnail url="漫画サムネイル URL"></media:thumbnail>
      <guid isPermaLink="false">ID</guid>
    </item>
    <item>
    ...
    </item>
    ...
  </channel>
</rss>
```

#2. LINQ to XMLとは？
LINQ（Language Integrated Query）とは、リストやデータベース、XMLなどの操作（要素の列挙や抽出、統計などのクエリ機能）をプログラミング言語から利用できる機能です。

LINQ to XMLは、XMLデータに対してLINQを利用することができます。



#3. C#とLINQ to XMLですぱこーRSSフィードを取得してみよう

今回はコンソールアプリで、すぱこーRSSフィードの取得し、データを出力していきます。

LINQ to XMLを利用するには、[**System.Xml.Linq名前空間**](https://msdn.microsoft.com/ja-jp/library/system.xml.linq.aspx)を使用します。

```csharp:SpacoFeedTrial.cs
using System;
using System.Collections.Generic;
using System.Xml.Linq;

class Program {

	static void Main( string[] args ) {
		// すぱこーRSSフィードのURLです。（最新の5話分だけ取得します）
		string url = @"http://pronama-api.azurewebsites.net/feed/spaco?count=10";
		// すぱこーRSSフィードで使用している名前空間です。
		XNamespace p = @"http://pinga.mu/terms/";
		XNamespace media = @"http://search.yahoo.com/mrss/";
		XNamespace dcndl = @"http://ndl.go.jp/dcndl/terms/";
		XNamespace dc = @"http://purl.org/dc/elements/1.1/";

		Console.Write( "すぱこーRSSフィードの取得中... " );
		try {
			// すぱこーRSSフィードを読み込みます。

			Console.WriteLine( "完了！" );

			// すぱこーRSSフィードのデータの取得＆出力します。

		}
		catch( Exception ex ) {
			Console.WriteLine( $"エラー : {ex.Message}" );
		}

	}
}
```

##3.1. RSSフィードを読み込む
まず、[**XElementクラス**](https://msdn.microsoft.com/ja-jp/library/system.xml.linq.xelement.aspx)の[**Loadメソッド**](https://msdn.microsoft.com/ja-jp/library/bb298435.aspx)でRSSフィードを読み込みます。

```csharp:すぱこーRSSフィードの読み込み
// すぱこーRSSフィードを読み込みます。
XElement spx = XElement.Load( url );
```

>※読み込むRSSフィードのデータサイズが大きいと、時間がかかります。

##3.2. RSSフィードからチャンネル情報を取得する

RSSフィードを読み込んだら、チャンネル情報と各話のデータを取得していきます。

チャンネル情報は**channel要素**内にあります。XElementクラスの[**Elementメソッド**](https://msdn.microsoft.com/ja-jp/library/bb348975.aspx)でchannel要素を取得します。

```csharp:channel要素の取得
// すぱこーRSSフィードのデータの取得＆出力します。
XElement spxChannel = spx.Element( "channel" );
```

取得したchannel要素から、XElementクラスの**Elementメソッド**（XMLDOMでいうSelectSingleNodeです）でチャンネル情報の各要素を取得し、[**Valueプロパティ**](https://msdn.microsoft.com/ja-jp/library/system.xml.linq.xelement.value.aspx)でデータを取り出します。

>※Valueプロパティの戻り値の型は**文字列（string）**です。

また、RSSフィードで使われている日付の文字列は**「[RFC 822](http://tools.ietf.org/html/rfc822#section-5)」の日付形式**となっており、**DateTime構造体**の**Parseメソッド**でDateTime型に変換することができます。

```csharp:channel要素からチャンネル情報を取得
// チャンネル情報を取得します。
Console.WriteLine( $"タイトル : {spxChannel.Element( "title" ).Value}" );
Console.WriteLine( $"概要 : {spxChannel.Element( "description" ).Value}" );
Console.WriteLine( $"最終更新日 : {DateTime.Parse( spxChannel.Element( "pubDate" ).Value )}" );
Console.WriteLine( $"リンク : {spxChannel.Element( "link" ).Value}" );
```

##3.3. LINQを使って、各話のデータを取得する
各話のデータは**item要素**内にあります。XElementクラスの[**Elementsメソッド**](https://msdn.microsoft.com/ja-jp/library/bb348975.aspx)（XMLDOMでいうSelectSingleNodeです）でitem要素のコレクションを取得します。

```csharp:item要素のコレクションを取得
// 各話のデータを取得します。
IEnumerable<XElement> spxItems = spxChannel.Elements( "item" );
```

取得したitem要素のコレクションは**IEnumerable\<XElement\>型**なので、**LINQ**を利用することができます！

ここではforeach文でコレクションの各要素（XElement型）を列挙し、各話のデータを取得してコンソール画面に表示します。

XElementクラスのElementメソッド及びElementsメソッドで、名前空間付きの要素を指定する時には、**「名前空間名（XNamespace型）」と「要素名（XName型）」を加算演算子（＋）で結合した文字列**を使用します。

```csharp:各話のデータを取得して表示
Console.WriteLine( "\n各話の情報" );
foreach( var item in spxItems ) {
	Console.WriteLine( $"◆ 第{int.Parse( item.Element( dcndl + "volume" ).Value )}話" );
	Console.WriteLine( $"　タイトル : {item.Element( "title" ).Value}" );
	Console.WriteLine( $"　作者 : {item.Element( dc + "creator" ).Value}" );
	Console.WriteLine( $"　公開日 : {DateTime.Parse( item.Element( "pubDate" ).Value )}" );
	Console.WriteLine( $"　リンク : {item.Element( "link" ).Value}" );
}
```

完成したプログラムを以下に示します。

```csharp:SpacoFeedTrial.cs
using System;
using System.Collections.Generic;
using System.Xml.Linq;

class Program {

	static void Main( string[] args ) {
		// すぱこーRSSフィードのURLです。（最新の5話分だけ取得します）
		string url = "http://pronama-api.azurewebsites.net/feed/spaco?count=5";
		// すぱこーRSSフィードで使用している名前空間です。
		XNamespace p = @"http://pinga.mu/terms/";
		XNamespace media = @"http://search.yahoo.com/mrss/";
		XNamespace dcndl = @"http://ndl.go.jp/dcndl/terms/";
		XNamespace dc = @"http://purl.org/dc/elements/1.1/";

		Console.Write( "すぱこーRSSフィードの取得中... " );
		try {
			// すぱこーRSSフィードの読み込みます。
			XElement spx = XElement.Load( url );
			Console.WriteLine( "完了！" );

			// すぱこーRSSフィードのデータの取得＆出力します。

			// チャンネル情報を取得します。
			XElement spxChannel = spx.Element( "channel" );

			Console.WriteLine( $"タイトル : {spxChannel.Element( "title" ).Value}" );
			Console.WriteLine( $"概要 : {spxChannel.Element( "description" ).Value}" );
			Console.WriteLine( $"最新話公開日 : {DateTime.Parse( spxChannel.Element( "pubDate" ).Value )}" );
			Console.WriteLine( $"リンク : {spxChannel.Element( "link" ).Value}" );

			// 各話のデータを取得します。
			IEnumerable<XElement> spxItems = spxChannel.Elements( "item" );
			Console.WriteLine( "\n各話の情報" );
			foreach( var item in spxItems ) {
				Console.WriteLine( $"◆ 第{int.Parse( item.Element( dcndl + "volume" ).Value )}話" );
				Console.WriteLine( $"　タイトル : {item.Element( "title" ).Value}" );
				Console.WriteLine( $"　作者 : {item.Element( dc + "creator" ).Value}" );
				Console.WriteLine( $"　公開日 : {DateTime.Parse( item.Element( "pubDate" ).Value )}" );
				Console.WriteLine( $"　リンク : {item.Element( "link" ).Value}" );
			}

		}
		catch( Exception ex ) {
			Console.WriteLine( $"エラー : {ex.Message}" );
		}

	}
}
```

◆ **実行結果**

>すぱこーRSSフィードの取得中... 完了！
タイトル : すぱこー
概要 : 高校生の暮井 慧（プロ生ちゃん）と、部活「情報処理研究会」のメンバー 戸増千由莉とフィネス・ヒルヴィレッジが活躍する Web 4コマ漫画「すぱこー」！
最新話公開日 : 2015/11/15 21:30:39
リンク : http://pronama.azurewebsites.net/tag/spaco/

>各話の情報
◆ 第41話
　タイトル : すぱこー Ver. 41
　作者 : 池村ヒロイチ
　公開日 : 2015/11/15 21:30:39
　リンク : http://pronama.azurewebsites.net/2015/11/15/web-comic-spaco-41/
◆ 第40話
　タイトル : すぱこー Ver. 40
　作者 : 池村ヒロイチ
　公開日 : 2015/11/04 23:13:28
　リンク : http://pronama.azurewebsites.net/2015/11/04/web-comic-spaco-40/
◆ 第39話
　タイトル : すぱこー Ver. 39
　作者 : 池村ヒロイチ
　公開日 : 2015/10/07 13:16:36
　リンク : http://pronama.azurewebsites.net/2015/10/07/web-comic-spaco-39/
◆ 第38話
　タイトル : すぱこー Ver. 38
　作者 : 池村ヒロイチ
　公開日 : 2015/10/03 23:41:44
　リンク : http://pronama.azurewebsites.net/2015/10/03/web-comic-spaco-38/
◆ 第37話
　タイトル : すぱこー Ver. 37
　作者 : 池村ヒロイチ
　公開日 : 2015/08/18 22:38:46
　リンク : http://pronama.azurewebsites.net/2015/08/18/web-comic-spaco-37/


それでは、See you next!


#関連サイト
* LINQ to XML - MSDN - Microsoft  
https://msdn.microsoft.com/ja-jp/library/bb387098.aspx
* Working with XML Namespaces - MSDN - Microsoft  
https://msdn.microsoft.com/ja-jp/library/bb387093.aspx