2009-11-16 126 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