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

这个是为了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 }

你可能感兴趣的:(变量)