Become a member!

TemplatePro Official Documentation

TemplatePro is a powerful and flexible template language designed to simplify the process of generating text-based outputs from structured data in Delphi applications. Whether you’re working with JSON, datasets, or custom objects, TemplatePro offers a wide range of syntactic elements that enable you to create dynamic and responsive templates with ease. In this article, we’ll explore the key syntactic elements of TemplatePro with examples to help you understand how to use this language effectively.

⭐ Updated to TemplatePro Language version 0.5. Check unit tests for more info about syntax and border cases.

Here’s a tipical utilization of a template:

program tproconsole;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  TemplatePro { TemplatePro compiler and executor },
  System.Rtti { required by TValue },
  System.SysUtils { required by try..except block }
  ;

//this is a custom filter
function AddSquareBrackets(const aValue: TValue; const aParameters: TArray<string>): TValue;
begin
  Result := '[' + aValue.AsString + ']';
end;

procedure Main;
begin
  var lCompiledTemplate: ITProCompiledTemplate := nil;
  var lCompiler := TTProCompiler.Create();
  try
    var lTemplate := 'Simple variable: {{:variable1}}';

    // template must be compiled before utilization
    lCompiledTemplate := lCompiler.Compile(lTemplate);

    // compiled template can be saved and retrieved from a file.
    // A compiled template cannot be executed with and older/newer version of the 
    // compiler.
  finally
    lCompiler.Free;
  end;

  //then, on the compiled template, you can define variable,
  //datasets, list of objects and json objects to use while rendering
  //the compiled template.

  //in this case we use only a simple variable
  lCompiledTemplate.SetData('variable1', 'Daniele Teti');

  //compiled template can also use "filters" defined
  //as simple functions with a specific prototype.
  //In this case we are going to use a simple filter wich adds
  //square brackets to the input value.
  lCompiledTemplate.AddFilter('brackets', AddSquareBrackets);

  //the render method returns the result of
  //the template execution as string
  WriteLn(lCompiledTemplate.Render);
end;

begin
  try
    Main;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Let’s introduce the TemplatePro language.

1. Variable Interpolation

At the core of TemplatePro is variable interpolation, allowing you to inject dynamic content directly into your templates. You can use the {{:variable}} syntax to display the value of a variable.

Example:

Hello, {{:name}}!

Output (if name is “Daniele”):

Hello, Daniele!

2. Looping with for .. in

The for .. in loop is a powerful construct in TemplatePro that lets you iterate over collections such as json arrays, datasets or lists of objects. Inside the loop, you can access each item in the collection using a loop variable.

Basic Example:

{{for person in people}}
  - {{:person.first_name}} {{:person.last_name}}
{{endfor}}

Output (for a list of people):

- Daniele Teti
- Peter Parker
- Bruce Banner

Nested Loop Example:

You can also nest loops to iterate over collections within collections.

{{for person in people}}
  {{:person.first_name}} {{:person.last_name}}
  {{for phone in person.phones}}
    - {{:phone.type}}: {{:phone.number}}
  {{endfor}}
{{endfor}}

Output:

Daniele Teti
  - Mobile: 123-456-7890
  - Work: 098-765-4321
Peter Parker
  - Home: 555-555-5555
  - Work: 444-444-4444

3. Conditional Statements: if, else, and endif

TemplatePro supports conditional statements that allow you to include or exclude parts of the template based on the value of a condition.

Simple Conditional Example:

{{if is_logged_in}}
  Welcome back, {{:username}}!
{{else}}
  Please log in to continue.
{{endif}}

Output (if is_logged_in is true and username is “Daniele”):

Welcome back, Daniele!

Output (if is_logged_in is false):

Please log in to continue.

Conditional with negation example:

{{if !is_logged_in}}
  You cannot see this content
{{endif}}

Output (if is_logged_in is false):

  You cannot see this content

4. Filters

Filters in TemplatePro allow you to modify the output of variables before they are rendered. Filter parameters (if any) are passed using “,” notation (see next paragraph).

Built-in Filter Example:

Original: {{:name}}
Uppercase: {{:name|uppercase}}
Lowercase: {{:name|lowercase}}

Output (if name is “Daniele Teti”):

Original: Daniele Teti
Uppercase: DANIELE TETI
Lowercase: daniele teti

Filters parameters (if any) can be passed comma separated (e.g. {{:value1|filter,par1,par2,“par3”}}).

TemplatePro offers a set of built-in filters:

Filter Name Description
uppercase returns the value in uppercase
lowercase returns the value in lowercase
capitalize returns the value capitalized a.k.a. first letter in each word in uppercase
rpad,xx returns the value padded to right with spaces. Total length is xx.
rpad,xx,"-" returns the value padded to right with “-” char. Total length is xx.
lpad,xx returns the value padded to left with spaces. Total length is xx.
lpad,xx,"-" returns the value padded to left with “-” char. Total length is xx.
datetostr returns the date value as string formatted using the system locale
datetostr,“yyyy mm dd” returns the date value as string formatted using the specified format
datetimetostr returns the datetime value as string formatted using the system locale
datetimetostr,“yyyy mm dd hh:nn:ss” returns the datetime value as string formatted using the specified format
formatdatetime alias to datetimetostr

Custom Filter Example:

Filters can be added to the compiled template. Filters are not required in the compile fase, they are linked and executed only at run-time.

Having a function like the following:

function AddSquareBrackets(const aValue: TValue; const aParameters: TArray<string>): TValue;
begin
  Result := '[' + aValue.AsString + ']';
end;

You can let the compiled template “see” it as shown below.

  //other code
  var lCompiledTemplate := lCompiler.Compile(lTemplate);
  lCompiledTemplate.AddFilter('brackets', AddSquareBrackets);

And then use the custom filter “brackets” in the template as shown below.

Bracketed: {{:name|brackets}}

(Where brackets is a custom filter that adds square brackets around the text.)

Output:

Bracketed: [Daniele Teti]

Filters cannnot be chained.

5. Working with JSON Objects

TemplatePro seamlessly integrates with JSON objects, allowing you to access nested properties using dot notation.

Simple JSON Example:

Company Name: {{:company.name}}
Country: {{:company.country}}

Output (for a JSON object with company.name as “bit Time Professionals” and company.country as “Italy”):

Company Name: bit Time Professionals
Country: Italy

Iterating Over JSON Arrays:

You can iterate over JSON arrays using the for .. in loop.

{{for employee in company.employees}}
  - {{:employee.first_name}} {{:employee.last_name}} ({{:employee.role}})
{{endfor}}

Output:

- Daniele Teti (Developer)
- Peter Parker (Developer)
- Bruce Banner (Scientist)

6. Using Functions

TemplatePro supports the use of functions to manipulate data within your templates. Functions can be invoked with parameters and are a great way to add logic to your templates. Currently functions are just filters applied to an empty string, so be warned that the first function parameter is always an empty string.

Basic Function Example:

Sum: {{""|sum,2,3}}
Greeting: {{""|concat,"Hello","World"}}

Output:

Sum: 5
Greeting: Hello, Daniele

7. Template Reuse with include

TemplatePro allows you to reuse templates by including them in other templates. This helps to maintain clean and modular code.

Example:

File header.tpro

Header content from header.tpro

File footer.tpro

Header content from footer.tpro

File main.tpro

{{include "header.tpro"}}

Content of the main template.

{{include "footer.tpro"}}

Output:

Header content from header.tpro

Content of the main template.

Footer content from footer.tpro

Included templates are linked into the main one and will be produced only one compiled template (just like many dcu are included in the output executable).

8. Escaping variables with $

Contents produced by TemplatePro are always HTML escaped. If you need to include raw content without processing, you can use the $ modifier.

Example:

{{"<div>123</div>"|lowercase}}
{{"<div>123</div>"$|lowercase}}

Output:

&lt;div&gt;123&lt;/div&gt;
<div>123</div>

9. Terminate template compiling with exit

exit statement interrupts the template compiling. It acts like an artificial eof.

Example:

{{for cust in customers}}
Customer name: {{:cust.Name}}   
{{exit}} 
{{endfor}}

Output (for first record of customers dataset has a field named “Name” with value “bit Time Professionals”):

Customer name: bit Time Professionals 

Dataset (or the object list) is not looped completely because exit interrupts loop at first iteration.

10. Escaping “double open curly brackets”

In case you have to emit a literal {{ just add another {; TemplatePro understand that you want to emits a double parentheses.

Example:

TemplatePro uses {{{ as start tag and }} as end tag

Output:

TemplatePro uses {{ as start tag and }} as end tag

11. Comments

TemplatePro comments start with {{# and terminate with }}. Can span on multiple lines too.

Example:

This is content {{# but this 
is a comment}} and this is another content

Output:

This is content and this is another content

Conclusion

TemplatePro is a versatile and powerful templating engine that offers a wide range of features to help you generate dynamic and efficient output in your Delphi applications. By mastering the various syntactic elements such as for loops, conditionals, filters, and functions, you can create templates that are both readable and maintainable.

The examples provided here are just a glimpse of what TemplatePro can do. I encourage you to explore the TemplatePro GitHub repository and experiment with the various features to see how they can be applied to your projects.

Happy templating!

Comments

comments powered by Disqus