1 // ================================================================================================
3 // MediaWikiのページを解析するパーサークラスソース</summary>
5 // <copyright file="MediaWikiParser.cs" company="honeplusのメモ帳">
6 // Copyright (C) 2012 Honeplus. All rights reserved.</copyright>
9 // ================================================================================================
11 namespace Honememo.Wptscs.Parsers
14 using System.Collections.Generic;
16 using Honememo.Parsers;
17 using Honememo.Utilities;
18 using Honememo.Wptscs.Websites;
21 /// MediaWikiのページを解析するパーサークラスです。
23 public class MediaWikiParser : XmlParser
28 /// このパーサーが対応するMediaWiki。
30 private MediaWiki website;
37 /// 指定されたMediaWikiサーバーのページを解析するためのパーサーを作成する。
39 /// <param name="site">このパーサーが対応するMediaWiki。</param>
40 /// <exception cref="ArgumentNullException"><c>null</c>が指定された場合。</exception>
41 public MediaWikiParser(MediaWiki site)
43 // 子パーサーのうち、再帰的に処理を行ういくつかのパーサーについては
45 // ※ 通常は意味が無いが、複雑なテンプレート等で解析失敗が多発し、
46 // 何度も同じ文字列を解析してしまうときに非常に時間がかかるため
48 this.CommentParser = new XmlCommentElementParser();
49 this.NowikiParser = new MediaWikiNowikiParser(this);
50 this.LinkParser = new CacheParser(new MediaWikiLinkParser(this));
51 this.TemplateParser = new CacheParser(new MediaWikiTemplateParser(this));
52 this.VariableParser = new CacheParser(new MediaWikiVariableParser(this));
53 this.HeadingParser = new CacheParser(new MediaWikiHeadingParser(this));
63 /// <remarks><see cref="Dispose"/>の呼び出しのみ。</remarks>
74 /// このパーサーが対応するMediaWiki。
76 /// <exception cref="ArgumentNullException"><c>null</c>が指定された場合。</exception>
77 public MediaWiki Website
86 this.website = Validate.NotNull(value);
94 // ※ 各要素のパーサーについては相互参照しているものが多々あり、
95 // 個別のクラスでnewされると危険なことから、ここで生成して公開する。
98 /// パーサー内で使用するXMLコメント要素のパーサー。
100 internal IParser CommentParser
107 /// パーサー内で使用するnowikiブロックのパーサー。
109 internal IParser NowikiParser
116 /// パーサー内で使用するMediaWiki内部リンクのパーサー。
118 internal IParser LinkParser
125 /// パーサー内で使用するMediaWikiテンプレートのパーサー。
127 internal IParser TemplateParser
134 /// パーサー内で使用するMediaWiki変数のパーサー。
136 internal IParser VariableParser
143 /// パーサー内で使用するMediaWiki変数のパーサー。
145 internal IParser HeadingParser
153 #region ITextParserインタフェース実装メソッド
156 /// 渡されたMediaWikiページに対して、指定された終了条件を満たすまで解析を行う。
158 /// <param name="s">解析対象の文字列。</param>
159 /// <param name="condition">解析を終了するかの判定を行うデリゲート。</param>
160 /// <param name="result">解析結果。</param>
161 /// <returns>解析に成功した場合<c>true</c>。</returns>
162 /// <remarks>指定された終了条件を満たさない場合、最終位置まで解析を行う。</remarks>
163 /// <exception cref="ObjectDisposedException"><see cref="Dispose"/>が実行済みの場合。</exception>
164 public override bool TryParseToEndCondition(string s, IsEndCondition condition, out IElement result)
172 else if (this.NowikiParser == null)
174 // 子パーサーが解放済みの場合Dispose済みで処理不可(同時にnullになるので代表でNowikiParser)
175 throw new ObjectDisposedException(this.GetType().Name);
178 // 文字列を1文字ずつチェックし、その内容に応じた要素のリストを作成する
179 ListElement list = new ListElement();
180 StringBuilder b = new StringBuilder();
181 bool newLine = false;
182 for (int i = 0; i < s.Length; i++)
184 // 終了条件のチェック、未指定時は条件なし
185 if (condition != null && condition(s, i))
190 IElement innerElement;
194 // 改行の場合、次回に見出しの解析が必要なため記録
203 if (this.TryParseAt(s, i, out innerElement, this.HeadingParser))
205 // それまでに解析済みのテキストを吐き出し、
207 this.FlashText(ref list, ref b);
208 list.Add(innerElement);
209 i += innerElement.ToString().Length - 1;
215 if (this.TryParseAt(s, i, out innerElement, this.CommentParser))
217 // それまでに解析済みのテキストを吐き出し、
219 this.FlashText(ref list, ref b);
220 list.Add(innerElement);
221 i += innerElement.ToString().Length - 1;
223 // コメント中に改行が含まれた場合も、見出しの処理を有効化する
224 if (innerElement.ToString().Contains("\n"))
232 // それ以外のnowiki, 変数, 内部リンク, テンプレートの各要素のTryParse処理を呼び出し
240 this.TemplateParser))
242 // それまでに解析済みのテキストを吐き出し、
244 this.FlashText(ref list, ref b);
245 list.Add(innerElement);
246 i += innerElement.ToString().Length - 1;
250 // 通常の文字列はテキスト要素として積み上げる
254 // 残っていれば最後に解析済みのテキストを吐き出し
255 this.FlashText(ref list, ref b);
260 // リストが1件であれば、その要素を直に返す
263 else if (list.Count == 0)
265 // 何もなければ、空文字列だったものとして空のテキスト要素を返す
266 result = new TextElement();
274 #region IDisposableインタフェース実装メソッド
277 /// このパーサーで使用する子パーサーを解放する。
279 public override void Dispose()
282 // ※ 以下は循環参照のため、明示的に解放しないとGCされない可能性がある
283 if (this.NowikiParser != null)
285 this.NowikiParser = null;
288 if (this.LinkParser != null)
290 this.LinkParser = null;
293 if (this.TemplateParser != null)
295 this.TemplateParser = null;
298 if (this.VariableParser != null)
300 this.VariableParser = null;
303 if (this.HeadingParser != null)
305 this.HeadingParser = null;
308 // 親クラスもIDisposableなため呼び出し
311 // ファイナライザ(このクラスではDisposeを呼ぶだけ)が不要であることを通知
312 GC.SuppressFinalize(this);