[FreeMarker 2.3.20] Part I 關於模版設計的介紹 ~值和類型~ 類型

簡介


FreeMarker 中支持的類型有這些:

  • Scalars :
    • String
    • Number
    • Boolean
    • Date
  • 容器:
    • Hash
    • Sequence
    • Collection
  • 子程序 (Subroutines) :
    • 方法和函數
    • 用戶自定義指令 (directives)
  • 雜項 (Miscellaneous) / 很少使用:
    • Node


Scalars


這些在職類型中是比較基礎、簡單的,包括:

  • String :簡單的文本。如果你不想用來自 data-model 中的變量,而是直接將字符串直接插入到模板中,那麼就把那些文本放到引號中即可,比如,"green.mouse" or  "mouse(更多的語法細節可以在後邊的章節中看到)
  • Number :說一件商品的價格。無論是整數 (whole number) 或非整數 (non-whole number),他們之間是沒有區別的,在 FreeMarker 中只有一種數據類型就是 number. 比如,3/2只會是1.5,而不會出現1,就像是使用計算器一樣。當想要在模板中插入數值類型時,那麼你就要這樣寫了:150 or -90.05 or 0.001 (更多關於語法方面的細節將會在後邊章節介紹)
  • Boolean : 一個 boolean 類型的值代表了一個邏輯 true or false (yes or no). 比如說,一個用戶是否有登陸。最典型的就是在 if 的條件部分使用 booleans,如, <#if loggedIn > .. </#if>or<#if price == 0> .. </#if>; 在後一個例子中 price == 0 的結果就是 boolean 類型的。在模板文件中你可以用保留字 trueorfalse 來指定 boolean 值。
  • Date : 存儲日期/時間相關的數據。它有三種變種:
    • 以天爲精確值的類型 (通常就是用日期 (date)來表示),比如 2003年4月4日
    • 一天的時間 time (沒有日期部分),比如說 10:19:18 PM, 這種類型的數據是一毫秒爲精度的
    • date-time (有時也會稱爲"time stamp") ,比如說 2003年4月4日, 10:19:18 PM. 同樣一天的時間那部分仍然是以毫秒爲單位的

不幸的是,由於 Java 平臺的限制,有時 FreeMarker 無法決定一個 date 類型的數據無法決定會使用哪一部分 (可能是 date-time or time, etc.) 對於這個問題的解決方案是一個高級主題,會在後續的章節中討論。


需要記住的是 FreeMarker 把 strings, numbers, booleans 分別對待,因此 "150"150是完全不同的。一個數類型持有數值, 一個布爾類型持有邏輯 true or false。 一個 string 類型持有任意的字符序列集合。


容器


容器這些值的主要目的是存儲別的變量;他們只是容器。那些被持有的變量通常就是指子變量。容器的類型有以下幾類:

  • Hash :它的每一個字變量都一個與其關聯的唯一的查詢名稱。它的名稱是一個無約束的字符串。在 hash 裏邊的變量是沒有定義一個先後順序的。因此,就沒有第一個子變量,第二個子變量,等等,這些說法。這些子變量只能夠通過名稱來訪問。
  • Sequence : 對應其每一個子變量都有一個關聯的數,下標。第一個子變量與 0 相關聯,第二個和 1 關聯,以此類推。它的子變量是有序的。這些數通常被稱爲子變量的索引,下標。通常序列中值的存儲是比較緊湊的,比如說,一般直到最後一個子變量的下標都是關聯着一個子變量的,但是這個並不是嚴格要求的,而且子變量的值也並不需要是一樣的。
  • Collection : 從一個模板作者的角度來看,是一個嚴格的序列,你不能訪問它的大小,也不能通過下標來遍歷子變量,但是它們仍然是可以通過 list 指令將其列出來。


要注意的是因爲一個值可能會擁有多種類型,它可能同時是一個 hash 類型和一個 sequence類型,也就是說它的值支持以下標爲基礎的訪問和以名稱爲依據的訪問。但是呢,還是有個例外的就是,一個容器類型只可能是序列或是集合,是不可能同時都屬於。


由於存儲在 hashes, sequences, collections 中的值可以是任何值,因此,也就有可能是一個 hash, sequence, collection 類型的值。在這中存儲方式下你就能夠建立任意深度的存儲結構。


data-model 本身 (準確的說是 root ) 是一 hash 類型。


子程序


方法和函數


一個變量的值是用來計算其它值的方法或函數,那麼計算出來的值會被所給的參數所影響。


對程序員說的話 (for programmer types): 對於面向過程的程序語言來說,方法/函數是最經典的值。這意味着方法/函數可能是參數也可能是別的方法/函數的值,你可以將他們賦值給變量,等等。


假設程序將可以用來計算平均值的方法變量 avg 放入了 data-model,當你訪問avg時,附帶了參數 3 和 5 ,那麼你將會得到值 4.


關於方法的使用會在後邊進行解釋,不過下邊這個例子大概能幫助理解什麼是方法:

The average of 3 and 5 is: ${avg(3, 5)}
The average of 6 and 10 and 20 is: ${avg(6, 10, 20)}
The average of the price of a python and an elephant is:
${avg(animals.python.price, animals.elephant.price)}  

這會有如下輸出:

The average of 3 and 5 is: 4
The average of 6 and 10 and 20 is: 12
The average of the price of a python and an elephant is:
4999.5  

那麼方法和函數之間有什麼區別呢?就如模板作者所考慮的,沒有。當然也並不是沒有點差別,因爲方法一般是來自 data-model的 (它們主要是反映了 Java 對象的方法),而函數時定義在模板裏邊的 (用函數指令定義的——一個高級主題),不過兩者的使用方法是相同的。


自定義指令


這種類型的值可以被用作用戶自定義指令 (換句話說就是指 FreeMarker tag)。一個自定義指令是一個子程序,有點像可重複使用的模板片段。不過這個是一個高級主題,我們同樣會在後邊其自己的章節中介紹。

對程序員說的話 (for programmer types): 自定義指令 (比如宏,macros),也是經典的值類型,就如同方法和函數一樣的經典類型。

這裏只是對自定義指令有個瞭解 (所以如果你不明白的可以先忽略掉這部分),假設我們有個變量 box, 它是一個用來輸出漂亮且帶有標題條和信息的 HTML 消息框的自定義指令。box變量可以像下邊的例子一樣在模板中使用:

<@box title="Attention!">
  Too much copy-pasting may leads to
  maintenance headaches.
</@box>  

方法和函數 VS 自定義指令


這個也是對高級用戶而言的 (如果你不明白也可以忽略掉這部分)。 當你面對要實現某個功能時,在方法/函數和自定義指令間的選擇是比較困難的。一般規則 (the rule of thumb):當是以下情況的時候使用自定義指令來代替方法/函數:

  • ...輸出(返回值) 是標記(HTML, XML, etc). 主要的原因是函數的結果是那些能夠自動進行 XML 轉義(XML-escaping)[主要是由於 ${...} 的緣故]的值 (subject),但是自定義指令卻不會 (這個主要是由於<@...>, 它的值被認爲是標記了,因此就不會被轉義)。
  • ...它的作用是產生 side-effect (比如說更改一個全局變量或一個靜態變量) 而不是返回值。比如說,它的目的是在服務器 log 中加入一對鍵值。(事實上自定義指頂也不會有返回值的,不過某些反饋通過設置非本地變量仍然是可能的)
  • ...它會產生流控制 (比如像是 list, if 指令所做的). 這種功能對於方法/函數是不能實現的。

不識別 FreeMarker 的 Java 對象的方法在模板裏邊一般是以方法出現的,而不會在意它是 Java 方法這個事。 (The Java methods of FreeMarker-unaware Java objects are normally visible as methods in templates, regardless of the nature of the Java methods, 這個感覺比較難翻譯,求賜教:))也就是說,這個沒有選擇的餘地.


雜項


節點


在一個樹形結構中一個結點變量代表一個結點,它最多是被用在解析 XML 過程中,這也是個高級,特別的主題。


仍然,這裏我們爲高級用戶做一個總結:一個結點就如同序列一樣能夠存儲其他的節點,這些節點被稱作子結點。一個結點會存儲其容器結點的引用,這個節點被稱作父親結點。一個結點主要的信息就是它的拓撲信息,其他存儲下來的數據則是能夠有其他用途的,這樣的值可以有多種類型的。(這裏應該是指除了用來表示結點與結點之間的關聯信息外的其他信息,比如說權重什麼的。)比如一個值可能是一個結點和一個數,這個數剛好就代表負載。出去拓撲信息外,一個結點也可以附帶一些源信息:結點名稱、節點類型 (string),結點的命名空間 (string). 比如說在一個 XHTML 文檔中有個結點元素用 h1表示,那麼它的名字可以是"h1", 它的結點類型可以是 "element", 它的命名空間可能是"http://www.w3.org/1999/xhtml".當然這個就由 data-model 的設計者來決定這些元信息究竟是代表什麼意思以及它們是否會被是使用。關於便利拓撲結構和源信息的方法會在後邊的章節裏講到 (那麼現在不明白的話也沒關係)

發佈了13 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章