模板引擎StringTemplate

來源:互聯網
上載者:User
文章目錄
  • 2.1,間接屬性(indirect property names)
  • 2.2,多值屬性(multi-valued attribute)
  • 2.3 屬性的呈現(attribute render)
  • 3.1 從檔案中載入模板
  • 3.2 命名模板(Group Files)
  • 4.1 匿名子模板(anonymous subtemplate)
  • 4.2 條件包含子模板
  • 5.1 未涉及的部分
  • 5.2 連結
1,特點

1,強制Model和View的分離,也就是View負責呈現,不能修改Model。同時View中不用來包括任何商務邏輯,詳見作者的論文(中文,英文)。

2,Lazy-Evaluation,所有的Attribute直到st.ToString()調用時才evaluate.這樣的好處是setAttribute是Order  Independent。

3,Recursive enable。

2,屬性(attribute)

StringTemplate文法有兩種組成元素,一種是屬性(attribute),另一種是一般字元(plain text)。在$…$中包圍的是屬性,其餘的都是一般字元。比如:

select $column$ from $table$ 

其中紅色部分的$column$和$table$都是屬性。在模板引擎呈現,即調用st.ToString()時,屬性被實際值替換,而一般字元原封不動地輸出。

我們可以通過下面的方式來向模板“填充”(push)屬性:

StringTemplate st = new StringTemplate("select $column$ from $table")st.SetAttribute("column", "uid");st.SetAttribute("table", "users");Console.WriteLine(st.ToString());  //output: select uid from users

屬性的填充方式很簡單,就是調用attribute.ToString()方法的結果,如果attribute是null不會拋出異常,而是輸出Null 字元串。

在.NET實現中attribute可以引用.net對象欄位或屬性(不區分大小寫),如果欄位和屬性同名則屬性優先。attribute也可以是Dictionary或HashTable的Key,這樣會找到該Key對應的值,然後在調用這個值的ToString()方法。樣本:

class Query{    public string column = "a";    public string table = "t";    public string Table { get { return "T"; } }}StringTemplate st = new StringTemplate("select $q.column$ from $q.TABLE$");Query q = new Query();st.SetAttribute("q",q);Console.WriteLine(st.ToString());  //output: select a from T

2.1,間接屬性(indirect property names)

你可以通過下面的attribute.(anotherAttr)文法來引用間接屬性:

StringTemplate st1 = new StringTemplate("$q.(property)$"); //property是間接屬性,也是一個attribute Query q = new Query();st1.SetAttribute("q", q);st1.SetAttribute("property", "table");Console.WriteLine(st1.ToString());  //output: t

有些StringTemplate的保留字(reserved keyword),是不能作為屬性的:

如果attribute中的property和這些保留字重複了,StringTemplate就會報錯,解決方案是使用間接屬性:

class Query{    public string first = "NumberOne";}StringTemplate st = new StringTemplate("select $q.(IndirectAttr)$");Query q = new Query();st.SetAttribute("q", q);st.SetAttribute("IndirectAttr", "first");Console.WriteLine(st.ToString());  //select NumberOne//或者直接用Literal String: select $q.("first")$
2.2,多值屬性(multi-valued attribute)

所謂多值屬性其實就是像數組一樣的可迭代對象。多值屬性通常有兩種輸出方式:1,類似於String.Join()的拼接。2,迭代。

A)拼接
StringTemplate st = new StringTemplate("select $columns$ from users");List<string> columns = new List<string>();columns.Add("a");columns.Add("b");st.SetAttribute("columns", columns);Console.WriteLine(st.ToString());  //output: select ab from usersStringTemplate st1 = new StringTemplate("select $columns; separator=\",\"$ from users");            st1.SetAttribute("columns", "a");st1.SetAttribute("columns", "b");    //此時columns變成multi-valued,作者講其實SetAttribute應該叫做AddAtribute才對,對於同名attribute他不是替換而是添加Console.WriteLine(st1.ToString());  //output: select a,b from users StringTemplate st2 = new StringTemplate("select $columns; separator=dilimiter$ from users");st2.SetAttribute("columns", "a");st2.SetAttribute("columns", "b");st2.SetAttribute("dilimiter", ","); //separator也可以使exprConsole.WriteLine(st2.ToString());  //output: select a,b from users 
B)迭代
StringTemplate st = new StringTemplate("select $columns:{<i>$it$</i>}$ from users");  //迭代{...}中的anonymous template,並以自動填滿it為當前元素st.SetAttribute("columns", "a");st.SetAttribute("columns", "b");  Console.WriteLine(st.ToString());  //output: select  <i>a</i>  <i>b</i>  from usersStringTemplate st1 = new StringTemplate("select $columns:{col|<i>$col$</i>}$ from users"); //自動填滿col為當前元素,同時it還是要填充的            st1.SetAttribute("columns", "a");st1.SetAttribute("columns", "b");Console.WriteLine(st1.ToString());  //output: select  <i>a</i>  <i>b</i>  from users
C)函數

StringTemplate裡面內建了一些函數用來操作multi-valued attributes,把他當做Lisp中的List一樣操作,通過一些組合能實現牛逼功能。

StringTemplate st = new StringTemplate("[$first(columns)$] [$last(columns)$] [$first(rest(columns))$]");  st.SetAttribute("columns", "a");st.SetAttribute("columns", "b");st.SetAttribute("columns", "c");Console.WriteLine(st.ToString());  //output: [a] [c] [b]
2.3 屬性的呈現(attribute render)

我們知道屬性最後在模板中的呈現都是調用屬性的ToString()方法,但是我們有時候想在模板呈現的時候改變某個屬性的呈現,那麼我們該怎麼做呢?試想一下,我們對於DateTime,我們只想顯示日期,而不想顯示具體的時間,那我們怎麼處理呢?一個辦法是建立一個類型,然後重寫ToString方法,但這樣改動有點大,因為你需要在Model中所有用到這個DateTime的地方都要做類型轉換。

StringTemplate提供的一個介面IAttributeRenderer用來做這種工作,該介面只負責一個類型的呈現,我們可以向一個模板註冊這個呈現方式:

class DateTimeRender:IAttributeRenderer{    public string ToString(object o)    {        DateTime dt = (DateTime)o;        return dt.ToString("yyyy.MM.dd");    }}StringTemplate st = new StringTemplate("$d$");st.SetAttribute("d", DateTime.Now);Console.WriteLine(st.ToString());st.RegisterAttributeRenderer(typeof(DateTime), new DateTimeRender());  //register the attribute render for DateTimeConsole.WriteLine(st.ToString());

 

3,StringTemplateGroup3.1 從檔案中載入模板

模板時常是寫在檔案中的,比如一些作為html頁面的模板。如果想從檔案中裝載模板我們可以使用StringTemplateGroup:

string rootDirectoryOfTemplate = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Query");StringTemplateGroup group = new StringTemplateGroup("queryTemplate",rootDirectoryOfTemplate);StringTemplate st1 =  group.GetInstanceOf("query");   //load  ROOT_PATH/query.stst1.SetAttribute("func","sysdate()");Console.WriteLine(st1.ToString());StringTemplate st2 = group.GetInstanceOf("\\sub\\query");  //load  ROOT_PATH/sub/query.stst2.SetAttribute("func", "sysdate()");Console.WriteLine(st2.ToString());
3.2 命名模板(Group Files)

如果想模組化模板,一個方式是使用單獨的檔案。但是如果模板很短小這樣會產生很多檔案,StringTemplate提供了Group Files用來定義短小的模板模組,你可以通過給通過名稱來引用定義好的模板模組。命名模板的定義規則是:

templateName(arg1, arg2, ..., argN) ::= "single-line template"ortemplateName(arg1, arg2, ..., argN) ::= <<multi-line template>>ortemplateName(arg1, arg2, ..., argN) ::= <%multi-line template that ignores indentation and newlines%>

命名模板還提供了模板參數,你可以通過SetAttribute來設定模板的參數。樣本:

string groupDef = @"group mygroup;vardef(type,name) ::= ""<type> <name>;""method(type,name,args) ::= <<<type> <name>(<args; separator="","">) {  <statements; separator=""\n"">}>>";StringTemplateGroup stg = new StringTemplateGroup(new StringReader(groupDef));var vardef = stg.GetInstanceOf("vardef");vardef.SetAttribute("type", "int");vardef.SetAttribute("name", "sum");Console.WriteLine(vardef.ToString());  //output: int sum;

 

4,子模板(subtemplate)4.1 匿名子模板(anonymous subtemplate)

我們可以對屬性或多值屬性應用匿名子模板,文法我們在多值屬性的迭代中已經見識了:$attr:{ <anonymous template> }$。匿名模板還可以嵌套:

StringTemplate st = new StringTemplate("$x:{<b>$it$</b>}:{<li>$it$</li>}; separator=\"\n\"$");st.SetAttribute("x", 1);st.SetAttribute("x", 2);st.SetAttribute("x", 3);Console.WriteLine(st.ToString());

這樣我們就可以對每個元素先應用<b>,然後在應用<li>。

對於多值屬性,我們還可以對每個屬性交替地應用不同的子模板,文法跟上面的就跟上面應用多個匿名模板很類似,將“:”變成“,”:

StringTemplate st = new StringTemplate("$x:{<red>$it$</red>},{<blue>$it$</blue>}; separator=\"\n\"$");st.SetAttribute("x", 1);st.SetAttribute("x", "jatsz");st.SetAttribute("x", 2);st.SetAttribute("x","git");Console.WriteLine(st.ToString());

 

4.2 條件包含子模板
$if(x)$...$elseif(y)$...$elseif(z)$...$else$...$endif$

除了false, null, empty(list,hastable)視作false以外,其他的值都被視作true。我們可以通過條件運算式來包含(include)不同的子模板:

我們共有三個模板檔案,分別位於Views目錄下的index.st, sub/login.st, sub/logout.st,檔案的內容如下:

===index.st$if(loggedin)$   $sub/logout(lnk=linkUrl)$$else$   $sub/login(lnk=linkUrl)$$endif$===sub/login.st<a href="$lnk$">Please click to login</a>==sub/logout.st<a href="$lnk$">Please click to logout</a>

我們的程式碼如下:

StringTemplateGroup stg = new StringTemplateGroup("index", AppDomain.CurrentDomain.BaseDirectory + "views");var stIndex = stg.GetInstanceOf("index");stIndex.SetAttribute("loggedin", true);stIndex.SetAttribute("linkUrl","http://example.com/logout");Console.WriteLine(stIndex.ToString());stIndex.Reset();  //or stIndex.RemoveAttribute("loggedin");stIndex.SetAttribute("loggedin", false);stIndex.SetAttribute("linkUrl", "http://example.com/login");Console.WriteLine(stIndex.ToString());

 

5,雜項5.1 未涉及的部分
  • Group Interface
  • Template Inheritance
5.2 連結

本文樣本使用的是StringTemplate v3版。

http://www.stringtemplate.org/

http://www.antlr.org/wiki/display/ST/StringTemplate+3.0+Printable+Documentation#StringTemplate30PrintableDocumentation-6Groupinterfaces

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.