Introducción a HTL getting-started-with-htl

El lenguaje de plantilla HTML (HTL) es el sistema de plantillas del lado del servidor recomendado para HTML en Adobe Experience Manager. Como en todos los sistemas de plantillas del lado del servidor HTML, un archivo HTL define la salida enviada al explorador especificando el propio HTML, alguna lógica de presentación básica y variables que se deben evaluar durante la ejecución.

Este documento ofrece una visión general del propósito de HTL, así como una introducción a conceptos y construcciones fundamentales del lenguaje.

TIP
Este documento presenta el propósito de HTL y una visión general de su estructura y conceptos fundamentales. Si tiene preguntas acerca de sintaxis específica, consulte la especificación de HTL.

Capas HTL layers

AEM En la, varias capas definen HTL.

  1. Especificación de HTL: HTL es una especificación de código abierto, no basada en plataformas, que cualquiera puede implementar libremente.
  2. Motor de script HTL de Sling: el proyecto Sling ha creado la implementación de referencia de HTL, que utiliza AEM.
  3. AEM AEM AEM Extensiones de: se basa en la parte superior del motor de script HTL de Sling para ofrecer a los desarrolladores funciones prácticas específicas de los entornos de trabajo de los que se puede trabajar.

Esta documentación de HTL se centra en el uso de HTL para desarrollar soluciones de AEM. Como tal, afecta a las tres capas, vinculando los recursos externos según sea necesario.

Conceptos fundamentales de HTL fundamental-concepts-of-htl

El lenguaje de plantilla HTML utiliza un lenguaje de expresión para insertar fragmentos de contenido en el marcado procesado y los atributos de datos HTML5 para definir instrucciones sobre bloques de marcado (como condiciones o iteraciones). A medida que HTL se compila en Servlets Java, las expresiones y los atributos de datos HTL se evalúan completamente en el lado del servidor y nada permanece visible en el HTML resultante.

TIP
Para ejecutar la mayoría de los ejemplos proporcionados en esta página, se puede utilizar un entorno de ejecución en directo denominado Read Eval Print Loop.

Bloques y expresiones blocks-and-expressions

Este es un primer ejemplo, que se puede contener tal y como está en un archivo template.html:

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

Se pueden distinguir dos tipos diferentes de sintaxis:

  • Instrucciones de bloque: si desea mostrar el elemento <h1> de forma condicional, utilice un atributo de datos HTML 5 de data-sly-test. HTL proporciona varios atributos de este tipo, que permiten adjuntar el comportamiento a cualquier elemento HTML, y todos tienen el prefijo data-sly.
  • Lenguaje de expresión - Los caracteres ${ y } delimitan las expresiones HTL. Durante el tiempo de ejecución, estas expresiones se evalúan y su valor se inserta en el flujo HTML saliente.

Consulte la Especificación de HTL para obtener más información sobre ambas sintaxis.

El elemento SLY the-sly-element

Un concepto central de HTL es ofrecer la posibilidad de reutilizar elementos HTML existentes para definir instrucciones de bloque. Esta reutilización evita la necesidad de insertar delimitadores adicionales para definir dónde comienza y finaliza la instrucción. Al anotar el marcado, se transforma discretamente el HTML estático en una plantilla dinámica sin romper la validez del HTML, lo que garantiza una visualización adecuada, incluso como archivos estáticos.

Sin embargo, a veces puede que no haya un elemento existente en la ubicación exacta en la que se debe insertar una instrucción de bloque. En estos casos, puede insertar un elemento sly especial. Este elemento se elimina automáticamente de la salida mientras se ejecutan las instrucciones de bloque adjuntas y se muestra su contenido en consecuencia.

El siguiente ejemplo:

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

Genera algo como el siguiente HTML, pero solo si hay una propiedad jcr:title y una propiedad jcr:description definidas, y si ninguna de ellas está vacía:

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

Una cosa que hay que tener en cuenta es usar el elemento sly cuando no se pudo haber anotado ningún elemento existente con la instrucción de bloque. El motivo se debe a que los elementos sly disuaden al valor ofrecido por el idioma de no alterar el HTML estático al hacerlo dinámico.

Por ejemplo, si el ejemplo anterior se hubiera ajustado ya dentro de un elemento div, el elemento añadido sly sería abusivo:

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

Y el elemento div podría haberse anotado con la condición:

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

Comentarios de HTL htl-comments

El siguiente ejemplo muestra un comentario HTL en la primera línea y un comentario HTML en la segunda.

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

Los comentarios HTL son comentarios HTML con una sintaxis adicional de tipo JavaScript. El procesador ignora por completo todo el comentario HTL y todo lo que haya dentro, eliminándolo de la salida.

Sin embargo, el contenido de los comentarios del HTML estándar se pasa y se evalúan las expresiones dentro del comentario.

Los comentarios HTML no pueden contener comentarios HTL y viceversa.

Contextos especiales special-contexts

Para sacar el máximo partido a HTL, es importante comprender bien las consecuencias de estar basado en la sintaxis HTML.

Consulte la sección Mostrar contexto de la especificación de HTL para obtener más información.

Nombres de elementos y atributos element-and-attribute-names

Las expresiones solo se pueden colocar en texto HTML o valores de atributo, pero no dentro de nombres de elementos o nombres de atributos, o ya no sería un HTML válido. Para establecer nombres de elementos de forma dinámica, se puede utilizar la instrucción data-sly-element en los elementos deseados y para establecer nombres de atributos de forma dinámica, incluso estableciendo varios atributos a la vez, se puede utilizar la instrucción data-sly-attribute.

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

Contextos sin instrucciones de bloque contexts-without-block-statements

Como HTL utiliza atributos de datos para definir instrucciones de bloque, no es posible definir dichas instrucciones de bloque dentro de los siguientes contextos y solo se pueden utilizar expresiones en ellos:

  • Comentarios HTML
  • Elementos de script
  • Elementos de estilo

El motivo es que el contenido de estos contextos es texto y no HTML, y los elementos HTML contenidos se considerarían como datos de caracteres simples. Por lo tanto, sin elementos de HTML reales, tampoco puede haber data-sly atributos ejecutados.

Este enfoque puede parecer una restricción significativa. Sin embargo, se prefiere porque el lenguaje de plantilla de HTML solo debe generar una salida de HTML válida. La sección API de uso para la lógica de acceso que aparece a continuación presenta cómo se puede llamar a la lógica adicional desde la plantilla, que se puede utilizar si es necesaria para preparar resultados complejos para estos contextos. Para enviar datos desde el back-end a un script front-end, genere una cadena JSON con la lógica del componente y colóquela en un atributo de datos mediante una expresión HTL simple.

El siguiente ejemplo ilustra el comportamiento de los comentarios del HTML, pero en los elementos de script o estilo, se observaría el mismo comportamiento:

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

Genera algo similar al siguiente HTML:

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

Contextos explícitos requeridos explicit-contexts-required

Como se explica en la sección Escape automático según el contexto que aparece a continuación, uno de los objetivos de HTL es reducir los riesgos de introducir vulnerabilidades de scripts entre sitios (XSS) mediante la aplicación automática de escape según el contexto a todas las expresiones. HTL detecta el contexto de las expresiones en el marcado del HTML, pero no analiza JavaScript o CSS en línea, por lo que los desarrolladores deben especificar el contexto exacto para estas expresiones.

Dado que no se aplican los resultados de escape correctos en vulnerabilidades XSS, HTL elimina la salida de todas las expresiones que están en contextos de script y estilo cuando no se ha declarado el contexto.

A continuación, se muestra un ejemplo de cómo establecer el contexto para las expresiones colocadas dentro de secuencias de comandos y estilos:

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

Para obtener más información acerca de cómo controlar el escape, consulte la sección Contexto de muestra del lenguaje de expresión de las especificaciones HTL.

Capacidades generales de HTL general-capabilities-of-htl

Esta sección muestra rápidamente las funciones generales del lenguaje de plantilla HTML.

API de uso para acceder a la lógica use-api-for-accessing-logic

Lenguaje de plantilla HTML - HTL - La API para uso de Java permite que un archivo HTL acceda a los métodos de ayuda en una clase Java personalizada mediante data-sly-use. Este proceso permite encapsular toda la lógica empresarial compleja en el código Java, mientras que el código HTL solo trata la producción de marcado directo.

Consulte el documento API de uso de Java de HTL para obtener más información.

Escape automático según el contexto automatic-context-aware-escaping

Consideremos el siguiente ejemplo:

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

En la mayoría de los lenguajes de plantilla, este ejemplo podría crear una vulnerabilidad de ejecución de scripts en sitios cruzados (XSS), ya que incluso cuando todas las variables se escapan de forma automática de HTML, el atributo href debe seguir siendo específicamente de escape de URL. Esta omisión es uno de los errores más comunes, ya que puede olvidarse fácilmente, y es difícil detectarla de manera automatizada.

Para ayudarle, el lenguaje de plantilla de HTML omite automáticamente cada variable según el contexto en el que se coloca. Este enfoque es posible gracias al hecho de que HTL comprende la sintaxis de HTML.

Con el siguiente archivo logic.js como ejemplo:

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

El ejemplo inicial genera el siguiente resultado:

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

Vea cómo los dos atributos se han escapado de forma diferente, ya que HTL sabe que los atributos href y src deben evitarse para el contexto URI. Además, si la URI empezara por javascript:, el atributo se habría eliminado por completo, a menos que el contexto se cambiara explícitamente a otro.

Para obtener más información acerca de cómo controlar el escape, consulte la sección Contexto de muestra del lenguaje de expresión de las especificaciones de HTL.

Eliminación automática de atributos vacíos automatic-removal-of-empty-attributes

Consideremos el siguiente ejemplo:

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

Si el valor de la propiedad class está vacío, el lenguaje de plantilla de HTML quita automáticamente todo el atributo class de la salida.

De nuevo, este proceso es posible porque HTL comprende la sintaxis del HTML y, por lo tanto, puede mostrar condicionalmente atributos con valores dinámicos solo si su valor no está vacío. El motivo es muy práctico, ya que evita agregar un bloque de condición alrededor de los atributos, lo que habría hecho que el marcado no fuera válido ni legible.

Además, el tipo de variable colocada en la expresión es importante:

  • String:

    • no vacío: establece la cadena como un valor de atributo.
    • empty: quita el atributo por completo.
  • Número: Establece el valor como un valor de atributo.

  • Boolean:

    • true: muestra el atributo sin valor (como atributo HTML booleano)
    • false: elimina completamente el atributo.

Este es un ejemplo de cómo una expresión booleana permitiría controlar un atributo HTML booleano:

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

Para configurar atributos, la instrucción data-sly-attribute también puede ser útil.

Patrones comunes con HTL common-patterns-with-htl

Esta sección presenta algunos escenarios comunes. Explica la mejor manera de resolver estos escenarios con el lenguaje de HTML de plantillas.

Carga de bibliotecas de cliente loading-client-libraries

En HTL, las bibliotecas de cliente se cargan a través de una plantilla de ayuda proporcionada por AEM, a la que se puede acceder mediante data-sly-use. Hay tres plantillas disponibles en este archivo a las que se puede llamar mediante data-sly-call:

  • css: carga solo los archivos CSS de las bibliotecas de cliente a las que se hace referencia.
  • js: carga solo los archivos JavaScript de las bibliotecas de cliente a las que se hace referencia.
  • all: carga todos los archivos de las bibliotecas de cliente a las que se hace referencia (tanto CSS como JavaScript).

Cada plantilla de ayuda espera una opción categories para hacer referencia a las bibliotecas de cliente deseadas. Esa opción puede ser una matriz de valores de cadena o una cadena que contenga una lista de valores separados por comas.

Los siguientes son dos ejemplos breves.

Carga completa de varias bibliotecas de cliente a la vez 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']}"/>

Hacer referencia a una biblioteca de cliente en diferentes secciones de una página 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>

En este ejemplo, si los elementos del HTML head y body están en archivos independientes, la plantilla clientlib.html debe cargarse en cada archivo que la requiera.

La sección de las instrucciones de plantilla y llamada de la especificación de HTL proporciona más detalles acerca de cómo funcionan la declaración y la llamada a estas plantillas.

Pasaje de datos al cliente passing-data-to-the-client

La forma más adecuada de pasar datos al cliente en general, pero aún más con HTL, es usar atributos data.

En el siguiente ejemplo se muestra cómo serializar un objeto en JSON (también posible en Java) para pasarlo al cliente. Entonces se puede colocar fácilmente en un atributo 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)
    };
});

A partir de ahí, es fácil imaginar cómo un JavaScript del lado del cliente puede acceder a ese atributo y volver a analizar el JSON. Este método sería el JavaScript correspondiente para colocarlo en una biblioteca de cliente, por ejemplo:

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

Uso de plantillas del lado del cliente working-with-client-side-templates

Un caso especial, en el que la técnica explicada en la sección Limitaciones de elevación de contextos especiales puede utilizarse legítimamente, es escribir plantillas del lado del cliente (como Handlebars por ejemplo) que se encuentran dentro de los elementos scrip. La razón por la que esta técnica se puede utilizar de forma segura en ese caso es porque el elemento script no contiene JavaScript como se supone, sino más elementos HTML. Aquí hay un ejemplo de cómo funcionaría:

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

El marcado del elemento script puede incluir instrucciones de bloque HTL sin contextos explícitos, ya que el contenido de la plantilla Handlebars está aislado en su propio archivo. Además, este ejemplo muestra cómo se puede mezclar HTL de ejecución del lado del servidor (como en el elemento h2) con un lenguaje de plantilla de ejecución del lado del cliente, como Handlebars (mostrado en el elemento h3).

Sin embargo, una técnica más moderna sería utilizar el elemento HTML template en su lugar, ya que la ventaja sería que no es necesario aislar el contenido de las plantillas en archivos separados.

Limitaciones de elevación de contextos especiales lifting-limitations-of-special-contexts

En los casos especiales en los que es necesario evitar las restricciones de los contextos de script, estilo y comentario, es posible aislar su contenido en un archivo HTL independiente. HTL interpreta todo lo que hay en su propio archivo como un fragmento de HTML estándar, ignorando cualquier contexto limitante desde el que se incluyó.

Consulte la sección Trabajo con plantillas del lado del cliente más abajo para ver un ejemplo.

CAUTION
Esta técnica puede introducir vulnerabilidades de scripts entre sitios (XSS). Los aspectos de seguridad deben estudiarse cuidadosamente si se utiliza este enfoque. Por lo general, hay mejores maneras de implementar esto que confiar en esta práctica.
recommendation-more-help
86859df1-0285-4512-b293-0ef9cbea5ee8