OSDN Git Service

Wikipedia翻訳支援ツール Ver1.10時点のソース
[wptscs/wpts.git] / Wptscs / Parsers / MediaWikiParser.cs
1 // ================================================================================================
2 // <summary>
3 //      MediaWikiのページを解析するパーサークラスソース</summary>
4 //
5 // <copyright file="MediaWikiParser.cs" company="honeplusのメモ帳">
6 //      Copyright (C) 2012 Honeplus. All rights reserved.</copyright>
7 // <author>
8 //      Honeplus</author>
9 // ================================================================================================
10
11 namespace Honememo.Wptscs.Parsers
12 {
13     using System;
14     using System.Collections.Generic;
15     using System.Text;
16     using Honememo.Parsers;
17     using Honememo.Utilities;
18     using Honememo.Wptscs.Websites;
19
20     /// <summary>
21     /// MediaWikiのページを解析するパーサークラスです。
22     /// </summary>
23     public class MediaWikiParser : XmlParser
24     {
25         #region private変数
26
27         /// <summary>
28         /// このパーサーが対応するMediaWiki。
29         /// </summary>
30         private MediaWiki website;
31
32         #endregion
33         
34         #region コンストラクタ
35
36         /// <summary>
37         /// 指定されたMediaWikiサーバーのページを解析するためのパーサーを作成する。
38         /// </summary>
39         /// <param name="site">このパーサーが対応するMediaWiki</param>
40         public MediaWikiParser(MediaWiki site)
41         {
42             this.Website = site;
43             this.CommentParser = new XmlCommentElementParser();
44             this.NowikiParser = new MediaWikiNowikiParser(this);
45             this.LinkParser = new MediaWikiLinkParser(this);
46             this.TemplateParser = new MediaWikiTemplateParser(this);
47             this.VariableParser = new MediaWikiVariableParser(this);
48             this.HeadingParser = new MediaWikiHeadingParser(this);
49         }
50
51         #endregion
52
53         #region 公開プロパティ
54
55         /// <summary>
56         /// このパーサーが対応するMediaWiki。
57         /// </summary>
58         /// <exception cref="ArgumentNullException"><c>null</c>が指定された場合。</exception>
59         public MediaWiki Website
60         {
61             get
62             {
63                 return this.website;
64             }
65
66             set
67             {
68                 this.website = Validate.NotNull(value);
69             }
70         }
71
72         #endregion
73
74         #region 関連クラス公開プロパティ
75
76         // ※ 各要素のパーサーについては相互参照しているものが多々あり、
77         //    個別のクラスでnewされると危険なことから、ここで生成して公開する。
78
79         /// <summary>
80         /// パーサー内で使用するXMLコメント要素のパーサー。
81         /// </summary>
82         internal IParser CommentParser
83         {
84             get;
85             private set;
86         }
87
88         /// <summary>
89         /// パーサー内で使用するnowikiブロックのパーサー。
90         /// </summary>
91         internal IParser NowikiParser
92         {
93             get;
94             private set;
95         }
96
97         /// <summary>
98         /// パーサー内で使用するMediaWiki内部リンクのパーサー。
99         /// </summary>
100         internal IParser LinkParser
101         {
102             get;
103             private set;
104         }
105
106         /// <summary>
107         /// パーサー内で使用するMediaWikiテンプレートのパーサー。
108         /// </summary>
109         internal IParser TemplateParser
110         {
111             get;
112             private set;
113         }
114
115         /// <summary>
116         /// パーサー内で使用するMediaWiki変数のパーサー。
117         /// </summary>
118         internal IParser VariableParser
119         {
120             get;
121             private set;
122         }
123
124         /// <summary>
125         /// パーサー内で使用するMediaWiki変数のパーサー。
126         /// </summary>
127         internal IParser HeadingParser
128         {
129             get;
130             private set;
131         }
132
133         #endregion
134
135         #region インタフェース実装メソッド
136
137         /// <summary>
138         /// 渡されたMediaWikiページに対して、指定された終了条件を満たすまで解析を行う。
139         /// </summary>
140         /// <param name="s">解析対象の文字列。</param>
141         /// <param name="condition">解析を終了するかの判定を行うデリゲート。</param>
142         /// <param name="result">解析結果。</param>
143         /// <returns>解析に成功した場合<c>true</c>。</returns>
144         /// <remarks>指定された終了条件を満たさない場合、最終位置まで解析を行う。</remarks>
145         public override bool TryParseToEndCondition(string s, IsEndCondition condition, out IElement result)
146         {
147             // 文字列を1文字ずつチェックし、その内容に応じた要素のリストを作成する
148             ListElement list = new ListElement();
149             StringBuilder b = new StringBuilder();
150             bool newLine = false;
151             for (int i = 0; i < s.Length; i++)
152             {
153                 // 終了条件のチェック、未指定時は条件なし
154                 if (condition != null && condition(s, i))
155                 {
156                     break;
157                 }
158
159                 IElement innerElement;
160
161                 if (s[i] == '\n')
162                 {
163                     // 改行の場合、次回に見出しの解析が必要なため記録
164                     b.Append(s[i]);
165                     newLine = true;
166                     continue;
167                 }
168                 else if (newLine)
169                 {
170                     // 見出しの解析
171                     newLine = false;
172                     if (this.TryParseAt(s, i, out innerElement, this.HeadingParser))
173                     {
174                         // それまでに解析済みのテキストを吐き出し、
175                         // その後に解析した要素を追加
176                         this.FlashText(ref list, ref b);
177                         list.Add(innerElement);
178                         i += innerElement.ToString().Length - 1;
179                         continue;
180                     }
181                 }
182
183                 // コメントの解析
184                 if (this.TryParseAt(s, i, out innerElement, this.CommentParser))
185                 {
186                     // それまでに解析済みのテキストを吐き出し、
187                     // その後に解析した要素を追加
188                     this.FlashText(ref list, ref b);
189                     list.Add(innerElement);
190                     i += innerElement.ToString().Length - 1;
191
192                     // コメント中に改行が含まれた場合も、見出しの処理を有効化する
193                     if (innerElement.ToString().Contains("\n"))
194                     {
195                         newLine = true;
196                     }
197
198                     continue;
199                 }
200
201                 // それ以外のnowiki, 変数, 内部リンク, テンプレートの各要素のTryParse処理を呼び出し
202                 if (this.TryParseAt(
203                     s,
204                     i,
205                     out innerElement,
206                     this.NowikiParser,
207                     this.VariableParser,
208                     this.LinkParser,
209                     this.TemplateParser))
210                 {
211                     // それまでに解析済みのテキストを吐き出し、
212                     // その後に解析した要素を追加
213                     this.FlashText(ref list, ref b);
214                     list.Add(innerElement);
215                     i += innerElement.ToString().Length - 1;
216                     continue;
217                 }
218
219                 // 通常の文字列はテキスト要素として積み上げる
220                 b.Append(s[i]);
221             }
222
223             // 残っていれば最後に解析済みのテキストを吐き出し
224             this.FlashText(ref list, ref b);
225
226             result = list;
227             if (list.Count == 1)
228             {
229                 // リストが1件であれば、その要素を直に返す
230                 result = list[0];
231             }
232             else if (list.Count == 0)
233             {
234                 // 何もなければ、空文字列だったものとして空のテキスト要素を返す
235                 result = new TextElement();
236             }
237
238             return true;
239         }
240
241         #endregion
242     }
243 }