Guida introduttiva ad HTL getting-started-with-htl

HTML Template Language (HTL) è il sistema di modelli lato server preferito e consigliato per HTML in Adobe Experience Manager. Come in tutti i sistemi di modelli HTML lato server, un file HTL definisce l’output inviato al browser specificando l’HTML stesso, alcune logiche di presentazione di base e variabili da valutare in fase di esecuzione.

Questo documento fornisce una panoramica dello scopo di HTL e un’introduzione ai concetti e costrutti fondamentali del linguaggio.

TIP
Questo documento presenta lo scopo di HTL e una panoramica della sua struttura e dei suoi concetti fondamentali. Se hai domande sulla sintassi, consulta la specifica HTL.

Livelli HTL layers

In AEM, un certo numero di livelli definiscono HTL.

  1. Specifica HTL: HTL è una specifica open-source, indipendente dalla piattaforma, che chiunque può implementare.
  2. Motore di script HTL Sling: il progetto Sling ha creato l’implementazione di riferimento di HTL, utilizzata da AEM.
  3. Estensioni AEM - L'AEM si basa sul motore di script HTL Sling per offrire agli sviluppatori funzionalità convenienti specifiche per l'AEM.

Questa documentazione si concentra sull’utilizzo di HTL per sviluppare soluzioni AEM. Come tale, tocca tutti e tre i livelli, collegando le risorse esterne in base alle esigenze.

Concetti fondamentali di HTL fundamental-concepts-of-htl

HTML Template Language utilizza un linguaggio di espressione per inserire parti di contenuto nel markup rappresentato e attributi di dati HTML5 per definire istruzioni su blocchi di markup (come condizioni o iterazioni). Man mano che HTL viene compilato nei servlet Java, le espressioni e gli attributi dei dati HTL vengono valutati interamente lato server e nulla rimane visibile nell’HTML risultante.

TIP
Per eseguire la maggior parte degli esempi forniti in questa pagina, è possibile utilizzare un ambiente di esecuzione live denominato Read Eval Print Loop.

Blocchi ed espressioni blocks-and-expressions

Di seguito un primo esempio, che potrebbe essere contenuto così com’è in un file template.html:

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

Si possono distinguere due diversi tipi di sintassi:

  • Istruzioni di blocco - Se si desidera visualizzare l'elemento <h1> in modo condizionale, utilizzare un attributo di dati data-sly-test HTML5. HTL fornisce più attributi di questo tipo, che consentono di associare il comportamento a qualsiasi elemento HTML e hanno tutti il prefisso data-sly.
  • Linguaggio espressioni - I caratteri ${ e } delimitano le espressioni HTL. In fase di esecuzione, queste espressioni vengono valutate e il loro valore viene inserito nel flusso HTML in uscita.

Per informazioni dettagliate su entrambe le sintassi, consulta la sezione Specifica HTL.

L’elemento SLY the-sly-element

Un concetto centrale di HTL consiste nell’offrire la possibilità di riutilizzare gli elementi HTML esistenti per definire le istruzioni di blocco. Questo riutilizzo evita la necessità di inserire delimitatori aggiuntivi per definire l’inizio e la fine dell’istruzione. L’annotazione del markup trasforma in modo discreto static HTML in un modello dinamico senza interrompere la validità di HTML, garantendo una visualizzazione corretta anche come file statici.

Tuttavia, a volte potrebbe non esserci un elemento esistente nella posizione esatta in cui deve essere inserita un’istruzione di blocco. In questi casi, è possibile inserire un elemento sly speciale. Questo elemento viene rimosso automaticamente dall’output durante l’esecuzione delle istruzioni di blocco associate e la conseguente visualizzazione del relativo contenuto.

Il seguente esempio:

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

Restituisce un output simile al seguente HTML, ma solo se sono definite entrambe le proprietà jcr:title e jcr:description e se nessuna delle due è vuota:

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

tuttavia, è importante ricorda di usare l’elemento sly solo se nessun elemento esistente può essere annotato con l’istruzione di blocco. Il motivo è che sly elementi impediscono al valore offerto dal linguaggio di modificare il HTML statico quando lo si rende dinamico.

Ad esempio, se l’esempio precedente fosse stato racchiuso all’interno di un elemento div, l’elemento sly aggiunto risulterebbe abusivo:

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

E l'elemento div avrebbe potuto essere annotato con la condizione:

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

Commenti HTL htl-comments

L’esempio seguente mostra un commento HTL sulla prima riga e un commento HTML sulla seconda riga.

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

I commenti HTL sono commenti HTML con una sintassi di tipo JavaScript aggiuntiva. Il processore ignora completamente l’intero commento HTL e qualsiasi cosa al suo interno, rimuovendolo dall’output.

Tuttavia, il contenuto dei commenti standard di HTML viene trasmesso e vengono valutate le espressioni all’interno del commento.

I commenti HTML non possono contenere commenti HTL e viceversa.

Contesti speciali special-contexts

Per poter utilizzare al meglio HTL, è importante comprendere bene le conseguenze del fatto che sia basato sulla sintassi HTML.

Per ulteriori dettagli, consulta la sezione Display Context della specifica HTL.

Nomi di elementi e di attributi element-and-attribute-names

Le espressioni possono essere inserite solo nei valori di testo o di attributo HTML, ma non all’interno di nomi di elementi o di attributi, altrimenti non sarebbe più un HTML valido. Per impostare dinamicamente i nomi degli elementi, è possibile utilizzare l'istruzione data-sly-element sugli elementi desiderati. Per impostare dinamicamente i nomi degli attributi, anche impostando più attributi contemporaneamente, è possibile utilizzare l'istruzione data-sly-attribute.

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

Contesti senza istruzioni di blocco contexts-without-block-statements

Poiché HTL utilizza gli attributi di dati per definire le istruzioni di blocco, non è possibile definirle all’interno dei seguenti contesti, in cui è possibile utilizzare solo le espressioni:

  • commenti HTML
  • elementi script
  • elementi di stile

Il motivo è che il contenuto di questi contesti è testo e non HTML e gli elementi HTML contenuti sarebbero considerati come dati di carattere semplici. Pertanto, senza veri e propri elementi HTML, non possono essere eseguiti anche data-sly attributi.

Questo approccio può sembrare una restrizione significativa. Tuttavia, è preferibile perché HTML Template Language deve generare solo un output HTML valido. La sezione Use-API per l’accesso alla logica di seguito illustra come richiamare una logica aggiuntiva dal modello, che può essere utilizzata se necessaria per preparare output complessi per questi contesti. Per inviare dati dal back-end a uno script front-end, genera una stringa JSON con la logica del componente e inseriscila in un attributo di dati utilizzando una semplice espressione HTL.

Nell'esempio seguente viene illustrato il comportamento dei commenti di HTML, ma in elementi di script o di stile si osserva lo stesso comportamento:

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

Restituisce un risultato simile al seguente HTML:

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

Contesti espliciti richiesti explicit-contexts-required

Come spiegato nella sezione Escape automatico in base al contesto di seguito, uno degli obiettivi di HTL è quello di ridurre i rischi di introduzione di vulnerabilità cross-site scripting (XSS) applicando automaticamente l’escape in base al contesto a tutte le espressioni. HTL rileva il contesto delle espressioni nel markup HTML, ma non analizza JavaScript o CSS in linea, pertanto gli sviluppatori devono specificare il contesto esatto per tali espressioni.

Poiché la mancata applicazione dei risultati di escape corretti genera vulnerabilità XSS, HTL rimuove l’output di tutte le espressioni che si trovano in contesti di script e di stile quando il contesto non è stato dichiarato.

Di seguito un esempio di come impostare il contesto per le espressioni posizionate all’interno di script e stili:

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

Per ulteriori dettagli su come controllare l’escape, consulta la sezione Expression Language Display Context delle specifiche HTL.

Funzionalità generali di HTL general-capabilities-of-htl

Questa sezione descrive rapidamente le funzioni generali di HTML Template Language.

Use-API per l’accesso alla logica use-api-for-accessing-logic

Java Use-API per HTML Template Language (HTL) consente a un file HTL di accedere a metodi helper in una classe Java personalizzata tramite data-sly-use. Questo processo consente di incapsulare nel codice Java tutte le logiche di business complesse, mentre il codice HTL tratta solo la produzione di markup diretto.

Per ulteriori dettagli, consulta il documento Java Use-API per HTL.

Escape automatico in base al contesto automatic-context-aware-escaping

Prendi in considerazione l’esempio seguente:

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

Nella maggior parte dei linguaggi basati su modelli, questo esempio potrebbe potenzialmente creare una vulnerabilità cross-site scripting (XSS), perché, anche quando tutte le variabili hanno automaticamente un escape HTML, l’attributo href deve essere ancora specifico per l’escape URL. Questa omissione è uno degli errori più comuni, perché può essere facilmente dimenticata ed è difficile da individuare in modo automatico.

Per facilitare questa fase, HTML Template Language applica automaticamente l’escape a ogni variabile in base al contesto in cui viene inserita. Questo approccio è possibile grazie al fatto che HTL comprende la sintassi di HTML.

Prendiamo in esame il seguente file logic.js:

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

L’esempio iniziale restituisce il seguente output:

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

Nota come i due attributi hanno escape diversi, perché HTL riconosce che gli attributi href e src devono avere un escape per il contesto URI. Inoltre, se l’URI iniziasse con javascript:, l’attributo sarebbe stato rimosso completamente, a meno che il contesto non fosse stato esplicitamente cambiato.

Per ulteriori dettagli su come controllare l’escape, consulta la sezione Expression Language Display Contex nellle specifiche HTL.

Rimozione automatica di attributi vuoti automatic-removal-of-empty-attributes

Prendi in considerazione l’esempio seguente:

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

Se il valore della proprietà class è vuoto, HTML Template Language rimuove automaticamente l'intero attributo class dall'output.

Anche in questo caso, questo processo è possibile perché HTL comprende la sintassi HTML e può quindi mostrare gli attributi con valori dinamici in modo condizionale solo se il loro valore non è vuoto. Il motivo è molto utile perché evita di aggiungere un blocco di condizione intorno agli attributi, il che avrebbe reso il markup non valido e illeggibile.

Inoltre, è importante il tipo di variabile posizionata nell’espressione:

  • Stringa:

    • non vuoto: Imposta la stringa come valore di attributo.
    • empty: rimuove completamente l’attributo.
  • Numero: Imposta il valore come valore di attributo.

  • Booleano:

    • true: visualizza l’attributo senza valore (come attributo HTML booleano)
    • false: rimuove completamente l’attributo.

Di seguito un esempio di come un’espressione booleana può consentire di controllare un attributo HTML booleano:

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

Per l’impostazione degli attributi, anche l’istruzione data-sly-attribute potrebbe risultare utile.

Pattern comuni con HTL common-patterns-with-htl

Questa sezione presenta alcuni scenari comuni. Spiega come risolvere al meglio questi scenari con HTML Template Language.

Caricamento librerie client loading-client-libraries

In HTL, le librerie client vengono caricate tramite un modello helper fornito da AEM, a cui è possibile accedere tramite data-sly-use. In questo file sono disponibili tre modelli, che possono essere richiamati tramite data-sly-call:

  • css: carica solo i file CSS delle librerie client di riferimento.
  • js: carica solo i file JavaScript delle librerie client di riferimento.
  • all: carica tutti i file delle librerie client di riferimento (sia CSS che JavaScript).

Ogni modello helper richiede un’opzione categories per fare riferimento alle librerie client desiderate. Tale opzione può essere una matrice di valori stringa o una stringa contenente un elenco di valori separati da virgola.

Di seguito sono riportati due brevi esempi.

Caricamento completo di più librerie client contemporaneamente loading-multiple-client-libraries-fully-at-once

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

Riferimento a una libreria client in diverse sezioni di una pagina referencing-a-client-library-in-different-sections-of-a-page

<!doctype html>
<html data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
    <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>

In questo esempio, se gli elementi HTML head e body si trovano in file separati, il modello clientlib.html deve essere caricato in ogni file che lo richiede.

La sezione sulle istruzioni di modello e chiamata nella Specifica HTL fornisce ulteriori dettagli sul funzionamento della dichiarazione e della chiamata di tali modelli.

Trasmissione di dati al client passing-data-to-the-client

Il modo migliore e più elegante per trasmettere i dati al client in generale, ma ancora di più con HTL, è quello di utilizzare gli attributi data.

L’esempio seguente illustra come serializzare un oggetto in JSON (possibile anche in Java) per passare al client. Può quindi essere facilmente posizionato in un attributo data:

<!--/* 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)
    };
});

Da lì, è facile immaginare come un JavaScript lato client possa accedere a tale attributo e analizzare nuovamente il JSON. Questo approccio sarebbe il JavaScript corrispondente da posizionare in una libreria client, ad esempio:

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);
}

Utilizzo dei modelli lato client working-with-client-side-templates

Un caso speciale, in cui la tecnica spiegata nella sezione Limitazioni di sollevamento di contesti speciali può essere legittimamente utilizzata, è quello di scrivere modelli lato client (come ad esempio Handlebars) che si trovano all’interno di elementi scrip. Il motivo per cui questa tecnica può essere utilizzata in questo caso è che l’elemento script non contiene quindi JavaScript, come ipotizzato, ma altri elementi HTML. Di seguito un esempio di come potrebbe funzionare:

<!--/* 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>

Il markup dell'elemento script può includere istruzioni di blocco HTL senza contesti espliciti, in quanto il contenuto del modello Handlebars è isolato nel proprio file. Inoltre, questo esempio mostra come è possibile combinare HTL eseguito lato server (come nell'elemento h2) con un Template Language eseguito lato client, come Handlebars (mostrato sull'elemento h3).

Una tecnica più moderna, tuttavia, sarebbe quella di utilizzare l’elemento HTML template, in quanto il vantaggio sarebbe che non richiede di isolare il contenuto dei modelli in file separati.

Limitazioni di sollevamento di contesti speciali lifting-limitations-of-special-contexts

Nei casi speciali in cui è necessario aggirare le restrizioni dei contesti di script, di stile e di commento, è possibile isolarne il contenuto in un file HTL separato. HTL interpreta tutto ciò che si trova nel proprio file come un frammento HTML standard, ignorando qualsiasi contesto limitativo da dove è stato incluso.

Per un esempio, consulta la sezione Utilizzo dei modelli lato client più avanti.

CAUTION
Questa tecnica può introdurre vulnerabilità cross-site scripting (XSS). Gli aspetti relativi alla sicurezza dovrebbero essere attentamente studiati se si ricorre a tale approccio. Solitamente esistono modi migliori per implementare la stessa cosa che affidarsi a questa pratica.
recommendation-more-help
86859df1-0285-4512-b293-0ef9cbea5ee8