Accessing data from the Sempare Template Engine for Delphi

Sempare Limited - Oct 16 - - Dev Community

The Sempare Template Engine (available at https://github.com/sempare/sempare-delphi-template-engine and GetIt) is a versatile templating system designed specifically for Delphi developers to streamline the creation and management of dynamic HTML, text, or any other text-based output formats. Whether you are building web applications, reports, or email templates, the Sempare Template Engine offers a powerful yet straightforward solution that integrates with minimal boilerplate into Delphi projects. The template engine has been around since 2019 and has many features for you to explore.

In this tutorial we will explore the various ways in which data can be accessed by Sempare Template Engine templates.

Overview

The template engine provides numerous ways for data to be accessed:

  1. Data passed to the template
  2. Data passed upfront in the context
  3. Data queried on demand
  4. Data queried by static helper functions
  5. Data queried by helper methods

This tutorial assumes you have installed the template engine following the instructions discussed elsewhere.

Let us explore each of these approaches.

Data passed to the template

This is the simplest approach where we pass data while evaluating the template.

program test;

uses
  Sempare.Template;

type
  TTemplateData = record
    Name : string;
  end;

var
  LData: TTemplateData;
  LTemplate : ITemplate;
begin
  LData.Name := 'Joe';
  LTemplate := Template.Parse('Hello <% name %>');
  writeln(Template.Eval(LTemplate, LData));
end;
Enter fullscreen mode Exit fullscreen mode

Data passed upfront in the context

By default, the Template helper methods will create a new context if you do not provide one. A context allows us to provide bespoke configuration that changes the way the template engine behaves. We can use this to also store global variables.

program test;

uses
  Sempare.Template;
var 
  LContext: ITemplateContext;
  LTemplate : ITemplate;
begin
  LContext := Template.Context();
  LContext.Variable['Company'] := 'Sempare Limited';
  LContext.Variable['CopyrightYear'] := 2024;
  LTemplate := Template.Parse('Copyright <% Company %>, <% CopyrightYear %>');
  writeln(Template.Eval(LContext, LTemplate, LData));
end;
Enter fullscreen mode Exit fullscreen mode

Data queried on demand

Rather than injecting values into the context, we can provide an anonymous function that allows for values to be resolved.

program test;

uses
  Sempare.Template;
var 
  LContext: ITemplateContext;
  LTemplate : ITemplate;
begin
  LContext := Template.Context();
  LContext.VariableResolver := function(const AContext: ITemplateContext; const AName: string; out AResult: TValue): boolean
    begin
      if AName = 'Company' then
      begin
        AResult := 'Sempare Limited';
        exit(true);
      end;
      if AName = 'CopyrightYear' then
      begin
        AResult := 2024;
        exit(true);
      end;
      AResult := '';
      exit(false);
    end;
  LTemplate := Template.Parse('Copyright <% Company %>, <% CopyrightYear %>');
  writeln(Template.Eval(LContext, LTemplate, LData));
end;
Enter fullscreen mode Exit fullscreen mode

Above, the resolver must return true if it is able to find the result. The AResult is a TValue from the RTTI unit which can store anything.

Note that if you allocate memory, you must deallocate memory yourself after the template has been evaluated.

Data queried by static helper functions

program test;

uses
  Sempare.Template;

type
  THelperMethods = class
    class function GetCompany() : string; static;
    class function GetCopyrightYear() : integer; static;
  end;

class function THelperMethods.GetCompany() : string;  
begin
  exit('Sempare Limited');
end;

class function THelperMethods.GetCopyrightYear() : integer; 
begin
  exit(2024);
end;

var 
  LContext: ITemplateContext;
  LTemplate : ITemplate;
begin
  LContext := Template.Context();
  LContext.Functions.AddFunctions(THelperMethods);
  LTemplate := Template.Parse('Copyright <% GetCompany() %>, <% GetCopyrightYear() %>');
  writeln(Template.Eval(LContext, LTemplate, LData));
end;
Enter fullscreen mode Exit fullscreen mode

In the above, we have illustrated how we add static functions and procedures.

Data queried by helper methods

program test;

uses
  Sempare.Template;

type
  TCompanyInfo = class
    function GetCompany() : string; 
    function GetCopyrightYear() : integer; 
    property Company: string read GetCompany;
    property CopyrightYear: integer read GetCopyrightYear;
  end;

function TCompanyInfo.GetCompany() : string;  
begin
  exit('Sempare Limited');
end;

function TCompanyInfo.GetCopyrightYear() : integer; 
begin
  exit(2024);
end;

var 
  LCompanyInfo : TCompanyInfo;
  LContext: ITemplateContext;
  LTemplate : ITemplate;
begin
  LCompanyInfo := TCompanyInfo.Create;
  try
    LContext := Template.Context();
    LContext.Variables['company'] := LCompanyInfo;
    LTemplate := Template.Parse('Copyright <% _.Company %>, <% _.CopyrightYear %>');
    writeln(Template.Eval(LContext, LTemplate, LData));
  finally
    LCompanyInfo.Free;
  end;
end;
Enter fullscreen mode Exit fullscreen mode

In the above, we also use '_' which is a magic variable that is an alias for the data being passed into the template.

Conclusion

As we have seen above, the Sempare Template Engine is very flexible and allows you to access data in many ways, allowing you to use it according to your usage pattern.

Sponsorship Required

Please help us maintain the project by supporting Sempare via GitHub sponsors (https://github.com/sponsors/sempare) or via our payment link (https://buy.stripe.com/aEU7t61N88pffQIdQQ). Sponsors can obtain access to our integrated IDE wizard for RAD Studio.

. . . . . . . . . . .