一个简单的变量替换型模版

这个是为了Micolog.Net的“主题预编译”制作的模版工具。主要负责简单的模版替换,以及在模版文件中调用C#方法。

Micolog.Net 的主题机制采用的是XML的数据+XSLT转码生成HTML。在一个博客系统中,有很多设置,比如博客名称等是不经常更换的,与其在每次生成html时都从XML中转换,不如直接在选择主题时直接对这些设置进行替换。考虑到主题应有的扩展性,这个模版机制采用“注入方法”的方式实现。

首先看一个最简单的例子:

            var template = new Micolog.Common.Template.Simple();
            template.LoadString("Hi,I'm {$Username}");
            template.Parameters.Add("Username", "Soar、毅");
            template.Process();
            Console.WriteLine(template.ToString());
            //将输出 Hi,I'm Soar、毅

其次,有时候,我们会需要对传入的参数格式化,比如输出按照一定格式的日期:

            var template = new Micolog.Common.Template.Simple();
            template.LoadString("Hi,I'm {$Username} And Now Is {$Now:yyyy年MM月dd日}");
            template.Parameters.Add("Username", "Soar、毅");
            template.Parameters.Add("Now", DateTime.Now);
            template.Process();
            Console.WriteLine(template.ToString());
            //将输出 Hi,I'm Soar、毅 And Now Is 2012年08月24日

在做到这一步的时候,这个简单的模版引擎算是差不多了。可是还缺少点什么:扩展。因为一个博客模版在安装完成后,可能需要进行一些自定义的设置。这些设置就要通过另一个方法来完成了。这个就是,动态的调用方法,通过传入不同的参数实现扩展,并且可以定义默认值:

            var template = new Micolog.Common.Template.Simple();
            template.LoadString("Hi,I'm {$Username} And Now Is {$Now:yyyy年MM月dd日}\n1 + 1 = {$Add(1,1)}\n{$NotDifine(1,1),默认值}");
            template.Parameters.Add("Username", "Soar、毅");
            template.Parameters.Add("Now", DateTime.Now);
            template.Methods.Add("Add", (arg) => 
            {
                if (arg == null || arg.Length != 2) return "参数不正确!";
                return (Convert.ToInt32(arg[0]) + Convert.ToInt32(arg[1])).ToString();
            });
            template.Process();
            Console.WriteLine(template.ToString());
            //将输出
            //Hi,I'm Soar、毅 And Now Is 2012年08月24日
            //1 + 1 = 2
            //默认值

简单的引擎就是简单的引擎,不带有IF判断,For循环等。但是功能够用了。至少在Micolog.Net中够用了。模版采取的方式是正则表达式,除了,正则部分有点复杂之外,其他的还好。代码如下:

源代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.IO;
  5 using System.Text.RegularExpressions;
  6 using NewLife.Reflection;
  7 
  8 namespace Micolog.Common.Template
  9 {
 10     /// <summary>
 11     /// 简易模板,实现简单的模板替换
 12     /// </summary>
 13     /// <remarks>
 14     /// 简单变量替换:{$Date}
 15     /// 格式变量替换:{$Date:yyyy-MM-dd}
 16     /// 方法调用替换:{$GetDate(1,2,3),100}{$GetDate(1,2)}
 17     /// 方法调用格式替换:{$GetDate(1,2,3):0.00,100}{$GetDate(1,2):0.00}
 18     /// </remarks>
 19     public class Simple
 20     {
 21         private static readonly Regex SimpleTagReg = new Regex(@"\{\$(\w+)\}");
 22         private static readonly Regex FormatTagReg = new Regex(@"\{\$(\w+):([\w|\.]+)\}");
 23         private static readonly Regex MethodTagReg = new Regex(@"\{\$(\w+)\(([\w|,]+)\),([\w|\.]+)}");
 24         private static readonly Regex MethodFormatTagReg = new Regex(@"\{\$(\w+)\(([\w|,]+)\):([\w|\.]+),([\w|\.]+)}");
 25         private static readonly Regex MethodNotDefaultTagReg = new Regex(@"\{\$(\w+)\(([\w|,]+)\)}");
 26         private static readonly Regex MethodFormatNotDefaultTagReg = new Regex(@"\{\$(\w+)\(([\w|,]+)\):([\w|\.]+)}");
 27         private StringBuilder template;
 28         private String _Body;
 29         /// <summary>
 30         /// 模板内容
 31         /// </summary>
 32         public String Body
 33         {
 34             get 
 35             {
 36                 return _Body; 
 37             }
 38             set 
 39             {
 40                 _Body = value;
 41                 this.template = new StringBuilder(value);
 42             }
 43         }
 44         ///// <summary>
 45         ///// 输出模板内容
 46         ///// </summary>
 47         ///// <returns></returns>
 48         //public override string ToString()
 49         //{
 50         //    return this._Body;
 51         //}
 52         private Dictionary<String,Object> _Parameters;
 53         /// <summary>
 54         /// 编译参数
 55         /// </summary>
 56         public Dictionary<String,Object> Parameters
 57         {
 58             get 
 59             {
 60                 if (_Parameters == null)
 61                 {
 62                     lock (typeof(Simple))
 63                     {
 64                         if (_Parameters == null)
 65                         {
 66                             _Parameters = new Dictionary<String, Object>();
 67                         }
 68                     }
 69                 }
 70                 return _Parameters; 
 71             }
 72         }
 73 
 74         private Dictionary<String, Func<String[], Object>> _Methods;
 75         /// <summary>
 76         /// 编译方法
 77         /// </summary>
 78         public Dictionary<String, Func<String[], Object>> Methods
 79         {
 80             get
 81             {
 82                 if (_Methods == null)
 83                 {
 84                     lock (typeof(Simple))
 85                     {
 86                         _Methods = new Dictionary<String, Func<String[], Object>>();
 87                     }
 88                 }
 89                 return _Methods;
 90             }
 91         }
 92         
 93         /// <summary>
 94         /// 载入模板文件
 95         /// </summary>
 96         /// <param name="path"></param>
 97         public void Load(String path)
 98         {
 99             this.Load(path, Encoding.UTF8);
100         }
101         /// <summary>
102         /// 载入模板文件,并制定编码方式
103         /// </summary>
104         /// <param name="path"></param>
105         /// <param name="encoding"></param>
106         public void Load(String path, Encoding encoding)
107         {
108             using (var sr = new StreamReader(path, encoding))
109             {
110                 this._Body = sr.ReadToEnd();
111                 this.template = new StringBuilder(this._Body);
112             }
113         }
114         /// <summary>
115         /// 载入模板字符串
116         /// </summary>
117         /// <param name="body"></param>
118         public void LoadString(String body)
119         {
120             this._Body = body;
121             this.template = new StringBuilder(body);
122         }
123 
124         /// <summary>
125         /// 编译模板
126         /// </summary>
127         public void Process()
128         {
129             //Regex
130             if (this._Parameters == null) return;
131             var map = new Dictionary<String,String>();
132             //处理简单标签
133             foreach (Match match in SimpleTagReg.Matches(this._Body))
134             {
135                 var tag = match.Groups[0].Value;
136                 var name = match.Groups[1].Value;
137                 if (this._Parameters.ContainsKey(name) && !map.ContainsKey(tag))
138                 {
139                     //如果参数中包含这个标签,就将这个标签加入缓存
140                     map.Add(tag, this._Parameters[name].ToString());
141                 }
142             }
143             //处理格式化标签
144             foreach (Match match in FormatTagReg.Matches(this._Body))
145             {
146                 var tag = match.Groups[0].Value;
147                 var name = match.Groups[1].Value;
148                 var format = match.Groups[2].Value;
149                 if (this._Parameters.ContainsKey(name) && !map.ContainsKey(tag))
150                 {
151                     map.Add(tag, String.Format("{0:" + format + "}", this._Parameters[name]));
152                 }
153             }
154             //处理方法标签
155             foreach (Match match in MethodTagReg.Matches(this._Body))
156             {
157                 var tag = match.Groups[0].Value;
158                 var method = match.Groups[1].Value;
159                 var parameters = match.Groups[2].Value;
160                 var defaultValue = match.Groups[3].Value;
161                 if (!map.ContainsKey(tag))
162                 {
163                     if (this._Methods.ContainsKey(method))
164                     {
165                         var value = this._Methods[method](parameters.Split(',')).ToString();
166                         map.Add(tag, value);
167                     }
168                     else
169                     {
170                         map.Add(tag, defaultValue);
171                     }
172                 }
173             }
174             foreach (Match match in MethodFormatTagReg.Matches(this._Body))
175             {
176                 var tag = match.Groups[0].Value;
177                 var method = match.Groups[1].Value;
178                 var parameters = match.Groups[2].Value;
179                 var format = match.Groups[3].Value;
180                 var defaultValue = match.Groups[4].Value;
181                 if (!map.ContainsKey(tag))
182                 {
183                     if (this._Methods.ContainsKey(method))
184                     {
185                         var value = this._Methods[method](parameters.Split(','));
186                         map.Add(tag, String.Format("{0:" + format + "}", value));
187                     }
188                     else
189                     {
190                         map.Add(tag, defaultValue);
191                     }
192                 }
193             }
194             foreach (Match match in MethodNotDefaultTagReg.Matches(this._Body))
195             {
196                 var tag = match.Groups[0].Value;
197                 var method = match.Groups[1].Value;
198                 var parameters = match.Groups[2].Value;
199                 if (!map.ContainsKey(tag))
200                 {
201                     if (this._Methods.ContainsKey(method))
202                     {
203                         var value = this._Methods[method](parameters.Split(',')).ToString();
204                         map.Add(tag, value);
205                     }
206                     else
207                     {
208                         map.Add(tag, String.Empty);
209                     }
210                 }
211             }
212             foreach (Match match in MethodFormatNotDefaultTagReg.Matches(this._Body)) // .Matches(this._Body))
213             {
214                 var tag = match.Groups[0].Value;
215                 var method = match.Groups[1].Value;
216                 var parameters = match.Groups[2].Value;
217                 var format = match.Groups[3].Value;
218                 var defaultValue = match.Groups[4].Value;
219                 if (!map.ContainsKey(tag))
220                 {
221                     if (this._Methods.ContainsKey(method))
222                     {
223                         var value = this._Methods[method](parameters.Split(','));
224                         map.Add(tag, String.Format("{0:" + format + "}", value));
225                     }
226                     else
227                     {
228                         map.Add(tag, defaultValue);
229                     }
230                 }
231             }
232             foreach (var i in map)
233             {
234                 this.template.Replace(i.Key, i.Value);//替换模板内容
235             }
236         }
237         /// <summary>
238         /// 保存处理结果
239         /// </summary>
240         /// <param name="path"></param>
241         public void SaveAs(String path)
242         {
243             this.SaveAs(path, Encoding.UTF8);
244         }
245         /// <summary>
246         /// 保存处理结果并制定编码方式
247         /// </summary>
248         /// <param name="path"></param>
249         /// <param name="encoding"></param>
250         public void SaveAs(String path, Encoding encoding)
251         {
252             if (this.template == null) throw new Exception("还未载入模板!");
253             using (var sw = new StreamWriter(path, false, encoding))
254             {
255                 sw.Write(this.template.ToString());
256             }
257         }
258         public override string ToString()
259         {
260             return this.template == null ? this._Body : this.template.ToString();
261         }
262     }
263 }
原文地址:https://www.cnblogs.com/Soar1991/p/2654851.html