昨天发了一篇关于模板的功能介绍的文章,今天我想说说我为什么想设计一个自己的模板分析程序而不愿意使用微软老大给我们做好的近似完美的一切.
做网站的本质无非是一些html加一点点css,再放一些Js做调料,这加工出来的就是各种各样的网站平台;但微软老大却先把html和css做成美国大汉堡,再把JS弄成根香肠提供给广大的食客。虽然大家都喜欢这种大餐,但吃多也终究不是很好,而且有时候我们需要的是一份简单的农家小炒,所以我就通过几天的努力让自己重新有机会直接与HTML、CSS、JS等打交道。
前面有朋友说我只是把<asp:Repeater id="rptTables" > 换成了{repeater rptTables},虽然我当时不太同意这种说法,但细想一下其实这种说法也是对的。这所以要把<asp:Repeater id="rptTables" > 换成{repeater rptTables},是因为后者比前者更容易分析。也有朋友说我是用另一种方式重新实现了另一种ASP.NET控件,其实这也是正确的,ASP.NET控件的好处和使用方式已经是广大.NET程序员所熟悉的东东,为了使别人看到我的方案不至于不知所谓,我也只能实现和它差不多的方案,而且我知道我要的是直接与最原始的原素打交道的权力,而不是要去否定别的方案和形式。
说了这么多,应该开始说说我的代码了,以下是模板分析的主要代码片段,具体的分析我会在后续的文章中进行说明。
做网站的本质无非是一些html加一点点css,再放一些Js做调料,这加工出来的就是各种各样的网站平台;但微软老大却先把html和css做成美国大汉堡,再把JS弄成根香肠提供给广大的食客。虽然大家都喜欢这种大餐,但吃多也终究不是很好,而且有时候我们需要的是一份简单的农家小炒,所以我就通过几天的努力让自己重新有机会直接与HTML、CSS、JS等打交道。
前面有朋友说我只是把<asp:Repeater id="rptTables" > 换成了{repeater rptTables},虽然我当时不太同意这种说法,但细想一下其实这种说法也是对的。这所以要把<asp:Repeater id="rptTables" > 换成{repeater rptTables},是因为后者比前者更容易分析。也有朋友说我是用另一种方式重新实现了另一种ASP.NET控件,其实这也是正确的,ASP.NET控件的好处和使用方式已经是广大.NET程序员所熟悉的东东,为了使别人看到我的方案不至于不知所谓,我也只能实现和它差不多的方案,而且我知道我要的是直接与最原始的原素打交道的权力,而不是要去否定别的方案和形式。
说了这么多,应该开始说说我的代码了,以下是模板分析的主要代码片段,具体的分析我会在后续的文章中进行说明。
1
internal class Template : IUI.ITemplate
2
{
3
bool _isInstantiateIn = false;
4
private Dictionary<string, UIModel.Control> dicContainer;
5
private List<Control> listContainer;
6
private List<Token> tokens;
7
private char[] chrs;
8
9
public Template()
10
{
11
dicContainer = new Dictionary<string, Control>();
12
listContainer = new List<Control>();
13
tokens = new List<Token>();
14
}
15
16
public void InstantiateIn(ref string input)
17
{
18
_isInstantiateIn = true;
19
chrs = input.ToCharArray();
20
21
InitTokens(chrs);
22
23
GroupTokens();
24
25
InitTags();
26
}
27
28
public bool ContainsKey(string id)
29
{
30
return dicContainer.ContainsKey(id);
31
}
32
33
public Ctit.TTCCostPro.UIModel.Control FindControl(string id)
34
{
35
if (dicContainer.ContainsKey(id))
36
{
37
return dicContainer[id];
38
}
39
else
40
{
41
return null;
42
}
43
}
44
45
public string Render()
46
{
47
if (!_isInstantiateIn)
48
throw new Exception("Template must InstantiateIn before render!!");
49
50
//StringBuilder sb = new StringBuilder();
51
52
//for (int i = 0; i < tokens.Count; i++)
53
//{
54
// sb.AppendFormat("First: {0}, Second: {1}, StartIndex: {2}, EndIndex: {3} TokenType: {4} InnerStart: {5}, InnerEnd: {6} <br />", tokens[i].First, tokens[i].Second, tokens[i].StartIndex, tokens[i].EndIndex, tokens[i].TokenType.ToString(), tokens[i].InnerStart, tokens[i].InnerEnd);
55
//}
56
//return sb.ToString();
57
58
StringBuilder sb = new StringBuilder();
59
60
int k = 0;
61
62
for (int i = 0; i < listContainer.Count; i++)
63
{
64
while (k < listContainer[i].StartIndex && k < chrs.Length)
65
{
66
sb.Append(chrs[k]);
67
k++;
68
}
69
70
if (listContainer[i].Display)
71
{
72
StringBuilder sHtml = new StringBuilder();
73
RenderControl(listContainer[i], sHtml);
74
sb.Append(sHtml);
75
}
76
k = listContainer[i].EndIndex + 1;
77
}
78
79
while (k < chrs.Length)
80
{
81
sb.Append(chrs[k++]);
82
}
83
84
return sb.ToString();
85
}
86
87
private void RenderControl(Control ctr, StringBuilder sHtml)
88
{
89
switch (ctr.TagName.ToLower())
90
{
91
case "repeater":
92
{
93
Repeater rpt = (Repeater)ctr;
94
95
96
if (rpt.DataSource != null)
97
{
98
CreateInnerTemplate(sHtml, rpt, rpt.HeaderTemplate);
99
IEnumerable date = (IEnumerable)rpt.DataSource;
100
101
foreach (object o in date)
102
{
103
rpt.Current = new Dictionary<string, string>();
104
PropertyInfo[] properties = o.GetType().GetProperties();
105
foreach (PropertyInfo p in properties)
106
{
107
rpt.Current.Add(p.Name, p.GetValue(o, null).ToString());
108
}
109
CreateInnerTemplate(sHtml, rpt, rpt.ItemTemplate);
110
}
111
112
CreateInnerTemplate(sHtml, rpt, rpt.FooterTemplate);
113
}
114
115
break;
116
}
117
case "view":
118
{
119
break;
120
}
121
case "eval":
122
{
123
TextControl eval = (TextControl)ctr;
124
if (eval.ParentNode.Current.ContainsKey(eval.Second))
125
{
126
sHtml.Append(eval.ParentNode.Current[eval.Second]);
127
}
128
break;
129
}
130
default:
131
{
132
break;
133
}
134
}
135
}
136
137
private void CreateInnerTemplate(StringBuilder sHtml, Repeater rpt, InnerIndex inner)
138
{
139
if (Controls.HadChildTag(inner, rpt))
140
{
141
List<Control> ls = Controls.GetChildNodes(inner, rpt);
142
int k = inner.InnerStart;
143
144
for (int i = 0; i < ls.Count; i++)
145
{
146
while (k < ls[i].StartIndex && k < inner.InnerEnd)
147
{
148
sHtml.Append(chrs[k++]);
149
}
150
151
if (ls[i].Display == true)
152
{
153
RenderControl(ls[i], sHtml);
154
}
155
156
k = ls[i].EndIndex + 1;
157
}
158
159
while (k < inner.InnerEnd)
160
{
161
sHtml.Append(chrs[k++]);
162
}
163
}
164
else
165
{
166
CharsManager.Copy(chrs, inner, sHtml);
167
}
168
}
169
170
private void AddSingleTag(Control parentNode, Token token)
171
{
172
switch (token.First.ToLower())
173
{
174
case "page":
175
case "eval":
176
{
177
TextControl textInfo = new TextControl();
178
textInfo.StartIndex = token.StartIndex;
179
textInfo.EndIndex = token.EndIndex;
180
textInfo.First = token.First;
181
textInfo.Second = token.Second;
182
textInfo.ParentNode = parentNode;
183
textInfo.TagName = token.First;
184
185
//把根结点元素放在列表容器里面去.
186
if (parentNode == null)
187
{
188
listContainer.Add(textInfo);
189
}
190
else//子结点放在父结点下面
191
{
192
parentNode.AppendChild(textInfo);
193
}
194
break;
195
}
196
default:
197
break;
198
}
199
}
200
201
private void AddComplexTag(Control parentNode, ref int index)
202
{
203
if (index >= tokens.Count)
204
return;
205
206
Token token = tokens[index];
207
208
switch (token.First.ToLower())
209
{
210
case "repeater":
211
{
212
Repeater rpt = new Repeater();
213
rpt.Id = token.Second;
214
rpt.StartIndex = token.StartIndex;
215
rpt.EndIndex = token.EndIndex;
216
rpt.ParentNode = parentNode;
217
rpt.TagName = token.First;
218
219
while (++index < tokens.Count && tokens[index].EndIndex != token.EndIndex)
220
{
221
if (tokens[index].TokenType == TokenType.Single)
222
{
223
AddSingleTag(rpt, tokens[index]);
224
}
225
else if (tokens[index].TokenType == TokenType.CloseBegin)
226
{
227
switch (tokens[index].First.ToLower())
228
{
229
case "headertemplate":
230
{
231
rpt.HeaderTemplate.InnerStart = tokens[index].InnerStart;
232
rpt.HeaderTemplate.InnerEnd = tokens[index].InnerEnd;
233
break;
234
}
235
case "itemtemplate":
236
{
237
rpt.ItemTemplate.InnerStart = tokens[index].InnerStart;
238
rpt.ItemTemplate.InnerEnd = tokens[index].InnerEnd;
239
break;
240
}
241
case "alternatingitemtemplate":
242
{
243
rpt.AlternatingItemTemplate.InnerStart = tokens[index].InnerStart;
244
rpt.AlternatingItemTemplate.InnerEnd = tokens[index].InnerEnd;
245
break;
246
}
247
case "separatortemplate":
248
{
249
rpt.SeparatorTemplate.InnerStart = tokens[index].InnerStart;
250
rpt.SeparatorTemplate.InnerEnd = tokens[index].InnerEnd;
251
break;
252
}
253
case "footertemplate":
254
{
255
rpt.FooterTemplate.InnerStart = tokens[index].InnerStart;
256
rpt.FooterTemplate.InnerEnd = tokens[index].InnerEnd;
257
break;
258
}
259
default:
260
break;
261
}
262
}
263
else if (tokens[index].TokenType == TokenType.ComplexBegin)
264
{
265
AddComplexTag(rpt, ref index);
266
}
267
}
268
269
if (parentNode != null)
270
{
271
parentNode.AppendChild(rpt);
272
}
273
else
274
{
275
listContainer.Add(rpt);
276
}
277
278
if (!dicContainer.ContainsKey(rpt.Id))
279
{
280
dicContainer.Add(rpt.Id, rpt);
281
}
282
#if DEBUG
283
else
284
{
285
throw new Exception(string.Format("Another control in this page already uses id: {0}", rpt.Id));
286
}
287
#endif
288
break;
289
}
290
case "view":
291
{
292
break;
293
}
294
default:
295
break;
296
}
297
}
298
299
private void InitTags()
300
{
301
for (int i = 0; i < tokens.Count; i++)
302
{
303
Token token = tokens[i];
304
if (token.TokenType == TokenType.Single)
305
{
306
AddSingleTag(null, token);
307
}
308
else if (token.TokenType == TokenType.ComplexBegin)
309
{
310
AddComplexTag(null, ref i);
311
}
312
}
313
}
314
315
private void InitTokens(char[] chrs)
316
{
317
for (int i = 0; i < chrs.Length; i++)
318
{
319
if (chrs[i] == '{' && (i == 0 || chrs[i - 1] != '\\'))
320
{
321
Token token = new Token();
322
token.StartIndex = i;
323
324
if (chrs[i + 1] == '/')
325
{
326
if (++i >= chrs.Length)
327
break;
328
329
Pair<string, string> p = Tags.GetTag(chrs, ref i);
330
token.First = p.First;
331
token.Second = p.Second;
332
token.TokenType = GetTokenType(token.First, true);
333
}
334
else
335
{
336
Pair<string, string> p = Tags.GetTag(chrs, ref i);
337
token.First = p.First;
338
token.Second = p.Second;
339
token.TokenType = GetTokenType(token.First, false);
340
}
341
342
token.EndIndex = i;
343
tokens.Add(token);
344
}
345
}
346
}
347
348
private void GroupTokens()
349
{
350
Stack<Token> s = new Stack<Token>();
351
352
for (int i = 0; i < tokens.Count; i++)
353
{
354
if (tokens[i].TokenType == TokenType.ComplexBegin || tokens[i].TokenType == TokenType.CloseBegin )
355
{
356
s.Push(tokens[i]);
357
}
358
else if (tokens[i].TokenType == TokenType.ComplexEnd || tokens[i].TokenType == TokenType.CloseEnd)
359
{
360
if (string.Compare(tokens[i].First, s.Peek().First) == 0)
361
{
362
Token token = s.Pop();
363
token.InnerStart = token.EndIndex + 1;
364
token.InnerEnd = tokens[i].StartIndex;
365
token.EndIndex = tokens[i].EndIndex;
366
}
367
else
368
{
369
s.Push(tokens[i]);
370
}
371
}
372
}
373
374
if (s.Count != 0)
375
{
376
throw new Exception("Tags do not match, please check your template file.");
377
}
378
}
379
380
private TokenType GetTokenType(string tagName, bool isEnd)
381
{
382
TagType tagType = TagTypeManager.GetTagType(tagName);
383
TokenType tokenType = new TokenType();
384
385
if (isEnd)
386
{
387
if (tagType == TagType.Close)
388
{
389
tokenType = TokenType.CloseEnd;
390
}
391
else if (tagType == TagType.Complex)
392
{
393
tokenType = TokenType.ComplexEnd;
394
}
395
else
396
{
397
tokenType = TokenType.NotToken;
398
}
399
}
400
else
401
{
402
if (tagType == TagType.Close)
403
{
404
tokenType = TokenType.CloseBegin;
405
}
406
else if (tagType == TagType.Complex)
407
{
408
tokenType = TokenType.ComplexBegin;
409
}
410
else if (tagType == TagType.Single)
411
{
412
tokenType = TokenType.Single;
413
}
414
else
415
{
416
tokenType = TokenType.NotToken;
417
}
418
}
419
420
return tokenType;
421
}
422
}
internal class Template : IUI.ITemplate2
{3
bool _isInstantiateIn = false;4
private Dictionary<string, UIModel.Control> dicContainer;5
private List<Control> listContainer;6
private List<Token> tokens;7
private char[] chrs;8

9
public Template()10
{11
dicContainer = new Dictionary<string, Control>();12
listContainer = new List<Control>();13
tokens = new List<Token>();14
}15

16
public void InstantiateIn(ref string input)17
{18
_isInstantiateIn = true;19
chrs = input.ToCharArray();20

21
InitTokens(chrs);22

23
GroupTokens();24

25
InitTags();26
}27

28
public bool ContainsKey(string id)29
{30
return dicContainer.ContainsKey(id);31
}32

33
public Ctit.TTCCostPro.UIModel.Control FindControl(string id)34
{35
if (dicContainer.ContainsKey(id))36
{37
return dicContainer[id];38
}39
else40
{41
return null;42
}43
}44

45
public string Render()46
{47
if (!_isInstantiateIn)48
throw new Exception("Template must InstantiateIn before render!!");49

50
//StringBuilder sb = new StringBuilder();51

52
//for (int i = 0; i < tokens.Count; i++)53
//{54
// sb.AppendFormat("First: {0}, Second: {1}, StartIndex: {2}, EndIndex: {3} TokenType: {4} InnerStart: {5}, InnerEnd: {6} <br />", tokens[i].First, tokens[i].Second, tokens[i].StartIndex, tokens[i].EndIndex, tokens[i].TokenType.ToString(), tokens[i].InnerStart, tokens[i].InnerEnd);55
//}56
//return sb.ToString();57

58
StringBuilder sb = new StringBuilder();59

60
int k = 0;61

62
for (int i = 0; i < listContainer.Count; i++)63
{64
while (k < listContainer[i].StartIndex && k < chrs.Length)65
{66
sb.Append(chrs[k]);67
k++;68
}69

70
if (listContainer[i].Display)71
{72
StringBuilder sHtml = new StringBuilder();73
RenderControl(listContainer[i], sHtml);74
sb.Append(sHtml);75
}76
k = listContainer[i].EndIndex + 1;77
}78

79
while (k < chrs.Length)80
{81
sb.Append(chrs[k++]);82
}83

84
return sb.ToString();85
}86

87
private void RenderControl(Control ctr, StringBuilder sHtml)88
{89
switch (ctr.TagName.ToLower())90
{91
case "repeater":92
{93
Repeater rpt = (Repeater)ctr;94

95

96
if (rpt.DataSource != null)97
{98
CreateInnerTemplate(sHtml, rpt, rpt.HeaderTemplate);99
IEnumerable date = (IEnumerable)rpt.DataSource;100

101
foreach (object o in date)102
{103
rpt.Current = new Dictionary<string, string>();104
PropertyInfo[] properties = o.GetType().GetProperties();105
foreach (PropertyInfo p in properties)106
{107
rpt.Current.Add(p.Name, p.GetValue(o, null).ToString());108
}109
CreateInnerTemplate(sHtml, rpt, rpt.ItemTemplate);110
}111

112
CreateInnerTemplate(sHtml, rpt, rpt.FooterTemplate);113
}114

115
break;116
}117
case "view":118
{119
break;120
}121
case "eval":122
{123
TextControl eval = (TextControl)ctr;124
if (eval.ParentNode.Current.ContainsKey(eval.Second))125
{126
sHtml.Append(eval.ParentNode.Current[eval.Second]);127
}128
break;129
}130
default:131
{132
break;133
}134
}135
}136

137
private void CreateInnerTemplate(StringBuilder sHtml, Repeater rpt, InnerIndex inner)138
{139
if (Controls.HadChildTag(inner, rpt))140
{141
List<Control> ls = Controls.GetChildNodes(inner, rpt);142
int k = inner.InnerStart;143

144
for (int i = 0; i < ls.Count; i++)145
{146
while (k < ls[i].StartIndex && k < inner.InnerEnd)147
{148
sHtml.Append(chrs[k++]);149
}150

151
if (ls[i].Display == true)152
{153
RenderControl(ls[i], sHtml);154
}155

156
k = ls[i].EndIndex + 1;157
}158

159
while (k < inner.InnerEnd)160
{161
sHtml.Append(chrs[k++]);162
}163
}164
else165
{166
CharsManager.Copy(chrs, inner, sHtml);167
}168
}169

170
private void AddSingleTag(Control parentNode, Token token)171
{172
switch (token.First.ToLower())173
{174
case "page":175
case "eval":176
{177
TextControl textInfo = new TextControl();178
textInfo.StartIndex = token.StartIndex;179
textInfo.EndIndex = token.EndIndex;180
textInfo.First = token.First;181
textInfo.Second = token.Second;182
textInfo.ParentNode = parentNode;183
textInfo.TagName = token.First;184

185
//把根结点元素放在列表容器里面去.186
if (parentNode == null)187
{188
listContainer.Add(textInfo);189
}190
else//子结点放在父结点下面191
{192
parentNode.AppendChild(textInfo);193
}194
break;195
}196
default:197
break;198
}199
}200

201
private void AddComplexTag(Control parentNode, ref int index)202
{203
if (index >= tokens.Count)204
return;205

206
Token token = tokens[index];207

208
switch (token.First.ToLower())209
{210
case "repeater":211
{212
Repeater rpt = new Repeater();213
rpt.Id = token.Second;214
rpt.StartIndex = token.StartIndex;215
rpt.EndIndex = token.EndIndex;216
rpt.ParentNode = parentNode;217
rpt.TagName = token.First;218

219
while (++index < tokens.Count && tokens[index].EndIndex != token.EndIndex)220
{221
if (tokens[index].TokenType == TokenType.Single)222
{223
AddSingleTag(rpt, tokens[index]);224
}225
else if (tokens[index].TokenType == TokenType.CloseBegin)226
{227
switch (tokens[index].First.ToLower())228
{229
case "headertemplate":230
{231
rpt.HeaderTemplate.InnerStart = tokens[index].InnerStart;232
rpt.HeaderTemplate.InnerEnd = tokens[index].InnerEnd;233
break;234
}235
case "itemtemplate":236
{237
rpt.ItemTemplate.InnerStart = tokens[index].InnerStart;238
rpt.ItemTemplate.InnerEnd = tokens[index].InnerEnd;239
break;240
}241
case "alternatingitemtemplate":242
{243
rpt.AlternatingItemTemplate.InnerStart = tokens[index].InnerStart;244
rpt.AlternatingItemTemplate.InnerEnd = tokens[index].InnerEnd;245
break;246
}247
case "separatortemplate":248
{249
rpt.SeparatorTemplate.InnerStart = tokens[index].InnerStart;250
rpt.SeparatorTemplate.InnerEnd = tokens[index].InnerEnd;251
break;252
}253
case "footertemplate":254
{255
rpt.FooterTemplate.InnerStart = tokens[index].InnerStart;256
rpt.FooterTemplate.InnerEnd = tokens[index].InnerEnd;257
break;258
}259
default:260
break;261
}262
}263
else if (tokens[index].TokenType == TokenType.ComplexBegin)264
{265
AddComplexTag(rpt, ref index);266
}267
}268

269
if (parentNode != null)270
{271
parentNode.AppendChild(rpt);272
}273
else274
{275
listContainer.Add(rpt);276
}277

278
if (!dicContainer.ContainsKey(rpt.Id))279
{280
dicContainer.Add(rpt.Id, rpt);281
}282
#if DEBUG283
else284
{285
throw new Exception(string.Format("Another control in this page already uses id: {0}", rpt.Id));286
}287
#endif288
break;289
}290
case "view":291
{292
break;293
}294
default:295
break;296
}297
}298

299
private void InitTags()300
{301
for (int i = 0; i < tokens.Count; i++)302
{303
Token token = tokens[i];304
if (token.TokenType == TokenType.Single)305
{306
AddSingleTag(null, token);307
}308
else if (token.TokenType == TokenType.ComplexBegin)309
{310
AddComplexTag(null, ref i);311
}312
}313
}314

315
private void InitTokens(char[] chrs)316
{317
for (int i = 0; i < chrs.Length; i++)318
{319
if (chrs[i] == '{' && (i == 0 || chrs[i - 1] != '\\'))320
{321
Token token = new Token();322
token.StartIndex = i;323

324
if (chrs[i + 1] == '/')325
{326
if (++i >= chrs.Length)327
break;328

329
Pair<string, string> p = Tags.GetTag(chrs, ref i);330
token.First = p.First;331
token.Second = p.Second;332
token.TokenType = GetTokenType(token.First, true);333
}334
else335
{336
Pair<string, string> p = Tags.GetTag(chrs, ref i);337
token.First = p.First;338
token.Second = p.Second;339
token.TokenType = GetTokenType(token.First, false);340
}341

342
token.EndIndex = i;343
tokens.Add(token);344
}345
}346
}347

348
private void GroupTokens()349
{350
Stack<Token> s = new Stack<Token>();351

352
for (int i = 0; i < tokens.Count; i++)353
{354
if (tokens[i].TokenType == TokenType.ComplexBegin || tokens[i].TokenType == TokenType.CloseBegin )355
{356
s.Push(tokens[i]);357
}358
else if (tokens[i].TokenType == TokenType.ComplexEnd || tokens[i].TokenType == TokenType.CloseEnd)359
{360
if (string.Compare(tokens[i].First, s.Peek().First) == 0)361
{362
Token token = s.Pop();363
token.InnerStart = token.EndIndex + 1;364
token.InnerEnd = tokens[i].StartIndex;365
token.EndIndex = tokens[i].EndIndex;366
}367
else368
{369
s.Push(tokens[i]);370
}371
}372
}373

374
if (s.Count != 0)375
{376
throw new Exception("Tags do not match, please check your template file.");377
}378
}379

380
private TokenType GetTokenType(string tagName, bool isEnd)381
{382
TagType tagType = TagTypeManager.GetTagType(tagName);383
TokenType tokenType = new TokenType();384

385
if (isEnd)386
{387
if (tagType == TagType.Close)388
{389
tokenType = TokenType.CloseEnd;390
}391
else if (tagType == TagType.Complex)392
{393
tokenType = TokenType.ComplexEnd;394
}395
else396
{397
tokenType = TokenType.NotToken;398
}399
}400
else401
{402
if (tagType == TagType.Close)403
{404
tokenType = TokenType.CloseBegin;405
}406
else if (tagType == TagType.Complex)407
{408
tokenType = TokenType.ComplexBegin;409
}410
else if (tagType == TagType.Single)411
{412
tokenType = TokenType.Single;413
}414
else415
{416
tokenType = TokenType.NotToken;417
}418
}419

420
return tokenType;421
}422
}

浙公网安备 33010602011771号