做网站的本质无非是一些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程序员所熟悉的东东,为了使别人看到我的方案不至于不知所谓,我也只能实现和它差不多的方案,而且我知道我要的是直接与最原始的原素打交道的权力,而不是要去否定别的方案和形式。
说了这么多,应该开始说说我的代码了,以下是模板分析的主要代码片段,具体的分析我会在后续的文章中进行说明。
1internal 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 }
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 }