Vous trouverez dans cet article toute la documentation pour comprendre le langage de programmation de Dialog Insight (Syntaxe, personnalisation, opérateurs, expressions conditionnelles, etc.) que vous pouvez utiliser dans la programmation d'un courriel HTML ou Drag n Drop.
Ressources
La syntaxe de base
Les balises DI#
Lorsque notre compilateur traite du code, il cherche les balises d'ouverture et de fermeture suivantes [[ et ]] qui délimitent le code qu'il doit interpréter. Tout ce qui se trouve en dehors des balises ouvrantes / fermantes de DI# est ignoré. À l’intérieur de ces balises, il est possible de ne pas interpréter de code afin d’afficher un simple texte. Pour cela, il suffit d’utiliser la méthode output.write(…);
Notez qu’un raccourci existe afin d’afficher du texte lorsqu’il s’agit de la seule instruction à exécuter entre les crochets : [[=… ;]]
Le code suivant [[="texte";]] |
Échappement du HTML
Tout ce qui se trouve en dehors d'une paire de balises ouvrantes/fermantes est ignoré par le compilateur, ce qui permet d'avoir du code DI# mixant les contenus. Ceci permet à DI# d'être contenu dans des documents HTML, pour créer par exemple des templates.
<p>Ceci sera ignoré par le compilateur</p> |
// Exemple 1 d'échappement avancé en utilisant des conditions |
Dans cet exemple, le compilateur va ignorer les blocs où la condition n'est pas remplie, même s’ils sont en dehors des balises ouvrantes/fermantes de DI#. Tout le code contenu dans la condition else ne sera donc jamais interprété puisque l'interpréteur DI# va passer les blocs contenant ce qui n'est pas rempli par la condition.
Séparation des instructions
Comme en C#, en Perl ou en PHP, DI# requiert que les instructions soient terminées par un point-virgule à la fin de chaque instruction. Aucune balise fermante n’implique de fin d’instructions, le point-virgule est obligatoire.
Les commentaires
Le DI# supporte deux types de commentaires :
- Les commentaires sur une seule ligne : Pour commenter jusqu'à la fin de la ligne du bloc PHP courant. Ceci signifie que toute le code HTML après // sera ignorée jusqu’à la fin de la ligne.
- Les commentaires multilignes : Pour commenter un bloc d’instruction en commençant par /* et en finissant par */. Tout ce qui est inclus entre ces deux balises sera ignoré.
Tableaux et collections
Un tableau en DI# est en fait une carte ordonnée. Une carte est un type qui associe des valeurs à des clés. Ce type est optimisé pour différentes utilisations ; il peut être considéré comme un tableau, une liste, une table de hashage, un dictionnaire, une collection, une pile, une file d'attente et probablement plus. On peut avoir, comme valeur d'un tableau, d'autres tableaux, multidimensionnels ou non. Autrement dit, on peut instancier un tableau de n’importe quel datatype qui serait soit fixe (voir les types listés ci-dessus), soit dynamique (équivalent à List<datatype> en .NET).
Déclaration
On peut définir un tableau en DI# comme ceci :
{ value1, value2, value3 }
datasource myArray = { 1, 2, 3, "abc", "def" }; |
On peut définir une collection d’éléments ainsi :
{ fieldName1 : value1, fieldName2 : value2, fieldName3 : value3 }
datasource myDictionary = { Prenom : "John", Nom : "Smith", Age : 30 }; |
// Les valeurs listées sont des Expressions, dont la valeur peut elle-même contenir une expression. On peut combiner les deux comme dans cet exemple : |
Instanciation
Il existe 2 façons d’instancier un tableau :
- Créer un tableau de long fixe : int a[10];
- Créer un tableau de longueur variable : string b[] ;
string a[] = {"texte1", "texte2", "texte3"}; |
// On peut assigner des valeurs initiales en déclarant l'array
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
string b[] = { "texte 1", "test", "abc" };
Lorsqu’une variable est déclarée de type tableau, cette dernière ne peut accepter que des valeurs du type de données du tableau. Exemple : int a[10] n’acceptera que des int.
Portée des variables (scope)
La portée d'une variable dépend du contexte dans lequel la variable est définie. Une variable définie à la racine du code aura une portée sur la totalité du script. Mais, une variable définie dans une fonction sera locale à la fonction. Autrement dit, toute variable créée à une portée limitée à sa propre fonction, ainsi qu’à ses fonctions sous-jacentes.
[[ |
Le contexte est quant à lui délimité par { et }. Ainsi, la déclaration d’une variable à l’intérieur de ces accolades, en fera une variable locale.
Expressions de requête
Les expressions de requête peuvent être utilisées pour interroger et transformer des données à partir de n'importe quelle source de données complexe. Ces requêtes servent à manipuler, trier ou filtrer un tableau (ou dictionnaire, liste, etc.). L’objectif est, à partir d’un tableau, de créer une nouvelle source de données qui :
- Filtre optionnellement le tableau original (clauses “Where”)
- Trie optionnellement le tableau original (clauses “Order by”)
- Extrait une propriété spécifique des items du tableau original
- Dédoublonne optionnellement les résultats
| Enquête de requêtes | Description |
|---|---|
| Select | Sélectionner les valeurs parmi la source de données. Il est possible d’utiliser l’option distinct afin de ne sélectionner que les valeurs distinctes parmi la source de données. |
| From | Choisir sur quelle source de données la requête sera appliquée. |
| Where | Restreindre les données sélectionnées avec une clause d’inclusion ou d’exclusion. |
| Order by | Trier les données selon un ou plusieurs champs par ordre ascendant ou descendant. Mots-clés supportés :
|
Concrètement, les expressions de requêtes s’utilisent comme ceci :
select identifier.propriete3
from identifier in expression
where identifier.propriete1 = valeur
order by (identifier.propriete2 asc)
Avec :
- Expression : la structure dans laquelle on veut récupérer un élément (un tableau, une collection, etc.).
- Identifier : le nom de la variable qui va récupérer l’élément du tableau sélectionné par la clause Where.
// Supposons la source de données suivante : |
Notes importantes Bien que ces fonctionnalités de requête et recherche de données dans les sources disponibles, bien que très puissantes, imposent des pénalités de performance importantes. Si utilisées de manière incorrecte dans un message, par exemple, ces requêtes peuvent avoir un impact important sur la vitesse de production des messages – considérez par exemple que toute requête faite dans un message transmis à un million de contacts devra être traitée un million de fois. N’hésitez pas à communiquer avec notre équipe de support ou nos analystes pour des conseils lors de la création de messages nécessitant ce degré de complexité. |
Les structures de contrôle
if
L'instruction if est une des plus importantes instructions de tous les langages. Elle permet l'exécution conditionnelle d'une partie de code. Les fonctionnalités de l'instruction if sont les mêmes qu'en C.
if (expression) |
OU
if (expression) |
L’instruction if converti son expression en sa valeur booléenne. Si l'expression vaut TRUE, DI# exécutera l'instruction et si elle vaut FALSE, l'instruction sera ignorée.
// L'exemple suivant affiche la phrase « a est plus grand que b » si a est plus grand que b : |
Vous pouvez imbriquer indéfiniment des instructions if dans d'autres instructions if, ce qui permet une grande flexibilité dans l'exécution d'une partie de code suivant un grand nombre de conditions.
else
Souvent, vous voulez exécuter une instruction si une condition est remplie, et une autre instruction si cette condition n'est pas remplie. C'est à cela que sert else. else fonctionne après un if et exécute les instructions correspondantes au cas où l'expression du if est FALSE.
/* Dans l'exemple suivant, ce bout de code affiche « a est |
if/else raccourci
Comme en C#, il est possible d’utiliser un raccourci à l’instruction if/else en utilisant l’opérateur conditionnel ? : tel que :
(condition) ? (expression_si_vrai) : (expression_si_faux);
[[ |
Note : Dû à des limitations du compilateur DI#, assurez-vous de placer la condition entre parenthèses lorsque vous utilisez cette forme.
while
La boucle while est le moyen le plus simple d'implémenter une boucle en DI#. Cette boucle se comporte de la même manière qu'en C.
// L'exemple le plus simple d'une boucle while est le suivant : |
// L’exemple suivant affiche tous les nombres de 1 jusqu'à 10 : |
Note : Portez attention à la gestion de vos variables qui contrôlent la boucle pour ne pas créer une boucle sans fin. Par mesure de protection, l’exécution des boucles while en DI# prend fin automatiquement dès que 250 itérations sont atteintes.
foreach
→ Itération sur un tableau
La structure de langage foreach fournit une façon simple de parcourir des tableaux.
foreach (identifier in expression) |
OU
foreach (identifier in expression) |
Dans cette structure, «identifier» est le nom que l’on choisit pour la qui itère les valeurs du tableau retourné par l’« expression ». Cette variable doit être du même type que les valeurs du tableau.
/* L’exemple suivant montre comment afficher tous les éléments d’un simple tableau de nombres entiers : */ |
→ Utilisation d'une expression complexe
Puisqu’un foreach permet d’itérer n’importe quel tableau issu d’une expression, il est possible d’utiliser des expressions complexes directement dans la structure du foreach, comme une expression de requête (voir leurs utilisations dans la partie précédente).
[[ |
→ Itération avec compteur
Comme dans de nombreux langages, il est possible d’entretenir un compteur pendant que l’on itère les valeurs de l’expression :
foreach (compteur => identifier in expression)
commande ;
Dans cette structure, « compteur » est le nom d’une variable qui est un nombre entier initialisé à 0 qui s’incrémentera à chaque itération de l’expression.
[[ |
Note : tout comme pour la boucle while, une boucle foreach s’interrompt automatiquement après 250 itérations.
break
/* L'instruction break permet de sortir d'une structure itérative foreach ou while. L’exemple suivant permet de « casser » la boucle du foreach afin de n’afficher que les 3 premiers nombres : */ [[ int myArray[] = { 1, 2, 3, 4, 5}; foreach(number in myArray) { output.write(number); if (number == 3) break; } ]] |
switch
L'instruction switch équivaut à une série d'instructions if. En de nombreuses occasions, vous aurez besoin de comparer la même variable (ou expression) avec un grand nombre de valeurs différentes, et d'exécuter différentes parties de code suivant la valeur à laquelle elle est égale. C'est exactement à cela que sert l'instruction switch.
Switch (expression) { case valeur : commande; } |
OU
Switch (expression) |
/* Les deux exemples suivants sont deux manières différentes d'écrire la même chose, l'une en utilisant une série de if, et l'autre en utilisant l'instruction switch : */ |
Contrairement à d’autres langages, il n’est pas nécessaire d’utiliser l’instruction break dans un switch de DI#. En effet, dès qu’un des cas est respecté, ses instructions seront exécutées et le compilateur sortira immédiatement du switch. Notez qu’il n’y a également pas de default dans le DI#, ainsi si aucun cas n’est respecté, le switch n’exécutera aucune instruction.
continue
L'instruction continue est utilisée dans une boucle afin d'éluder les instructions de l'itération courante et de continuer l'exécution à la condition de l'évaluation et donc, de commencer la prochaine itération.
[[ |
Un continue arrête donc immédiatement les instructions de la boucle et passe à la prochaine itération.
return
L’instruction return retourne le contrôle du programme au module appelant. L'exécution reprend alors à l'endroit de l'invocation du module.
- Si appelée depuis une fonction, la commande return termine immédiatement la fonction, et retourne l'argument qui lui est passé.
- Si appelée depuis l'environnement global, l'exécution du script est interrompue.
Return accepte une valeur de retour optionnel. Ceci permet d’assigner à une variable le résultat de ce qui a mis fin au script.
/* Dans l’exemple suivant l’instruction return, en plus d’arrêter le l’exécution de la fonction checkNumber retourne une valeur qui peut être assigné directement à une variable : */ [[ string checkNumber(int x) { if (x == 0) return "x égal 0"; if (x == 1) return "x égal 1"; if (x == 2) return "x égal 2"; } string result = checkNumber(1); output.write(result); // Affiche "x égal 1" ]] |
Note : si l’instruction return est utilisée à la racine du script, ceci stoppe l’exécution complète du script et la valeur retournée par return peut dans certains cas remplacer ce que le script aurait dû afficher.
Les fonctions
Déclaration
Une fonction DI# se déclare de la même façon qu'en C.
[Type] [Nom] ([Paramètre1], [Paramètre2], etc.)
{
Instructions...
}
Les fonctions doivent être définies à la racine du template, c’est-à-dire qu’elles ne peuvent pas être définies à l’intérieur d’un scope.
// Exemple d’une déclaration classique, avec valeur de retour définie |
// Exemple d’une déclaration avec une valeur par défaut |
Notes :
- Une fonction peut retourner n’importe quel type (string, int, decimal, etc.). Dans ce cas, la fonction doit nécessairement retourner une valeur. Cette valeur doit être obligatoirement du même type que le retour attendu par la fonction.
- Une fonction peut aussi être déclarée de type void. Dans ce cas, la fonction est utilisable comme simple instruction. L’exécution de cette fonction doit se terminer par un « return » (sans valeur de retour) ou bien atteindre la fin de la fonction.
Appel
Une fonction s’appelle comme dans tous les autres langages :
nomDeLaFonction(params) OU nomDeLaFonction()
Une fonction peut être utilisée comme statement/commande dans le script, par exemple :
OutputWithTags("mon texte", "i");
Les fonctions qui retournent une valeur (c'est-à-dire toutes les fonctions dont le type n’est pas void) peuvent aussi être utilisées en tant qu’expression ou valeur :
int x = addNumbers(1,1);
Portée des variables
Comme dans de nombreux langages, les variables créées à l’intérieur d’une fonction (les variables locales) ne sont pas visibles à l’extérieur de cette fonction. Les variables créées à l’extérieur de cette fonction ne quant à elles, pas accessible de l’intérieur de cette fonction.