とりあえず、RSS を読み込んで、それぞれの中身を取り出せるようになりました。
まず、基本方針。XML を読み込んで、それが対応しているフォーマットであることを確認します。確認が出来たら、管理したい項目のみ取り出して、管理するのに都合の良いフォーマットに変換します。
フォーマットの確認に、リフレクションを使います。一度使ってみたかったので、使うことにしました(ぉぃ)。
using System.Xml.Linq;
using System.Reflection;
/// <summary>
/// インスタンスを生成します。
/// </summary>
/// <param name="document">解析対象の XML ドキュメント</param>
/// <returns>RSS フィードを解析する SyndicationAnalyzer のインスタンスを返します。</returns>
/// <exception cref="System.NotSupportedException">サポートしていないフォーマットの場合、発生します。</exception>
public static SyndicationAnalyzer CreateInstance(XDocument document) {
// サポートしている型を列挙
Type[] supports = new Type[] { typeof(AnalyzerRss10), typeof(AnalyzerRss20), typeof(AnalyzerAtom) };
foreach (var t in supports) {
// それぞれの "CanParse" メソッドを検索
var canParse = t.GetMethod("CanParse", BindingFlags.Static | BindingFlags.Public);
// メソッドを実行
bool result = (bool)canParse.Invoke(null, new object[] { document });
if (result == true) {
// サポートしているなら、
// 規定のコンストラクターを取り出す
var stcConstructor = t.GetConstructor(new Type[] { });
// 規定のコンストラクターを呼び出して、インスタンスを生成する
var instance = stcConstructor.Invoke(new object[] { });
// XDocument 1つを引数に取るコンストラクターを取り出す
var constructor = t.GetConstructor(new Type[] { typeof(XDocument) });
// 規定のコンストラクターで生成したインスタンスを元に、引数ありコンストラクターを実行
constructor.Invoke(instance, new object[] { document });
// できたインスタンスを返す
return (SyndicationAnalyzer)instance;
}
}
throw new NotSupportedException();
}
あまり、うれしくないです。AnalyzerRss10
、AnalyzerRss20
、AnalyzerAtom
は、それぞれ static public bool CanParse(XDocument document)
メソッドと、規定のコンストラクタ、XDocument 型を引数にとるコンストラクタが定義されているものとします。この、「定義されているものとする」という縛りがかけられないのが、不便。インターフェイスを定義して・・・そのインターフェイスを実装したクラスを一覧、って出来ないかなぁ?ここに上げたコードだと、新しい型が増えたとき、型情報の一覧に追加するだけで対応できます。if 文または switch - case 文で、分岐を増やすってのが、したくなかった。それだけの理由でリフレクションを使ってみたのだけど、あまりうれしくなかったです。
とにかく、それらがあるもとして、supports
に、その型を列挙します。列挙されているものを順に、CanParse
メソッドを呼び出して、解析できるかどうかを判断します。このコードは CanParse
メソッドがあることを前提にしていますが、当然 canParse
の null チェックをしておくべきでしょう。
引数のない規定のコンストラクタは「静的な」コンストラクタなのですが、引数のあるコンストラクタは「動的な」コンストラクタなのだそうです。知らなかった。動的なコンストラクタは、インスタンスがなければ呼び出せません。その為、一度規定のコンストラクタを検索して、呼び出してインスタンスを生成し、そのインスタンスを利用して、引数を持ったコンストラクタを呼び出しています。
AnalyzerRss10
、AnalyzerRss20
、AnalyzerAtom
の親は、次のように定義します。CanParse
メソッドは、静的メソッドなので、ここには定義しません。
abstract class SyndicationAnalyzer
{
protected XDocument document;
#region プロパティ
/// <summary>
/// ドキュメントが設定され、解析ができる場合は true を返します。
/// </summary>
public virtual bool CanUse {
get { return (this.document != null); }
}
/// <summary>
/// 配信サイトのタイトルを取得します。
/// </summary>
public abstract string FeedTitle {
get;
}
/// <summary>
/// 配信サイトへの URL を取得します。
/// </summary>
public abstract Uri FeedLink {
get;
}
/// <summary>
/// 配信サイトの説明を取得します。
/// </summary>
public abstract string FeedDescription {
get;
}
/// <summary>
/// 配信中のアイテムの個数を取得します。
/// </summary>
public abstract int ItemCount {
get;
}
public abstract string ItemTitle(int index);
public abstract Uri ItemLink(int index);
public abstract string ItemDescription(int index);
#endregion
public static SyndicationAnalyzer CreateInstance(XDocument document) {
// 省略
}
}
投稿日時 : 2009年6月29日 21:32