<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Vincent.Chan‘s Blog

    常用鏈接

    統(tǒng)計(jì)

    積分與排名

    網(wǎng)站

    最新評論

    Web 顯示層技術(shù)評估

    Web 顯示層技術(shù)評估

    名詞界定

    顯示層的意思就是 Presentation Layer ,也翻譯成表現(xiàn)層、展現(xiàn)層、展示層。

    本文討論的范圍只包括采用 HTML Template 的顯示層技術(shù),不包括 Echo GWT(google web toolkit) 等根據(jù)代碼產(chǎn)生 HTML 的工具。

    本文主要討論 Server Side ( 針對 Java Language) 的顯示層技術(shù),然后進(jìn)一步討論 Browser Side Ajax )的顯示層技術(shù)(一個典型的 Ajax 應(yīng)用也分為 Model, View, Controller – Data, HTML/CSS, JavaScript )。注意,本文關(guān)于 Ajax 的討論只有很少一部分,因?yàn)槲也簧瞄L這個領(lǐng)域。只是一個順便的擴(kuò)展比較。

    一個很有趣的現(xiàn)象。 Server Side Browser Side 的顯示層技術(shù)格局恰好相反。 Server Side Scripted Template 技術(shù)比較多,比較流行;而 Browser Side HTML DOM Manipulation 技術(shù)、 HTML View Model 技術(shù)比較多,比較流行。

    本文會提到一些技術(shù)、或者框架的名稱,但只局限于討論該技術(shù)、該框架的顯示相關(guān)部分的內(nèi)容,而不涉及評估其他方面的特性。比如,本文不討論 Link URL Generation, Action URL Generation Button Script Generation 這些頁面組件事件機(jī)制的方面。

    本文是一個深度討論。不討論簡單的替換個字符串的 Hello World 案例,而是窮盡各種顯示層技術(shù)的能力極限,探索它們在復(fù)雜布局(動態(tài) include 等)、復(fù)雜顯示邏輯(條件、循環(huán)、嵌套、遞歸)等方面的功能。

    ?

    對了,(考慮到 Site Mesh Struts Tiles Taglib 等技術(shù)廣泛的群眾基礎(chǔ)),可能需要專門提一下,本文將不討論 Site Mesh Tiles 等布局技術(shù)( named include )。

    Site Mesh 相當(dāng)于 XSL 的一個簡化版本,只保留了根據(jù) (name->file) 配置替換某個 HTML Node 的能力,其余的如 Tiles ,也大致如此,由于多了一個 (name->file) 配置文件,比直接 include file 高級了不少。

    由于使用簡單(功能自然也簡單),這類技術(shù)獲得了廣大群眾的支持,呼聲很高。本文為忽略了這一類技術(shù)感到很遺憾。

    ?

    另外需要指出的是,并不存在一個十全十美的方案。

    工作總是要做的,不是在 Template 里面做,就是在 Java Code 里面做,總之,總要找個地方做這個工作,天下沒有免費(fèi)的午餐。一方面特性增強(qiáng)了,自然影響到另一方面。

    正如,代碼的耦合實(shí)際上并不能完全消除,我們只能把這些耦合點(diǎn)移動來移動去,今天我看這里不舒服了,把耦合點(diǎn)移動到另一個地方;明天另一個人看到那里不舒服了,又移動回來。而且各自都能說出一大堆道理。

    所以,需要注意的是,并不存在一個絕對的優(yōu)勝方案。本文只是列出各種技術(shù)指標(biāo)的參考評估數(shù)據(jù),以便幫助讀者根據(jù)自己的需要,做出比較準(zhǔn)確的評估。(是的,準(zhǔn)確的量化評估,而不是廣告語或者口號)

    理論模型

    一個顯示的整個過程,如果用一個函數(shù)來描述,那么看起來大概是這樣。

    F(Data, Template, Display Logic) => Result HTML

    其中的 Display Logic ,就是顯示邏輯。 Display Logic 操作 Data Template ,產(chǎn)生最終結(jié)果。

    這個 Display Logic 可能以各種形式出現(xiàn)在任何地點(diǎn)。

    比如,可能作為 Server Side Script 存在于 Template 里面,把 Data 取出來輸出;也可能存在于后臺 Java 里面,根據(jù) Data 操作 Template Node

    針對前一種情況,函數(shù)公式表達(dá)是: Template Script (Data) => Result

    針對后一種情況,函數(shù)公式表達(dá)是: Logic (Data, Template) => Result

    ?

    這個模型可以作為顯示層技術(shù)的劃分標(biāo)準(zhǔn)。

    (1) Scripted Template

    HTML Server Side Script 混雜在一起的顯示層技術(shù)。

    包括 JSP, Velocity, Freemarker, Taglib, Tapestry, XSL 等。

    肯定有人對這個劃分有異議。 XSL 里面有 choose, if, for 。這還好說。尤其是對 Taglib, Tapestry ,反映可能更加強(qiáng)烈。我似乎已經(jīng)看到, Taglib or Tapestry Fans 已經(jīng)跳起來了,高叫著, Taglib or Tapestry 明明是組件技術(shù),組件技術(shù),組件技術(shù) ….

    這里我還是表示很遺憾。在目前定義的這個狹義模型下,任何 Template 中包含 Logic 的顯示技術(shù)都劃為 Script 這一類。而且在表示邏輯的時候,這類組件技術(shù)表現(xiàn)的更加突出一些。

    比如 Tapestry <foreach> <if><if-not> <let><set> 等邏輯標(biāo)簽。尤其是這個 if not ,是專門多出來的一個條件語句,一般的編程語言里面都不具備這樣的對應(yīng)語法。當(dāng)然, Tapestry 并不專美, Taglib Logic Tag 也是如此。

    ?

    (2)Template Manipulation

    Java 代碼直接操作 Template (比如, HTML DOM )產(chǎn)生結(jié)果的顯示層技術(shù)。

    包括 XMLC, JDynamiTe, Rife 等。

    大家對這一類技術(shù)可能不是很熟悉。后面進(jìn)行特性分析的時候,會舉出一些典型的例子,來說明各自的用法。

    一個很有意思的現(xiàn)象是,在 Browser Side Ajax ),由于 Java Script 操作 HTML DOM 非常方便,這類顯示技術(shù)非常普遍。相反的, Scripted Template 的技術(shù),在 Browser Side 卻不多見。后面討論 Browser side 的時候,會列舉一些典型的例子。

    ?

    (3) Model Match

    Java 代碼負(fù)責(zé)提供符合顯示層要求的 Data Model ,顯示層框架本身把 Data Model Template 進(jìn)行匹配,產(chǎn)生結(jié)果。

    包括 Wicket, Fastm, DOMPlus, 等。

    Wicket 如同 Swing 的用法,需要為不同的 UI Component 提供不同的 View Model ,比如 Table, List, Label 等。 Fastm, DOMPlus 支持 POJO ,但同樣需要滿足一些框架特有的約定。

    也許有人會說,某些 Display Tag Lib, Tapestry Components 可能也需要 Java Code 提供特殊的 View Data Model

    不過,需要特殊的 View Data Model ,并不是一個好的特性,意味著不支持 POJO

    數(shù)據(jù)尋址

    在正式開始之前,先說明一下數(shù)據(jù)尋址的概念。

    數(shù)據(jù)尋址,意思是數(shù)據(jù)訪問、屬性獲取等。主要包括兩類風(fēng)格。

    (1) OGNL Style

    http://www.ognl.org/

    OGNL (Object Graph Navigation Language) 如此著名和深入人心,以至于我在這里用 OGNL Style 代表 Java Bean 屬性尋址的方式。

    比如, a.b[1].c.d[2].name

    另一類當(dāng)然是

    (2)XPath Style

    比如, a/b[1]/c/[d]/@name

    XPath Style 主要應(yīng)用在 XSL 中。

    一個 JXPath 項(xiàng)目能夠按照 XPath 的方式訪問 Java Bean 屬性。

    http://jakarta.apache.org/commons/jxpath/

    ?

    簡單的尋址, OGNL XPath 能夠?qū)?yīng)起來。但是, OGNL XPath 都各自是功能很強(qiáng)大的語言,復(fù)雜的用法并不能對應(yīng)。

    評估指標(biāo)

    下面列出一系列比較詳細(xì)的、能夠落到實(shí)處的、能夠客觀量化的、可操作的評估硬指標(biāo)。

    排名不分先后。大家可以參考各自關(guān)心的選項(xiàng)。

    雖然下面主要針對的都是 Java Web 顯示技術(shù),但這些指標(biāo)同樣適用于其他語言的 Web 顯示技術(shù)。

    評分采取 10 分作為滿分。

    (1) Host Language Consistency 宿主語言一致性

    Server Side Template Script Server Host Language 是同一種語言。這應(yīng)該是專門針對 JSP 的優(yōu)勢來說了。 JSP 能夠獲得 10 分。

    另外, XSL 也是。 XSL 本是也是 XML 格式。也能夠獲得 10 分。

    其他的 Template Script ,如 taglib,tapestry 只能獲得 0 分。

    freemarker, velocity 由于具有一定的動態(tài)解釋的方便特性,可以獲得 2 分。

    至于在 Java Code 里面操作 Template 或者提供匹配數(shù)據(jù)的那些技術(shù),由于 Template 中不存在 Script Logic ,能夠獲得 5 分。

    大家可能不太注意這個特性。但是這個特性還是有一些意義的。其他的如 ASP.net ,還有動態(tài)語言, Ruby, Python, PHP, Perl 等,都是 Template Script 和宿主語言一致。

    這能夠一定程度上降低學(xué)習(xí)成本。尤其是宿主語言比較適合作為 Script 的情況下。

    ?

    (2)Template Purity 模板純凈度

    這主要是指 Template 里面沒有 Script Logic 代碼污染。

    這方面,所有的 Scripted Template 技術(shù)都只能獲得 0 分。

    XMLC 能夠獲得 10 分,只利用 HTML 本身的 Attribute ,沒有增加任何自定義 DOM Attribute

    Wicket, DOMPlus 能夠獲得 9 分,它們增加了一部分自定義 DOM Attribute

    JDynamiTe, Fastm 能夠獲得 7 分,它們采用了 XML Comment 作為自定義結(jié)構(gòu)標(biāo)簽。

    Rife 也能夠獲得 3 -- 7 分,具體看它采用什么標(biāo)簽格式。

    (3)Template Tidiness 模板整潔度

    主要是指 Template 的格式是否整齊規(guī)范。 Taglib,?XSL 無疑是勝利者,本身就是 XML 格式,通用的 XML Parser 就可以解析它們,比較容易在 IDE Plugin 中處理。

    XMLC, Taglib, XSL 能夠獲得 10 分。

    Tapestry, Wicket, DOMPlus 也能夠獲得 10 分,同樣是 XML 格式。

    JDynamiTe, Fastm, Rife 能夠獲得 5 分。

    JSP, Velocity, Freemarker 只能獲得 0 分。

    (4) Replacement Flexibility 替換靈活度

    主要是指能否自由替換 Template 里面的任何一塊文本。不用考慮 DOM Node

    JSP, Freemarker, Velocity, Rife, JDynamicTe, Fastm 無疑是勝利者,毫無限制,能夠獲得 10 分。

    Taglib, XSL, Tapestry, Wicket, XMLC, DOMPlus 都或多或少受到 DOM Node 的限制(解析的最小單位是 XML Node ),能夠獲得 6 分。

    (5)WYIWYG 所見即所得

    Template 能夠在 Browser 里面直接大致正確顯示,設(shè)計(jì)人員友好。

    XMLC, DOMPlus 得分 10

    Wicket 得分 9

    JDynamiTe, Fastm, (Rife 根據(jù)情況 ) 得分 8

    Tapestry 得分 7 HTML 畢竟夾雜了 Logic Tag

    JSP, Freemarker, Velocity, Taglib, XSL 得分 0

    ?

    Freemarker, Velocity 屬于按行解析,有可能采取如下手段,把語句包含在 XML Comment 里面,進(jìn)行顯示友好的處理。這種情況下得分 5

    <!--

    #if ….

    -->

    ?

    由于 Taglib XML 規(guī)范格式,使得某些 IDE Plugin DreamWeaver Plugin 能夠顯示 HTML Display Taglib 。如果是對于此類 Plugin 來說, Taglib 的所見即所得分?jǐn)?shù)可以是 0-- 5 分。類似于 Tapestry ,仍然是 Logic Tag 影響了最終得分。

    (6)Action Code Purity 用戶代碼純凈度

    主要是指用戶提供顯示數(shù)據(jù)的后臺 Java 代碼的純凈度,是否免除了 HTML ,或者 Template 操作的污染。

    Servlet HTML 污染現(xiàn)象就非常嚴(yán)重。代碼里面夾雜了大量的 HTML Text 。分?jǐn)?shù)自然是 0

    JSP, Freemarker, Velocity 都能夠獲得 10 分。用戶后臺代碼十分純凈,不需要引入具體框架的代碼。任何一份 Action Code ,完全不用知道自己使用的是什么 Template ,這三種 Scripted Template 都能夠隨意替換。能夠獲得 10 分。 pojo

    Taglib 根據(jù)各種具體情況,能夠最高獲得 8 分。

    Fastm, DOMPlus 需要根據(jù)一定的約定,產(chǎn)生 POJO 數(shù)據(jù)。用戶 Action Code 同樣不需要引入具體的框架代碼,產(chǎn)生的這些數(shù)據(jù)同樣可以很容易地被其他 Template ,比如 JSP, Freemarker, Velocity 使用,能夠某種程度上替換 Template 。能夠獲得 6 分。

    Tapestry 需要在每份用戶 Action Code 里面引入 Template 框架的 Package 。只能獲得 4 分。

    Wicket 不僅需要在每份用戶 Action Code 里面引入框架的 Package ,還需要引入框架特殊的 View Data Model 數(shù)據(jù)類型,并且提供特殊類型的數(shù)據(jù)。只能獲得 2 分。

    XMLC, Rife, JDynamiTe 不僅需要在每份用戶 Action Code 里面引入框架的 Package ,而且需要大量的 Template 操作。只能獲得 0 分。

    ?

    (這項(xiàng)特性的比較,對于 Tapestry Wicket 來說是不公平的。因?yàn)樗鼈兊目蚣芫桶?/span> Template 本身。 Action 里面引入框架 Package 是很正常的。而且這些框架同樣可以外接其余的 Template ,只是原來的編程模型,需要做一些更改。這里只是對于單項(xiàng)比較就事論事。)

    (7) Infrastructure Code Purity 基架代碼純凈度

    這里是指框架的內(nèi)部實(shí)現(xiàn)代碼里面是否夾雜了 HTML Text 污染。這也意味著如果用戶需要擴(kuò)展頁面 UI 組件,是否也需要在代碼里面夾雜 HTML Text

    HTML Taglib, Wicket, Tapestry 的框架實(shí)現(xiàn)代碼里面包含了很多 HTML Text 輸出語句。用戶需要自定義擴(kuò)展頁面 UI 組件,也需要在代碼里面夾雜 HTML Text 。所以,得分只能是 0

    JSP, Freemarker, Velocity, XMLC, XSL, Rife, JDynamiTe, Fastm, DOMPlus 得分都是 10

    (8) 動態(tài) Include

    即運(yùn)行的時候,動態(tài)選擇 Include 另外的 Template 文件。

    JSP 文件里面的 @ include 屬于靜態(tài) Copy And Paste 技術(shù)。

    Jsp:include 命令是動態(tài) Include 相當(dāng)于

    <%?

    request.getRequestDispatcher(…).include(request, response);

    %>

    這才是動態(tài) Include 技術(shù)。

    ?

    Velocity, Freemarker #Parse 指令應(yīng)該也是動態(tài)解釋執(zhí)行的。也可以算是動態(tài) Include

    至于 XMLC, Rife, JDynamiTe 這類技術(shù)能夠隨意操作 Template Node ,動態(tài) Include 也是小菜一碟。

    Fastm, DOMPLus 同樣提供了操作 Template Node 的能力,而且為了避免這類 Template Manipulation 代碼污染,還提供了類似于 XSL Node Interceptor 的機(jī)制實(shí)現(xiàn)動態(tài) Include

    XSL Apply Imports Call Template 能夠動態(tài)引入并使用其他的 XSL

    ?

    所以, JSP, Freemarker, XMLC, Rife, JDynamiTe, Fastm, DOMPlus, XSL 的動態(tài) Include 方面的分?jǐn)?shù)都是 10

    其余的, Taglib, Wicket, Tapestry 得分為 0

    (9)Recursive Display of Tree Data 樹型數(shù)據(jù)的遞歸顯示

    遞歸顯示一個任意深度的樹型數(shù)據(jù),這是一個動態(tài) Include 基礎(chǔ)上的更高級的需求。可以說,不支持動態(tài) Include ,就不支持遞歸顯示。

    遞歸, XSL 無疑是天生贏家。 XSL Pattern Match 語法可以說就是為遞歸編寫的。

    其余的語法都是 Imperative Programming 。遞歸的前提是必須能夠定義一個方法,自己直接或者轉(zhuǎn)彎抹角的能夠調(diào)用到自己。

    對于 JSP, Velocity, Freemarker 這類沒頭沒尾的 Script 來說,屬于強(qiáng)人所難。

    Tapestry, Taglib, Wicket 比較牛,專門提供了 Tree Model

    XMLC, Rife, JDynamiTe 這些 Template Manipulator 高興了,可以在 Java 代碼里面任意根據(jù)數(shù)據(jù)任意操作 Template Node

    Fastm, DOMPlus 不僅可以在 Java 代碼里面任意操作,而且提供了類似于 XSL Pattern Match Node Interceptor 功能,不需要寫 Template Node 操作代碼,就可以實(shí)現(xiàn)遞歸。而且可以實(shí)現(xiàn) Data Iterator + Template Iterator 的匹配序列。

    ?

    遞歸方面,得分如下。

    XSL, XMLC, Rife, JDynamiTe, Fastm, DOMPlus 得分 10

    Tapestry, Taglib, Wicket 能夠顯示特定的 Tree Model 。得分 4

    其余的,得分 0 。只能通過 Java 代碼里面夾雜一堆的 HTML Text ,然后整體輸出給 Scripted Template 來實(shí)現(xiàn)。

    (10) Space Efficiency 空間效率

    基于 Template Manipulation 的技術(shù)都有空間效率問題。用戶同時訪問同一個 Page 的時候,內(nèi)存中存在多個副本。 XMLC 的問題可能最重。因?yàn)?/span> XML DOM 結(jié)構(gòu)很重。

    JDynamicTe, Rife 直接在一個 Template Node 上操作,如果有多個用戶同時訪問同一個 Page 。那么同一份 Template Node 就會在內(nèi)存中 Duplicate 多份。

    ?

    空間效率方面得分情況

    XMLC 得分 0 JDynamicTe, Rife 得分 3 。如果靜態(tài)文本節(jié)點(diǎn)作了優(yōu)化,分?jǐn)?shù)可能更高。

    Taglib 由于編譯的結(jié)果非常臃腫, Tag 之間的信息交流非常困難。分?jǐn)?shù)為 6

    DOMPlus 一份 DOM 產(chǎn)生多份 SAX Event ,沒有嚴(yán)重的多副本問題,但是 DOM 結(jié)構(gòu)本身比較大,所以得分為 6

    其余的技術(shù),內(nèi)存里的靜態(tài)文本都只保存一份,都沒有嚴(yán)重的空間效率問題,得分都是 10

    (11) Mapping Explicitness 映射關(guān)系明顯度

    什么數(shù)據(jù)應(yīng)該顯示在什么位置,一目了然。這種特性。

    JSP, Velocity, Freemarker 直接在 Template 里面把數(shù)據(jù)取出來顯示,一目了然,清清楚楚,得分都是 10

    Wicket 的強(qiáng)制 View Model 類型這里幫了大忙,無時無刻不提醒用戶 Model View (Template) 之間的映射關(guān)系。得分 8

    XMLC 直接操作 HTML Node By ID, or By Generated Method, 得分為 7

    比起, JSP 等來說, Taglib 的映射關(guān)系就隔了一層。尤其是當(dāng) Tag 之間存在層次關(guān)系的時候,比如, Form Tag 下面的 Input Tag Select Tag 下面的 Option Tag Taglib 的分?jǐn)?shù)只有 6

    XSL XPath Pattern Match 也是要稍微轉(zhuǎn)個彎,類似于 AOP Interceptor 的思路。得分為 5

    Tapestry 的配置如此復(fù)雜,得分只有 4

    Rife, JDynamicTe 直接操作 Template Node ,而且是自定義層次的 Template Node ,用戶編寫 Action Code 的時候,必須隨時查看 Template 里面的那些自定義標(biāo)簽之間的層次關(guān)系,并完全理解,了然于胸,才可能編寫正確的代碼。這方面的成本大大提高。分?jǐn)?shù)只有 3

    Fastm, DOMPlus 的問題類似,也是自定義層次的 Template Node ,需要隨時查看 Template 里面的那些自定義標(biāo)簽(或者 DOM Attribute )之間的層次關(guān)系。分?jǐn)?shù)只有 3

    ?(12) Display Logic Reusability 顯示邏輯重用度

    嵌在 Template 里面的 Server Side Script 代碼,不具有任何可重用性。除了整個 Include ,你無法在另外的地方調(diào)用 Template 里面的某一段代碼。

    JSP, Velocity, Freemarker, Logic Taglib, Tapestry Logic Tag XSL 的邏輯可重用度分?jǐn)?shù)都是 0 。當(dāng)頁面設(shè)計(jì)人員更改了具體頁面布局元素( HTML Tag )的時候,原來的 Template 里面的 Script 全部作廢,需要重新填充到新的 HTML 里面。

    Template Manipulation Model Match 技術(shù)的顯示邏輯都存在后臺的 Java 代碼里面,自然是可以重用的。方法調(diào)用,類繼承,包含,怎么都行。

    ?

    Wicket View Model 都是綁定到具體的 HTML UI Tag 上,比如, List, Table 等。當(dāng)這些 Tag 變化較大的時候,原有的代碼都需要改變。某些 HTML Display Taglib 也是如此。重用度分?jǐn)?shù)為 4

    當(dāng)結(jié)構(gòu)層次沒有變化,只是具體的 HTML Tag 變化的時候, XMLC 的原有 DOM 處理代碼幾乎不需要變動。在處理循環(huán)的時候,代碼需要 Create Specific HTML DOM Node ,然后添加到某個 DOM Node 上面。而且代碼可能大量使用自動產(chǎn)生的代碼的方法。這影響了它的得分,分?jǐn)?shù)為 4

    當(dāng)結(jié)構(gòu)層次沒有變化,只是具體的 HTML 布局元素發(fā)生了變化,那么, Rife, JDynamiTe, 的代碼都不需要變化。但是,它們的代碼侵入性非常強(qiáng),比 XMLC 還要強(qiáng)(如果 XMLC 采用標(biāo)準(zhǔn)的 HTML DOM 操作方法)。權(quán)衡考慮, Rife, JDynamiTe 的重用度分?jǐn)?shù)是 5

    當(dāng)結(jié)構(gòu)層次沒有變化,只是具體的 HTML 布局元素發(fā)生了變化, Fastm, DOMPlus 的代碼也不需要變化。而且, Fastm, DOMPlus 沒有代碼侵入性,產(chǎn)生的 Data Model 就是 POJO ,可以用在 JSP, Velocity, Freemarker Taglib 里面。所以,重用度分?jǐn)?shù)為 8

    Scripted Template

    前面講述了評估指標(biāo)。下面分別各項(xiàng)技術(shù)進(jìn)行單項(xiàng)說明。

    (1) Scripted Template

    HTML Server Side Script 混雜在一起的顯示層技術(shù)。

    包括 JSP, Velocity, Freemarker, Taglib, Tapestry, XSL 等。

    ?

    Server Side 的這些 Scripted Template 技術(shù)比較流行,耳聞能詳。前面進(jìn)行指標(biāo)描述的時候,各種參數(shù),也基本上涉及到了。就不具體展開進(jìn)行單項(xiàng)的用法說明和特性分析。

    JSP, Velocity, Freemarker 的優(yōu)勢在于這些技術(shù)對用戶后臺 Java 代碼侵入性非常低,這些 Template 都可以任意替換,而不影響用戶后臺 Java 代碼。

    ?

    下面講述另外兩類不是很常見的技術(shù)。

    (2)Template Manipulation

    Java 代碼直接操作 Template (比如, HTML DOM )產(chǎn)生結(jié)果的顯示層技術(shù)。

    包括 XMLC, JDynamiTe, Rife 等。

    ?

    (3) Model Match

    Java 代碼負(fù)責(zé)提供符合顯示層要求的 Data Model ,顯示層框架本身把 Data Model Template 進(jìn)行匹配,產(chǎn)生結(jié)果。

    包括 Wicket, Fastm, DOMPlus, 等。

    Template Manipulation

    Java 代碼直接操作 Template (比如, HTML DOM )產(chǎn)生結(jié)果的顯示層技術(shù)。

    包括 XMLC, JDynamiTe, Rife 等。

    這類技術(shù)都具有良好的所見即所得特性。

    (1)XMLC

    http://xmlc.enhydra.org/

    XMLC 把一個 HTML 文件翻譯成一個 Java HTML DOM Class

    比如,

    <INPUT ID="nameInput">

    <TITLE id="title">Hello, World</TITLE>

    <SPAN id="para1">...</SPAN>?...

    這些具有 id HTML 元素,在 Java HTML DOM Class 都產(chǎn)生了對應(yīng)的方法。

    HTMLElement getElementPara1()

    public void setTextPara1(String text)

    HTMLTitleElement getElementTitle()

    HTMLInputElement getElementNameInput();

    ?

    比如, <INPUT NAME="myName"> CLASS="class1 class2">

    就產(chǎn)生了如下的 Constant Fields.

    ?? public static final String NAME_myName;

    ?? public static final String CLASS_class1;

    ?? public static final String CLASS_class2;

    ?

    具體操作代碼如下,

    HTMLObject htmlObj = new HelloHTML();

    // Construct head

    HTMLHeadingElement head = htmlObj.createElement("h1");

    Text headText = htmlObj.createText("Hello World");

    head.appendChild(htmlTest);

    ?

    // Construct anchor

    HTMLAnchorElement anchor = htmlObj.createElement("a");

    anchor.setHref("Welcome.po");

    Text anchorText = htmlObj.createText("Welcome Page");

    anchor.appendChild(anchorText);

    ?

    // Replace contents of id-labeled node.

    Element replace = htmlObj.getElementReplaceme();

    Element parent = replace.getParent();

    ?

    // Start with the last new child so we can use insertBefore

    parent.replaceChild(anchor, replace);

    parent.insertBefore(head, anchor);

    ?

    可以看到,用戶的 Action Code 里面充滿了 HTML DOM Node 的添加刪除操作。而且里面使用的代碼都不是標(biāo)準(zhǔn)的 DOM 操作方法,而是代碼生成的方法。代碼侵入性非常強(qiáng),如果要換成別的 Template ,比如 JSP, velocity 所有的代碼都要作廢。

    當(dāng)然 XMLC 產(chǎn)生的是一個 DOM ,后面還是可以接續(xù) XSL 的。

    ?

    一般來說, XML DOM 操作只能針對完整的 Node 。一般需要替換整個 Attribute ,整個 Text

    對于, <a href=”http://www.mydomain.com/mymodule/{id}.html” 這類只需要替換某一部分的 Attribute 來說,處理起來就有點(diǎn)大而無當(dāng)。這時候, XMLC 引入了外部的 Regular Expression Matcher 等工具來處理這種情況。

    另外有一個不常見的需求。動態(tài)替換 Java Script 代碼的里面的某一部分。這時候, XMLC 就完全無能為力了。或許也可以引入外來的 Text Parser Engine ,比如 Velocity, Freemarker, Fastm, JDynamicTe 等來做這件事情。

    ?

    XMLC 的主要問題還是空間效率問題。每次請求,用戶需要產(chǎn)生一個 Java DOM Class 副本,進(jìn)行操作。如果有多個用戶訪問同一個 Page ,那么就同時存在多個 Java DOM Class 副本。

    當(dāng)然里面的靜態(tài)文本資源是共享的,我們看到上面的 Java DOM Class 里面,產(chǎn)生了很多 String 常數(shù)。

    但是 DOM Node 結(jié)構(gòu)本身的尺寸就比較大。即使采用了一些優(yōu)化簡化的 DOM Parser ,去除了用不到的結(jié)構(gòu),整個尺寸還是比較大。

    (2) JDynamiTe

    http://jdynamite.sourceforge.net/doc/jdynamite.html

    ?

    JDynamiTe PHPLib Template 的移植。采用 XML Comment 的方式標(biāo)記動態(tài)結(jié)構(gòu)塊。

    我們來看一個典型的兩層循環(huán)的例子。 <tr><td>

    ?

    <table border=1>
    <!-- BEGIN DYNAMIC : myBigRow -->
    <tr>

    <!-- BEGIN DYNAMIC : colX -->
    <td>{VALUE_X}</td>
    <!-- END DYNAMIC : colX -->

    <!-- BEGIN DYNAMIC : colY -->
    <td bgcolor="#33CCFF">{VALUE_Y}</td>
    <!-- END DYNAMIC : colY -->

    </tr>
    <!-- END DYNAMIC : myBigRow -->
    </table>

    ?

    對應(yīng)的代碼是,

    import cb.jdynamite.*;

    ?

    dynamiTe=new JDynamiTe();

    dynamiTe.setInput(application.getRealPath("cbtemplate/testTemplate.html"))

    ??? // Second table with nested Dynamic Element
    ??? for (int row = 0; row < 5; row++) {
    ??????? // first group of columns
    ??????? // 4) Use "setDynElemValue" to set or reset the value of a Dynamic Element
    ??????? dynamiTe.setDynElemValue("colX", ""); // reset for each row
    ??????? for (int col = 0; col < 3; col++) {
    ??????????? dynamiTe.setVariable("VALUE_X", "line_" + row + ",col_" + col);
    ??????????? dynamiTe.parseDynElem("colX"); // add a column
    ??????? }
    ??????? // second group of columns
    ??????? dynamiTe.setDynElemValue("colY", ""); // reset for each row
    ??????? for (int col = 3; col < 5; col++) {
    ??????????? dynamiTe.setVariable("VALUE_Y", "line_" + row + ",col(BIS)_" + col);
    ??????????? dynamiTe.parseDynElem("colY"); // add a column
    ??????? }
    ??????? dynamiTe.parseDynElem("myBigRow"); // add a row
    ??? }

    ??? // 5) Use "parse" to finaly get the value of your Dynamic Template Document
    ??? dynamiTe.parse();

    ??? out.println(dynamiTe.toString()); // send HTML page

    ?

    我們看到, Template 本身操作貫穿程序的始終。

    setDynElemValue, setVariable, parseDynElem, parse 都是 template Class 本身的方法,類似于 XML DOM Node 的添加刪除修改。

    我們看到這類 DOM Manipulator 的代碼侵入性非常強(qiáng),用了之后,如果要換別的 Template ,比如 JSP, velocity ,這段代碼完全作廢。

    (3) Rife

    http://rifers.org/

    類似于 JDynamiTe Rife 也采用自定義動態(tài)塊標(biāo)簽。

    下面是一個典型的例子。遞歸顯示一個 Data Tree 。下面只是核心片斷。如果對整個例子感興趣,可以去 Rife 的網(wǎng)站查看 Sample Tutorial

    這是一段 Tree Template

    <body>

    ${v level/}

    ${b level}

    ? <ul>${v nodes/}</ul>

    ${/b}

    ${b node}

    ? <li>${v title/}${v level/}</li>

    ${/b}

    </body>

    ?

    對應(yīng)的 Java 代碼操作 Template Node, 輸出 Data Tree

    ?

    import com.uwyn.rife.engine.Element;

    import com.uwyn.rife.template.InternalValue;

    import com.uwyn.rife.template.Template;

    ?

    // obtain an instance of the template that will output the tree

    Template template = getHtmlTemplate("tutorial.recursion");

    // obtain a new internal value to construct a collection

    // of sibling child nodes in the local scope

    InternalValue?? nodes = template.createInternalValue();

    // set the child's title value

    template.setValue("title", encodeHtml(child.getTitle()));

    // and append it to the local internal value

    nodes.appendBlock("node");

    // set the level value which includes the sibling nodes in the

    // same level

    template.setBlock("level", "level");

    ?

    我們看到, template 的操作代碼貫穿整個程序的始終。 getHtmlTemplate, createInternalValue, setValue, appendBlock, setBlock 。非常類似于上面 JDynamiTe 的用法。

    JDynamiTe 顯示 Data Tree 的過程也是大致如此。 XMLC 也是如此。

    Rife 同樣具有 JDynamiTe XMLC 的代碼侵入性強(qiáng)的缺點(diǎn)。如果需要換別的 Template 技術(shù),比如 JSP, velocity ,整個代碼都要做廢。

    Model Match

    Java 代碼負(fù)責(zé)提供符合顯示層要求的 Data Model ,顯示層框架本身把 Data Model Template 進(jìn)行匹配,產(chǎn)生結(jié)果。

    包括 Wicket, Fastm, DOMPlus, 等。

    這類技術(shù)都具有良好的所見即所得特性。

    (1) Wicket

    http://wicket.sourceforge.net/

    Wicket 類似于 Tapstry ,采用 HTML 自定義 Attribute 作為自定義標(biāo)簽。

    這段是 Rife 的一個典型的循環(huán)的例子。 wicket:id 一個標(biāo)簽,幾乎可以滿足任何需求。有興趣的讀者可以去 Wicket 網(wǎng)站查看完整的 Sample 。這里只有核心片斷。畢竟,本文不是一部 Wicket 教程。

    ?

    <html>

    <body>

    ? <form wicket:id = "commentForm">

    ??? Add your comment here:

    ??? <p>

    ??? <textarea wicket:id = "text">This is a comment</textarea>

    ??? <p>

    ??? <input type = "submit" value = "Submit"/>

    ? </form>

    ? <p>

    ? <span wicket:id = "comments">

    ??? <p>

    ?????? ??? <span wicket:id = "date">1/1/2004</span><br>

    ?????? ??? <span wicket:id = "text">Comment text goes here.</span>

    ?????? </p>

    ? </span>

    ? <wicket:remove>

    ??? <p>

    ?????? ??? 1/2/2004<br/>

    ?????? ??? More comment text here.

    ??? </p>

    ? </wicket:remove>

    </body>

    </html>???????????????????????

    ?

    我們可以看到, Template 非常干凈。只有少數(shù)的自定義 attribute, (and tag)

    對應(yīng)的 Java 代碼如下。

    ?

    import wicket.markup.html.WebPage;

    import wicket.markup.html.basic.Label;

    import wicket.markup.html.basic.MultiLineLabel;

    import wicket.markup.html.form.Form;

    import wicket.markup.html.form.TextArea;

    import wicket.markup.html.list.ListItem;

    import wicket.markup.html.list.ListView;

    import wicket.model.PropertyModel;

    ?

    public final class GuestBook extends WebPage

    {

    ?????? /** Use a Vector, as it is synchronized. */

    ?????? private static final List commentList = new Vector();

    ?????? private final ListView commentListView;

    ?

    ?????? public GuestBook()

    ?????? {

    ????????????? add(new CommentForm("commentForm"));

    ????????????? add(commentListView = new ListView("comments", commentList)

    ????????????? {

    ???????????????????? public void populateItem(final ListItem listItem)

    ???????????????????? {

    ??????????????????????????? final Comment comment = (Comment)listItem.getModelObject();

    ??????????????????????????? listItem.add(new Label("date", comment.date.toString()));

    ??????????????????????????? listItem.add(new MultiLineLabel("text", comment.text));

    ???????????????????? }

    ????????????? });

    ?????? }

    }

    ?

    我們看到, Wicket 的代碼,相當(dāng)干凈利索,雖然寫法上使用了匿名內(nèi)部類。沒有任何 Template 本身的操作。只是需要提供一個框架需要的 View Model ListView MultiLineLabel Label

    Wicket PropertyModel 能夠用來包裝一個 POJO 。比如,一段 HTML Template

    Stock of IBM: <span wicket:id="stockIBM">some value</span>

    ?

    對應(yīng)的 Java 代碼是

    import wicket.model.PropertyModel;

    ?

    public PojoStockQuotePage()

    {

    ??? StockQuote quote = new StockQuote("IBM");

    ??? add(new Label("stockIBM", new PropertyModel(quote, "quote"));

    }

    ?

    我們看到, Wicket 的代碼結(jié)構(gòu)非常像 Swing 。只需要對應(yīng) HTML UI Tag 提供一份 View Model 就可以。操作起來實(shí)在是方便。而且 HTML Tag 里面只需要添加 Wicket:id 這樣的自定義 Attribute ,就可以同時表達(dá)動態(tài)層次塊和變量部分(其實(shí) Rife 也是如此)。

    ?

    當(dāng)需要換 Template 的時候,比如 JSP, Velocity, Freemarker Taglib 等, Wicket 提供的 View Model 還是可以使用的。

    Wicket 的一個不足之處是,代碼需要使用框架自定義的 HTML View Model 。這也可能是一個優(yōu)點(diǎn),能夠幫助用戶清楚地理解,代碼和 HTML Template 之間的對應(yīng)關(guān)系。

    ?

    從嚴(yán)格意義上來說,比起 Taglib, Tapestry 來說 , 只有 Wicket, Echo 這樣的框架才是真正意義上的組件框架。而且, Wicket 相對于 Echo 的優(yōu)勢如此明顯,這里就不多說了。不然就跑題了。總之, Wicket 是一個非常值得關(guān)注的框架。

    (2) Fastm

    http://fastm.dev.java.net/servlets/ProjectDocumentList

    Fastm 的思路相當(dāng)于 JDynamiTe, Wicket 的思路組合。

    Fastm = JDynamiTe + Wicket

    Fastm 采用自定義標(biāo)簽來標(biāo)記動態(tài) Block ,然后類似于 JSTL, Velocity, Freemarker, Tapestry 那樣,接受一個 POJO 作為 Model ,并采用 OGNL Style( 同時也接受 XPath Style) 的方式對數(shù)據(jù)進(jìn)行尋址。

    Fastm 的公式很簡單, Fastm Template + Model = Result

    這個 Model POJO 。可以是 Java Bean, Map, DOM Node 等任何 Object

    ?

    我們來看一段典型的 Tree Data 遞歸顯示的例子。

    這段是 HTML Template 片斷。

    ?

    class name: <input type="text" value="{name}">

    <!-- BEGIN DYNAMIC: @children -->

    <ul>

    <!-- BEGIN DYNAMIC: children -->

    ? <li>

    ??? class name: <input type="text" value="{name}">

    ??? <!-- BEGIN DYNAMIC: @children -->

    ??? <ul>

    ??? <!-- BEGIN DYNAMIC: children -->

    ??? <!-- END DYNAMIC: children -->

    ??? </ul>

    ??? <!-- END DYNAMIC: @children -->

    ? </li>

    <!-- END DYNAMIC: children -->

    </ul>

    <!-- END DYNAMIC: @children -->

    ?

    上面的 @children 需要特別說明一下,意思是檢測當(dāng)前 Model 是否具有 children 這個 property ,如果具有,那么向下展開,否則就跳過去。這樣的話,如果沒有 children 的話,多余的 <ul> tag 就不需要打印出來了。雖然空 <ul>tag 并不影響顯示。

    ?

    對應(yīng)的 Java 代碼只需要提供一個 POJO 作為 Tree Data

    ?

    ??? public Object makeModel(){

    ?????? Map a = new HashMap();

    ?????? a.put( "name" , "A" );

    ?????? List aChildren = new ArrayList();

    ?????? a.put( "children" , aChildren);

    ?????? {

    ?????????? Map a1 = new HashMap();

    ?????????? a1.put( "name" , "A1" );

    ?????????? List a1Children = new ArrayList();

    ?????????? a1.put( "children" , a1Children);

    ?????????? {

    ????????????? Map a11 = new HashMap();

    ????????????? a11.put( "name" , "A1-1" );

    ????????????? a1Children.add(a11);

    ?

    ????????????? Map a12 = new HashMap();

    ????????????? a12.put( "name" , "A1-2" );

    ????????????? a1Children.add(a12);

    ?????????? }

    ?????????? aChildren.add(a1);

    ?????? }

    ?????? return a;

    ??? }

    ?

    這段代碼采用了 Map 作為 Model, 也可以采用 Java Bean, XML DOM Node 等任何 Object 。所以,當(dāng)然可以提供一個 XML 文件作為 Model

    ?

    看起來 Fastm JSP, Freemarker, Velocity JSTL 一樣,對 View Model 沒有什么特殊要求。 POJO 就可以。基本上就是如此。

    且慢, Fastm Model 還是有特殊要求的。類似于 Wicket Fastm 也沒有邏輯標(biāo)簽, Fastm 也利用數(shù)據(jù)來表示條件、循環(huán)等邏輯分支。遇到 Collection, Array 等數(shù)據(jù)類型,就自動把動態(tài)塊展開。如果不顯示某一塊,那么就提供一個空數(shù)據(jù)。

    這就是 Fastm 所需要的所有約定。看起來很簡單,真正滿足這個約定也不難。但是,某些特殊的情況下,為了滿足這個約定,需要后臺的用戶代碼做一些比 JSP, Velocity, Freemarker 要求的更多的 Model 組裝工作。

    Fastm 的另一個問題是, Model View Template )之間的映射關(guān)系不是很明了。雖然比 JDynamiTe Rife 等容易明白多了,但是比 Wicket 還是差一些。因?yàn)?/span> Fastm 沒有自定義 View Model 類型,需要用戶自己掌握 Bean, Map 層次和 Template 層次之間的正確對應(yīng)。

    (3) DOMPlus

    http://fastm.dev.java.net/servlets/ProjectDocumentList

    DOMPlus Fastm 的思路在 XML DOM 領(lǐng)域的擴(kuò)展。

    如果說, Fastm = JDynamiTe + Wicket ;那么, DOMPlus = XMLC + Wicket

    DOMPlus XMLC Wicket 思路的組合。

    如果說, Fastm 的公式是, Fastm Template + Model = Result

    那么, DOMPlus 的公式是, DOM + Model = DOM or SAX

    這個 Model POJO 。可以是 Java Bean, Map, DOM Node 等任何 Object

    一個很有趣的現(xiàn)象就是 DOM + DOM = DOM

    沒錯,就是如此。

    ?

    DOMPlus 采用自定義 DOM Attribute 來標(biāo)記動態(tài) Element, 動態(tài) Attribute, 動態(tài) Text

    我們來看一個典型的 Tree Data 遞歸顯示的例子。

    對應(yīng)的 HTML DOM 片斷是。

    ?

    ? <li nodeTarget = "child">

    ??? class name: <input type="text" attributesTarget="value=@name" />

    ??? <ul>

    ??? <li nodeTarget = "child" />

    ??? </ul>

    ? </li>

    ?

    nodeTarget 表示可能被重復(fù)多次的動態(tài) Element attributesTarget 表示需要替換的 attribute 。這里數(shù)據(jù)尋址方式采用的是 XPath @name 表示 DOM Node name attribute

    DOMPlus 的自定義標(biāo)簽只有 3 個, nodeTarget, attributeTarget, textTarget

    ?

    對應(yīng)的 XML Tree Data 是,

    ?

    <data name="topClass">

    <child name="A">

    ? <child name="A-1">

    ??? <child name="A-1-1"/>

    ? </child>

    ? <child name="A-2">

    ??? <child name="A-2-2">

    ????? <child name="A-2-2-3" />

    ??? </child>

    ? </child>

    ? <child name="A-3"/>

    </child>

    <child name="B">

    ? <child name="B-1" />

    </child>

    <child name="C" />

    </data>

    ?

    這兩個 DOM 一匹配,就產(chǎn)生了結(jié)果 XML ,是一棵顯示在 HMTL List 里面 Tree

    ?

    DOMPlus Template 更加干凈,幾乎接近于 XMLC Pure HTML DOM ,等同于 Wicket

    而且 DOMPlus 并沒有 XMLC 的空間問題。 DOMPlus 只保留一份 DOM 在內(nèi)存中,每次請求來的時候, DOMPlus 根據(jù)數(shù)據(jù)匹配產(chǎn)生 SAX Event ,直接寫入 Response

    ?

    DOMPlus 的匹配引擎很類似于 XSL 的功能,同樣是用 XML 格式的模板文件處理 XML 數(shù)據(jù)。而且兩者都同樣是遞歸處理引擎。

    所不同的是 DOMPlus Template 能夠在瀏覽器中正確顯示,而且表達(dá)結(jié)構(gòu)的自定義屬性非常簡單,只有 3 個( Fastm 2 個)。

    ?

    DOMPlus 的問題和 Fastm 一樣,數(shù)據(jù)層次和模板層次之間的關(guān)系,一定要非常清楚,而不是像 JSP, Velocity, Freemarker 那樣把數(shù)據(jù)抓過來就可以用。

    另外的問題就是,處理的最小單位是 XML Node XML Node 里面的 text 的部分替換就無能為力了。比如 <a href=”http://www.domain.com/module/{id}.html”

    XMLC 的解決方法一樣,可以引入外面的文本解析器。用來處理 XML Node 鞭長莫及的地方,比如, JavaScript 代碼的內(nèi)部的動態(tài)替換部分。

    Regular Expression Velocity, Freemarker, Fastm, JDydanamiTe ,等任何能夠脫離 Web 環(huán)境的通用文本解析工具都可以。 JSP, Taglib, Tapestry, Wicket 等無法脫離 Web 環(huán)境而存在,肯定不行。

    ?

    ------

    注:

    Fastm DOMPlus 是我的作品,輕量的 Template 匹配引擎。這兩項(xiàng)技術(shù)本身只是單項(xiàng)的 Template 顯示技術(shù),不是一個完整的 web 整體解決方案。

    特性總表

    (1) Host Language Consistency 宿主語言一致性

    (2)Template Purity 模板純凈度

    (3)Template Tidiness 模板整潔度

    (4) Replacement Flexibility 替換靈活度

    (5)WYIWYG 所見即所得

    (6)Action Code Purity 用戶代碼純凈度

    (7) Infrastructure Code Purity 基架代碼純凈度

    (8) 動態(tài) Include

    (9)Recursive Display of Tree Data 樹型數(shù)據(jù)的遞歸顯示

    (10) Space Efficiency 空間效率

    (11) Mapping Explicitness 映射關(guān)系明顯度

    (12) Display Logic Reusability 顯示邏輯重用度

    ?

    限于空間,下面的分?jǐn)?shù)表采用索引數(shù)字來代表特性。橫向是特性,縱向是技術(shù)。

    下面的表格中沒有寫 Freemarker ,只寫了 Velocity ,這兩項(xiàng)技術(shù)比較類似。各項(xiàng)參數(shù)也大致接近。當(dāng)然,各自的 Fans 都能夠看到很深很細(xì)的使用細(xì)節(jié),宏定義之類的。

    ?

    指標(biāo)索引

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    Scripted Template

    Velocity

    2

    0

    0

    10

    0-5

    10

    10

    10

    0

    10

    10

    0

    JSP

    10

    0

    0

    10

    0

    10

    10

    10

    0

    10

    10

    0

    Taglib

    0

    0

    10

    6

    0-5

    2 - 8

    0

    0

    4

    6

    6

    0

    Tapestry

    0

    0

    10

    6

    7

    4

    0

    0

    4

    10

    4

    0

    XSL

    10

    0

    10

    6

    0

    10

    10

    10

    10

    10

    5

    0

    Template Manipulation

    XMLC

    5

    10

    10

    6

    10

    0

    10

    10

    10

    0

    7

    4

    JDynamiTe

    5

    8

    5

    10

    8

    0

    10

    10

    10

    3

    3

    5

    Rife

    5

    3-7

    5

    10

    0-7

    0

    10

    10

    10

    3

    3

    5

    Model Match

    Wicket

    5

    9

    8

    6

    9

    2

    0

    0

    4

    10

    8

    4

    Fastm

    5

    7

    5

    10

    8

    6

    10

    10

    10

    10

    3

    8

    DOMPlus

    5

    9

    8

    6

    10

    6

    10

    10

    10

    6

    3

    8

    ?

    ?

    下面我們大致看一下 Browser Side Ajax )的情況。

    Browser Side

    Server Side 的技術(shù)格局恰好相反, Browser Side HTML DOM Manipulation 技術(shù)、 HTML View Model 技術(shù)比較多,比較流行。各種 JavaScript UI 控件, DOM 綁定控件,這方面的庫很多,而且很酷。這里不再列舉了。

    ?

    Browser Side Scripted Template 技術(shù)就比較少見了。我知道的大概有下面幾個。

    ?

    TrimPath JST

    http://www.trimpath.com/project/wiki/JavaScriptTemplates

    語法舉例

    <option value="${country.name}" {if country.name == currCountry}selected{/if}>

    ?

    ?

    Helma

    http://dev.helma.org/Wiki/JavaScript+Template+Engine/

    語法舉例

    ? <% if (session.user != null) %>

    ??? Hello <%= session.user.name %>

    ? <% else %>

    ??? <a href="/login">Login</a>

    ? <% end %>

    ?

    SWATO

    http://swik.net/SWATO/Swato+JavaScript+Template

    語法舉例

    #for (i in products) {

    #??? var p=products[i];

    ??? <td>$<%p.price%></td><td><%p.quantity%> : <%p.alert%></td>

    ??? </tr>

    #}

    ?

    以數(shù)據(jù)為中心的 Ajax 應(yīng)用中(把數(shù)據(jù)取過來,而不是取一段 HTML ,或者一段 Script ),當(dāng)頁面布局結(jié)構(gòu)比較復(fù)雜的情況下,也可以選擇 Browser Side XSL

    ?

    一個有趣的聯(lián)想是 DOMPlus 的思路。

    DOMPlus 不僅支持 DOM + DOM = SAX ,而且支持 DOM + DOM = DOM

    這個特性特別適合于 Browser Side 。假設(shè)存在 DOMPlus Javascript 版本。

    Javascript Server Side 拿來 XML Data ,和 Browser 里面的一段 HTML 進(jìn)行一下 Match ,顯示就搞定了。不需要寫任何代碼。

    Unobtrusive

    Brower Side 方面, Scripted Template 技術(shù)并不流行。

    這個事實(shí)說明了, Browser Side 的顯示技術(shù)更加歸于常態(tài),顯示模型更加自然。

    JavaScript 編程有個流行的概念,叫做 Unobtrusive ,就是我們常說的無侵入性。

    JavaScript, HTML, CSS 清晰有效的分開。

    行為的歸行為,內(nèi)容的歸內(nèi)容,風(fēng)格的歸風(fēng)格。

    凱撒的歸凱撒,上帝的歸上帝,人民的歸人民。

    各自照看好自己的領(lǐng)域,而不侵入他人的領(lǐng)域。

    ?

    無侵入, POJO 等概念,在 Server Side 方面(比如 Java ),也是甚囂塵上,炒作的不亦樂乎。

    但是在 Web 顯示技術(shù)的方面, Unobtrusive 無侵入特性,不能不說, Browser Side 由于先天的 JavaScript 操作 DOM 的優(yōu)勢,已經(jīng)走在了前面。

    ?

    雖然 JavaScript 作為一門動態(tài)語言,開發(fā)效率自然超過強(qiáng)類型編譯語言,但是代碼維護(hù)、 IDE 提示、輔助重構(gòu)方面的成本也不可低估。

    所以, Server Side 的顯示技術(shù),仍然是不可缺少的。在 Server Side 同樣應(yīng)用 Unobtrusive 原則,也仍然具有重要的意義。

    前面提到的兩個指標(biāo), Template Purity 模板純凈度 , Action Code Purity 用戶代碼純凈度。

    就屬于 Unobtrusive 指標(biāo)。

    ?

    顯示技術(shù)里面,代碼邏輯表示動態(tài)部分,復(fù)雜部分; Template 表達(dá)靜態(tài)部分,簡單部分。

    所以,人們更加關(guān)注代碼邏輯的容易管理的程度。

    由于代碼邏輯在 IDE 里面相對容易管理。人們更能夠容忍 Java 或者 Java Script 代碼里面出現(xiàn)具體的 Template Node ,而覺得 Template 里面的 Script 比較難以管理。

    ?

    Scripted Template 基本上是 Obtrusive 的,對 Template 的侵入性最強(qiáng)。雖然 Template 操作沒有侵入到 Java 或者 JavaScript 代碼。

    這叫做 1 -- Way Obtrusive

    ?

    Template Manipulation 大致能夠做到對 Template Unobtrusive 非侵入,雖然他們的 Template Node 操作侵入了 Java 或者 Java Script 代碼。

    這叫做 1-Way Unobtrusive

    ?

    Model Match 技術(shù)具有最好的 Unobtrusive 非侵入特性。 Java 或者 JavaScript 代碼不侵入 Template 到里面,具體的 Template Node 操作也不侵入到 Java 或者 JavaScript 代碼里面。

    這叫做 2-Way Unobtrusive

    ?

    Fastm, DOMPlus 是天生的 Model Match, 具有 2-Way Unobtrusive 特性。

    Wicket 也是天生的 Model Match ,大致能夠做到 1.5 -Way Unobtrusive

    如果嚴(yán)格限制不采用 Logic Taglib, Tapstry Logic Tag ,那么 Taglib Tapestry 也能夠做到 1.5 – Way Unobtrusive.

    顯示邏輯 AOP

    這個需求主要包括頁面數(shù)據(jù)類型的統(tǒng)一格式化。

    比如,所有類型為 Date ,名字以 Time 結(jié)尾的數(shù)據(jù)( startTime, endTime 等),都顯示到秒鐘; Day 結(jié)尾的時間字段 (registerDay, birthDay ) ,都顯示到天。 Period, Quarter, Year 結(jié)尾的字段也都有不同的顯示需求。

    能夠支持自定義顯示邏輯 AOP Interceptor 的技術(shù)并不是很多。

    XSL 語法天生就是 AOP 語法, Declaring Pattern Match ,用法就是要求程序員編寫 Interceptor

    Fastm, DOMPlus 對這方面也支持的很好。同樣是采用自定義 Interceptor

    ?

    W3 DOM Level 2 規(guī)范定義了 DOM Traversal

    http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/traversal.html

    DocumentTraversal, TreeWalker, NodeIterator, NodeFilter

    使用 Pull 模型( SAX Push 模型)處理 XML 的程序員,可以使用 NodeFilter 來過濾掉不需要顯示的節(jié)點(diǎn)。 NodeFilter 畢竟只是一個 Filter ,只能對 Node 內(nèi)容進(jìn)行簡單的開關(guān)選項(xiàng)處理, YES, or No ,顯示或者不顯示。只是作為 DocumentTraversal whatToShow 參數(shù)的一個補(bǔ)充。 AOP 能力很有限。

    多語言支持的終極解決方案

    多語言支持,也叫做國際化,本地化。

    一般采用字典文件的做法。比如, dict.en, dict.cn, dict.fr, dict.de, dict.jp 等。

    在這類做法里面, Template 里面通常都只有 Message Key

    <span>< message key=”name” /></span>

    ?

    有些更好的做法是這樣,提供缺省文本信息。

    <span id=”key.name”> 用戶名稱 </span>

    ?

    這樣能夠保持頁面的一目了然。

    ?

    除了字典文件的做法之外,另一種做法是直接把文字資源,存放到 Template 里面。

    然后分多個目錄。 En, cn, fr, de, jp 等目錄,下面全都是對應(yīng)的 Template 文件。

    這種方案叫做語言目錄方案。

    這種方案的缺點(diǎn)很明顯,一個文件的改動,要擴(kuò)散到所有的對應(yīng)文件中。

    這種方案的優(yōu)點(diǎn)也很明顯,文件內(nèi)容一目了然,尤其是支持所見即所得的模板。另一個優(yōu)點(diǎn)就是運(yùn)行效率。字典文件方案運(yùn)行的時候,需要進(jìn)行大量的查字典,動態(tài)替換文本工作。而語言目錄方案的模板里面大部分都是靜態(tài)文本。

    ?

    有沒有一個兩全其美的方案?答案是,有。

    首先,我們采用自己的母語(比如,中文)作為主模板文件,都放在 cn 目錄下。

    然后,其中需要多語言的文本信息,都采用下面這種方式包裝起來。

    <span id=”key.name”> 用戶名稱 </span>

    <p id=”key.help.charpter1”>long text about system help</p>

    ?

    這時候, Template 仍然保持了所見即所得的特性。然后,我們根據(jù)這些 Key ,做其他語言的字典文件。 Dict.en, dict.jp, dict.fr, etc.

    然后我們用一個文本處理引擎,替換掉這些多語言信息。為每一種語言產(chǎn)生一個目錄,下面都是對應(yīng)的語言的 Template 文件。比如, en, jp, fr, Template 文件目錄,里面都是對應(yīng)的填充了內(nèi)容的模板。打開一看,一目了然。

    當(dāng)然,這個處理過程中,并沒有影響那些動態(tài)數(shù)據(jù)部分,而只是替換了靜態(tài)文本部分。

    每次只需要更改主要語言目錄的文件,然后用引擎處理,變化自動分布到其他語言目錄。

    這種技術(shù)的關(guān)鍵在于, Template 本身是否可再生資源?能否被多次處理?能否被統(tǒng)一處理?

    有幾種技術(shù)是具有這種可能性的。

    Taglib 理論上可以被當(dāng)作 XML 文件處理,具有理論上的可行性。

    Fastm, DOMPlus 具有現(xiàn)實(shí)可操作性。 Fastm, DOMPlus 都可以自定義標(biāo)簽,處理動態(tài)部分的同時,也能夠忽略其他動態(tài)部分。

    總結(jié)與展望

    本文分析了 Web 層顯示技術(shù)的各類指標(biāo)和特性。

    本文的討論目前還只是局限于一般的 B/S 結(jié)構(gòu)。

    Web Service, SOA 代表了 Web 未來發(fā)展的趨向。數(shù)據(jù)整合,流程整合,各類資源整合。

    界面 UI 也不會限于 HTML 一種, XUL, XAML, SVG, RSS 等也有各自的應(yīng)用。

    ?

    我們都知道 Web 中有一種“盜鏈”的現(xiàn)象。

    一個網(wǎng)站,不是通過 Copy ,而是直接通過 Link 引入了其他網(wǎng)站的資源,比如 CSS ,圖片資源等。這樣可以節(jié)省自己的 Server 資源。

    有些技術(shù)更狠,能夠抓取別人的頁面內(nèi)容,剪貼拼湊之后顯示在自己的網(wǎng)頁上。

    這種情況實(shí)際上是一種偷偷摸摸的不被允許的資源共享實(shí)踐。

    ?

    Web Service 把這種實(shí)踐發(fā)展成了一種商業(yè)模式,資源共享模式。不僅可以共享數(shù)據(jù)和資源,而且可以共享內(nèi)容和服務(wù)(比如 Portlet )。

    比如, Web Service Remote Portal ,就是一種內(nèi)容提供模式、服務(wù)提供模式。網(wǎng)站流量不再依靠用戶點(diǎn)擊率來計(jì)算,而是依靠 Web Service 調(diào)用率。

    ?

    我們來看看,能夠共享的資源有哪些。

    CSS, 圖片, JavaScript 等可以直接 Link 過來;數(shù)據(jù)、內(nèi)容可以抓取過來。

    其中以 CSS 的共享最為流行。 CSS + 圖片 + 某些文字替換,組成了一個 Theme (顯示主體),或者 Skin (表觀)。很多人津津樂道,并孜孜不倦地談?wù)摗?yīng)用、提供各種 Themes, Skins

    但是還有一個重要的資源共享沒有得到充分的發(fā)展。就是 Template Layout 的共享。

    目前, Web Server Template 資源,一般都存放在自己的文件系統(tǒng)中。

    假設(shè)這樣一種方式。

    一個 Web Server 運(yùn)行的時候,通過 Web Service 獲取數(shù)據(jù),通過 Link 引用 CSS JS ,圖片等,通過 XLink + XPointer + XPath 獲取一份 XML Node or Fragment or Text ,作為 Template Layout ,自己的服務(wù)器上只需要一份 Display Logic 把這些東西組裝起來,就可以把頁面發(fā)布出來。甚至 Display Logic 也可以從 Web Service 獲取( Script 等,當(dāng)然這里面涉及到安全問題),自己只負(fù)責(zé)統(tǒng)籌管理安排調(diào)用。

    這種模型對于 Web Service Client 來說,也是適用的。

    這種模型的關(guān)鍵就在于, Unobtrusive 。所有領(lǐng)域都是清楚地分開, Domain Specific ,決不侵入到其他領(lǐng)域,也不允許其他領(lǐng)域的侵入。

    ?

    以上是我對 Web 顯示技術(shù)的總結(jié)和展望。

    本文到這里結(jié)束。

    posted on 2006-07-16 01:46 Vincent.Chen 閱讀(356) 評論(0)  編輯  收藏 所屬分類: JavaWebWork&StrutsJSFJavaScriptAJAXXMLRuby

    主站蜘蛛池模板: 久久久精品午夜免费不卡| 4444www免费看| 永久黄色免费网站| 亚洲av午夜福利精品一区| 亚洲国产成人精品无码一区二区 | 亚洲成在人天堂一区二区| 亚洲精品9999久久久久无码| 久久精品无码专区免费| 国产成人午夜精品免费视频| 国产亚洲精品自在线观看| 亚洲一区中文字幕在线观看| 拍拍拍无挡免费视频网站| 韩国18福利视频免费观看| 亚洲人成人一区二区三区| 亚洲日产乱码一二三区别| 精品四虎免费观看国产高清午夜| 亚洲精品乱码久久久久久久久久久久 | 2020亚洲男人天堂精品| 成人av片无码免费天天看| 日本人的色道www免费一区| 亚洲综合无码一区二区| 九九视频高清视频免费观看| 无码国产精品一区二区免费| 国产成人亚洲综合色影视| 一级日本高清视频免费观看 | 亚洲啪啪免费视频| 日韩精品福利片午夜免费观着| 亚洲gv猛男gv无码男同短文| 国产成人精品无码免费看 | 91成人在线免费观看| 亚洲午夜国产精品无码| 国产午夜无码精品免费看动漫| 亚洲成人动漫在线| 中文字幕无码播放免费| 亚洲国产精品一区二区久久| a级毛片100部免费观看| 亚洲综合久久综合激情久久 | 亚洲日韩国产精品无码av| 久久国产乱子精品免费女| 久久久久亚洲AV片无码下载蜜桃| 91精品免费国产高清在线|