開始使用 HTL

Adobe Experience Manager(AEM)支援的HTML範本語言(HTL)是AEM中HTML的偏好和建議的伺服器端範本系統。 它取代舊版AEM中使用的JSP(JavaServer Pages)。

注意

要運行本頁上提供的大多數示例,可以使用名為讀取評估打印循環的即時執行環境。

JSP上的HTL

建議新的AEM專案使用「HTML範本語言」,因為與JSP相比,它提供多項優點。 但是,對於現有項目,只有在預計遷移比在未來幾年維護現有JSP的工作量小的情況下,遷移才有意義。

但改用HTL並非一無是處的選擇,因為使用HTL編寫的元件與使用JSP或ESP編寫的元件相容。 這表示現有專案可以毫無問題地使用HTL來建立新元件,同時保留現有元件的JSP。

即使在同一個元件中,HTL檔案也可與JSP和ESP搭配使用。 以下示例說明了如何從JSP檔案包含HTL檔案的​行1​以及如何從HTL檔案包含JSP檔案的​行2:

<cq:include script="template.html"/>
<sly data-sly-include="template.jsp"/>

常見問題

開始使用HTML範本語言之前,我們先先回答一些與JSP與HTL主題相關的問題。

HTL是否有JSP所無法提供的限制? -與JSP相比,HTL並沒有其他限制,因為使用JSP可做的事也應該可以透過HTL達成。但是,HTL在設計上比JSP要嚴格,而且在單一JSP檔案中可實現的功能,可能需要將HTL分割為Java類別或JavaScript檔案,才能在HTL中實現。 但這通常是為了確保邏輯和標籤之間的關注之間很好地分離。

HTL是否支援JSP標籤庫? -否,但如「載入客戶機庫」 部分所 示,模板和 callstatements提 供了類似的模式。

AEM專案可擴充HTL功能嗎? -不,他們不能。HTL具有強大的擴充機制,可重複使用邏輯- Use-API —— 和標籤(template & call陳述式),可用來模組化專案的程式碼。

HTL優於JSP的主要優點為何? -安全性和項目效率是主要優點,詳見 概述

JSP最終會消失嗎? -在目前日期,沒有這些計畫。

HTL的基本概念

HTML範本語言使用運算式語言將內容片段插入轉譯的標籤中,而HTML5資料屬性則用來定義標籤區塊上的陳述式(例如條件或小版本)。 當HTL編譯為Java Servlet時,運算式和HTL資料屬性都會完全在伺服器端進行評估,而產生的HTML中不會顯示任何內容。

塊和表達式

以下是第一個範例,可像在​template.html​檔案中一樣包含:

<h1 data-sly-test="${properties.jcr:title}">
    ${properties.jcr:title}
</h1>

有兩種不同的語法可以區分:

  • 塊語句 -要有條件地顯示 <h1> 元素,則 data-sly-test 會使用HTML5資料屬性。HTL提供多種此類屬性,可將行為附加至任何HTML元素,而且所有屬性都加上前置詞data-sly

  • 運算式語言 - HTL運算式以字元和 ${ 分隔 }。在執行時期,會評估這些運算式,並將其值插入傳出的HTML串流。

上述連結的兩頁提供語法可用功能的詳細清單。

SLY元素

HTL的核心概念是提供重複使用現有HTML元素來定義區塊陳述式的可能性,避免插入其他分隔字元來定義陳述式的開始和結束位置。 此標籤的不顯眼註解可將靜態HTML轉換為功能正常的動態範本,可讓您不破壞HTML程式碼的有效性,因此即使是靜態檔案,也能正常顯示。

但是,有時在必須插入塊語句的確切位置可能不存在現有元素。 在這種情況下,可以插入將自動從輸出中移除的特殊SLY元素,同時執行附加的塊語句並相應地顯示其內容。

所以,以下例子:

<sly data-sly-test="${properties.jcr:title && properties.jcr:description}">
    <h1>${properties.jcr:title}</h1>
    <p>${properties.jcr:description}</p>
</sly>

將輸出類似下列HTML的內容,但僅當同時定義了​jcr:title​和​jcr:description​屬性,且兩者均為空時:

<h1>MY TITLE</h1>
<p>MY DESCRIPTION</p>

要記住的一點是,當沒有現有元素可以用塊陳述式加上註解時,僅使用SLY元素,因為SLY元素會阻止語言提供的值,使靜態HTML變為動態。

例如,如果上一個範例原本已包裝在DIV元素內,則新增的SLY元素會是辱罵性的:

<div>
    <sly data-sly-test="${properties.jcr:title && properties.jcr:description}">
        <h1>${properties.jcr:title}</h1>
        <p>${properties.jcr:description}</p>
    </sly>
</div>

而DIV元素可能已加上條件注釋:

<div data-sly-test="${properties.jcr:title && properties.jcr:description}">
    <h1>${properties.jcr:title}</h1>
    <p>${properties.jcr:description}</p>
</div>

HTL注釋

以下範例顯示在​行1​的HTL注釋,以及在​行2​的HTML注釋:

<!--/* An HTL Comment */-->
<!-- An HTML Comment -->

HTL注釋是HTML注釋,其中附加類似JavaScript的語法。 整個HTL注釋,以及處理器將完全忽略其中的任何內容,並從輸出中刪除。

但是,標準HTML注釋的內容將傳遞,並且評估注釋中的表達式。

HTML注釋不能包含HTL注釋,反之亦然。

特殊上下文

為了能夠最佳地運用HTL,請務必瞭解它以HTML語法為基礎的後果。

元素和屬性名稱

運算式只能放入HTML文字或屬性值中,但不能放在元素名稱或屬性名稱中,否則將不再是有效的HTML。 為了動態設定元素名稱,data-sly-element語句可用於所需的元素,並動態設定屬性名稱,即使一次設定多個屬性,也可以使用data-sly-attribute語句。

<h1 data-sly-element="${myElementName}" data-sly-attribute="${myAttributeMap}">...</h1>

沒有塊語句的上下文

由於HTL使用資料屬性來定義區塊陳述式,因此無法在下列內容中定義此類區塊陳述式,因此只能在此處使用陳述式:

  • HTML注釋
  • 指令碼元素
  • 樣式元素

其原因是這些上下文的內容是文字而非HTML,而且包含的HTML元素會被視為簡單的字元資料。 因此,若沒有真正的HTML元素,也無法執行​data-sly​屬性。

這聽起來可能像是一個很大的限制,但是它是需要的,因為HTML範本語言不應被濫用來產生非HTML的輸出。 下面的存取邏輯的使用-API一節介紹如何從範本呼叫其他邏輯,如果需要範本來準備複雜輸出,則可使用範本。 例如,從後端傳送資料至前端指令碼的簡單方式是讓元件的邏輯產生JSON字串,然後再將它放入資料屬性中,並使用簡單的HTL運算式。

以下範例說明HTML注釋的行為,但在指令碼或樣式元素中,會觀察到相同的行為:

<!--
    The title is: ${properties.jcr:title}
    <h1 data-sly-test="${properties.jcr:title}">${properties.jcr:title}</h1>
-->

將會輸出類似下列HTML的內容:

<!--
    The title is: MY TITLE
    <h1 data-sly-test="MY TITLE">MY TITLE</h1>
-->

需要顯式上下文

如下方「自動內容感知逸出」一節所述,HTL的目標之一是透過自動將內容感知逸出套用至所有運算式,降低引入跨網站指令碼(XSS)弱點的風險。 雖然HTL可自動偵測置於HTML標籤內之運算式的上下文,但它不會分析內嵌JavaScript或CSS的語法,因此需仰賴開發人員明確指定應套用至這些運算式的確切上下文。

由於XSS弱點中未套用正確的逸出結果,因此,HTL會在未宣告上下文時,移除指令碼和樣式內容中所有運算式的輸出。

以下是如何設定置入指令碼和樣式內之運算式的上下文範例:

<script> var trackingID = "${myTrackingID @ context='scriptString'}"; </script>
<style> a { font-family: "${myFont @ context='styleString'}"; } </style>

有關如何控制逸出的詳細資訊,請參閱表達式語言顯示上下文部分。

特殊上下文的解除限制

在需要略過指令碼、樣式和註解內容限制的特殊情況下,可以將其內容隔離在個別的HTL檔案中。 HTL會將位於其檔案中的所有項目解讀為一般的HTML片段,而忽略可能包含它的限制內容。

如需範例,請參閱使用用戶端範本一節。

注意

此技術可能會引入跨網站指令碼(XSS)弱點,若採用此技術,應仔細研究其安全性。 通常,實施同樣的事情,有比依靠這種做法更好的方法。

HTL的一般功能

本節快速介紹HTML範本語言的一般功能。

用於訪問邏輯的Use-API

請考慮下列範例:

<p data-sly-use.logic="logic.js">${logic.title}</p>

在伺服器端執行的logic.js JavaScript檔案旁邊放置:

use(function () {
    return {
        title: currentPage.getTitle().substring(0, 10) + "..."
    };
});

由於HTML範本語言不允許在標籤內混用程式碼,因此它提供Use-API擴充功能機制,以輕鬆從範本執行程式碼。

上述範例使用伺服器端執行的JavaScript來將標題縮短為10個字元,但也可以使用Java程式碼來提供完全限定的Java類別名稱。 一般而言,商業邏輯應該是以Java建立,但當元件需要從Java API提供的檢視特定變更時,使用伺服器端執行的JavaScript來進行變更會很方便。

以下各節中對此的詳細說明:

自動上下文感應逸出

請考慮下列範例:

<p data-sly-use.logic="logic.js">
    <a href="${logic.link}" title="${logic.title}">
        ${logic.text}
    </a>
</p>

在大部分範本語言中,此範例可能會造成跨網站指令碼(XSS)弱點,因為即使所有變數都自動以HTML逸出,href屬性仍必須特別以URL逸出。 這種遺漏是最常見的錯誤之一,因為它很容易被遺忘,而且很難以自動方式發現。

為協助您,「HTML範本語言」會自動將每個變數轉義至放置變數的上下文。 這要歸功於HTL瞭解HTML語法。

假設以下是logic.js檔案:

use(function () {
    return {
        link:  "#my link's safe",
        title: "my title's safe",
        text:  "my text's safe"
    };
});

初始範例將產生下列輸出:

<p>
    <a href="#my%20link%27s%20safe" title="my title&#39;s safe">
        my text&#39;s safe
    </a>
</p>

請注意,這兩個屬性的逸出方式不同,因為HTL知道hrefsrc屬性必須逸出以用於URI內容。 此外,如果URI以​javascript:​開頭,則屬性將會完全移除,除非上下文已明確變更為其他內容。

有關如何控制逸出的詳細資訊,請參閱表達式語言顯示上下文部分。

自動刪除空屬性

請考慮下列範例:

<p class="${properties.class}">some text</p>

如果class屬性的值恰好為空,則HTML模板語言將自動從輸出中刪除整個class屬性。

同樣地,這也是可能的,因為HTL瞭解HTML語法,因此只有在屬性值不為空時,才能有條件地顯示具有動態值的屬性。 這非常方便,因為它避免在屬性周圍添加條件塊,這會導致標籤無效和不可讀。

此外,在運算式中放置的變數類型也很重要:

  • String:

    • not empty:將 字串設定為屬性值。
    • 空白: 完全移除屬性。
  • 編號: 將值設定為屬性值。

  • 布林函數:

    • true:顯 示不帶值的屬性(作為布爾型HTML屬性)
    • false: 完全移除屬性。

以下是布林運算式如何允許控制布林HTML屬性的範例:

<input type="checkbox" checked="${properties.isChecked}"/>

對於設定屬性,data-sly-attribute語句也可能很有用。

使用HTL的常見模式

本節介紹一些常見的案例,以及如何使用HTML範本語言來最佳解決它們。

載入客戶端庫

在HTL中,用戶端程式庫會透過AEM提供的輔助範本載入,此範本可透過data-sly-use存取。 此檔案中有三個模板,可通過data-sly-call調用:

  • css -僅載入參考用戶端程式庫的CSS檔案。
  • js -僅載入參考用戶端程式庫的JavaScript檔案。
  • all -載入參考用戶端程式庫的所有檔案(包括CSS和JavaScript)。

每個幫助模板都需要​categories​選項來引用所需的客戶端庫。 該選項可以是字串值陣列或包含逗號分隔值清單的字串。

以下是兩個簡短的範例:

一次完全載入多個客戶端庫

<sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html?lang=zh-Hant"
     data-sly-call="${clientlib.all @ categories=['myCategory1', 'myCategory2']}"/>

在頁面的不同區段中參考用戶端程式庫

<!doctype html>
<html data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html?lang=zh-Hant">
    <head>
        <!-- HTML meta-data -->
        <sly data-sly-call="${clientlib.css @ categories='myCategory'}"/>
    </head>
    <body>
        <!-- page content -->
        <sly data-sly-call="${clientlib.js @ categories='myCategory'}"/>
    </body>
</html>

在上述第二個範例中,如果HTML head​和​body​元素被放置到不同的檔案中,則必須將​clientlib.html​範本載入需要的每個檔案中。

template & call陳述式中的章節提供更多有關宣告和呼叫此類範本的詳細資訊。

將資料傳遞到客戶端

一般而言,將資料傳遞給用戶端的最佳且最優雅的方式,是使用資料屬性。

以下範例說明如何使用邏輯(也可以以Java編寫)來非常方便地序列化要傳遞至用戶端的物件,然後將它放入資料屬性中:

<!--/* template.html file: */-->
<div data-sly-use.logic="logic.js" data-json="${logic.json}">...</div>
/* logic.js file: */
use(function () {
    var myData = {
        str: "foo",
        arr: [1, 2, 3]
    };

    return {
        json: JSON.stringify(myData)
    };
});

從這裡,您可以輕鬆想像用戶端JavaScript如何存取該屬性並重新剖析JSON。 例如,這會是要放入用戶端程式庫的對應JavaScript:

var elements = document.querySelectorAll("[data-json]");
for (var i = 0; i < elements.length; i++) {
    var obj = JSON.parse(elements[i].dataset.json);
    //console.log(obj);
}

使用客戶端模板

其中,Lifting Limitations of Special Contexts一節中說明的技術可合法使用的一個特殊情況是,編寫位於​script​元素內的用戶端範本(例如Handlebar)。 此技巧之所以可安全使用,是因為​script​元素不會像假設的那樣包含JavaScript,而會包含更多HTML元素。 以下是如何運作的範例:

<!--/* template.html file: */-->
<script id="entry-section" type="text/template"
    data-sly-include="entry-section.html"></script>

<!--/* entry-section.html file: */-->
<div class="entry-section">
    <h2 data-sly-test="${properties.entrySectionTitle}">
        ${properties.entrySectionTitle}
    </h2>
    {{#each entry}}<h3><a href="{{link}}">{{title}}</a></h3>{{/each}}
</div>

如上所示,將包含在​script​元素中的標籤可以包含HTL塊語句,而表達式不需要提供顯式上下文,因為Handlebars模板的內容已隔離在其檔案中。 此外,此範例還說明如何將伺服器端執行的HTL(如​h2​元素)與用戶端執行的範本語言(如Handlebars)混合使用(如​h3​元素上所示)。

不過,更現代的技巧是改用HTML template​元素,因為如此,您就不需要將範本的內容隔離為個別檔案。

閱讀下一節內容:

  • 運算式語言 -詳細瞭解在HTL運算式中可執行的動作。
  • 塊語句 -用於發現HTL中所有可用的塊語句,以及如何使用這些語句。

本頁內容

Adobe Summit Banner

A virtual event April 27-28.

Expand your skills and get inspired.

Register for free
Adobe Summit Banner

A virtual event April 27-28.

Expand your skills and get inspired.

Register for free
Adobe Maker Awards Banner

Time to shine!

Apply now for the 2021 Adobe Experience Maker Awards.

Apply now
Adobe Maker Awards Banner

Time to shine!

Apply now for the 2021 Adobe Experience Maker Awards.

Apply now