2009-11-16 76 views
1

我正在写一个ASP.NET/C#中的内容管理系统,该网站的模板是在html文件中定义的。我通过将参数传递给html文件。一个块以[并以结束]开头。有一些简单模板的示例:模板解析和反射

<html> 
<head> 
    <title>[Title]</title> 
    <meta name="description" content="[Description]" /> 
</head> 
<body> 
    <h1>[Headline]</h1> 
    <p>[Text]</p> 
</body> 
</html> 

现在,我有一个代表模板的类。对于例如模板类看起来是这样的:

public class MyTemplate 
{ 
    public string Title 
    { 
     get; 
     set; 
    } 

    public string Description 
    { 
     get; 
     set; 
    } 

    public string Headline 
    { 
     get; 
     set;   
    } 

    public string Text 
    { 
     get; 
     set;   
    } 
} 

类可能是一类,我写的,通过产生的Linq to SQL或只是任何类的类。

我创建了一个用属性值替换块的方法。我正在使用正则表达式来实现此目的:

public static string ParseTemplateFromObject(string input, object obj) 
    { 
     return Regex.Replace(input, @"\[(.*?)\]", new MatchEvaluator(delegate(Match match) 
     { 
      var blockName = match.Result("$1"); 

      return obj.GetType().GetProperties().SingleOrDefault(p => p.Name.Equals(blockName, StringComparison.OrdinalIgnoreCase)) 
       .GetValue(obj, null).ToString(); 

     }), RegexOptions.Multiline); 
    } 

...并且它正在工作。我使用GetProperties(),然后使用Linq代替GetProperty来防止区分大小写。但是现在我又遇到了另一个问题,那就是当我想在块中使用参数时。例如:我想创建一个垂直菜单。在系统菜单可垂直或水平:

[Menu Id=1, Direction="Vertical"] 

所以,我决定,而不是获取价值,从它的特性,这种类型的块的调用方法,并提取它的价值。例如:

public class MyTemplate 
{ 
    ... 
    public string Menu(int id, string direction) 
    { 
     string menu = ...; 
     return menu; 
    } 
} 

我伸出我的ParseTemplateFromObject来支持这一点:

public static string ParseTemplateFromObject(string input, object obj) 
    { 
     return Regex.Replace(input, @"\[(.*?)\]", new MatchEvaluator(delegate(Match match) 
     { 
      var blockName = match.Result("$1"); 

      var m = Regex.Match(blockName, "(?<Name>\\w+)=((?<Value>\\w+)|\"(?<Value>([^\"]*))\")"); 

      if (m.Captures.Count > 0) 
      { 
       var method = obj.GetType().GetMethods().Single(p => p.Name.Equals(blockName.Substring(0, blockName.IndexOf(' ')) 
        , StringComparison.OrdinalIgnoreCase)); 

       var methodParameters = method.GetParameters(); 
       var parameters = new object[methodParameters.Length]; 

       while (m.Success) 
       { 
        var name = m.Groups["Name"].Value; 
        var value = m.Groups["Value"].Value; 

        var methodParameter = methodParameters.Single(p => p.Name.ToLower() == name.ToLower()); 
        parameters[methodParameter.Position] = 
         Convert.ChangeType(value, methodParameter.ParameterType); 

        m = m.NextMatch(); 
       } 

       return method.Invoke(obj, parameters).ToString(); 
      } 
      else 
      { 
       return obj.GetType().GetProperties().SingleOrDefault(p => p.Name.Equals(blockName, StringComparison.OrdinalIgnoreCase)) 
        .GetValue(obj, null).ToString(); 

      } 
     }), RegexOptions.Multiline); 
    } 
} 

它的工作,但我正在寻找办法,使之更加有效。我不知道这是否是正确的实施方式?

谢谢。

回答

0

您是否考虑过在实际模板中管理令牌的样式,而不是从代码中对样式进行样式设置?例如,你有一个方向属性,可能是我建议的方法的理想候选人。这样你可以保持令牌的解析非常简单。

1

也许使用ASP.Net提供的原生模板?即,使用标准的.aspx页面定义您的模板,然后使用Server.Execute方法来捕获这些页面生成的输出。您将能够使用服务器代码块(<%=%>)或者1.)插入由后面的代码公开的变量,或者2.)在后面的代码中执行方法。将为您节省更新解析代码的工作量,并提供广泛认可的模板格式。

+0

尝试从控制台应用程序执行时,这会变得很糟糕 – Shawn 2011-02-10 21:27:45