Search Results for

    Show / Hide Table of Contents

    Meta templates (Delphi)

    Note

    This demo is available in your FlexCel installation at <FlexCel Install Folder>\Demo\Delphi\Modules\20.Reports\90.Meta Templates and also at https:​//​github.​com/​tmssoftware/​TMS-​FlexCel.​VCL-​demos/​tree/​master/​Delphi/​Modules/​20.​Reports/​90.​Meta Templates

    Overview

    FlexCel allows self-modifying templates, that can adapt themselves to the data that is going to be reported. This provides other way to create generic reports, besides what is shown in the Generic Reports example. But the utility of meta templates can go much further.

    In this example, we have a template that will show rss feeds. If the feed contains a pubDate field, it will be added. If it doesn't, the row will be deleted from the template before running the report.

    Concepts

    • You can use the <#Preprocess> tag to evaluate expressions when the template is being read. You can delete columns and rows, clear fields, etc. Once the preprocessing is over, the report will be run on the modified template.

    • Database fields and expressions can have default values, that will be applied when the field or expression does not exist. For example: <#DataTable.field;20> will evaluate to the value in DataTable.Field if Field exists, or 20 otherwise.

    • The <#Defined> tag can be used to know wheter a field or table is defined or not, and to for example delete the column if the field does not exist.

    Files

    DataModel.pas

    unit DataModel;
    
    interface
    type
      TFeedData = record
      private
        FName: string;
        FLogo: string;
        FUrl: string;
        FHasPubDate: boolean;
      public
        property Name: string read FName;
        property Url: string read FUrl;
        property Logo: string read FLogo;
        property HasPubDate: boolean read FHasPubDate;
    
        constructor Create(const aName, aUrl, aLogo: string; const aHasPubDate: boolean);
      end;
    
      function GetFeeds: TArray<TFeedData>;
    
    type
      TFeedContent = record
      public
        Title: string;
        Description: string;
        Link: string;
    
        constructor Create(aTitle, aDescription, aLink: string);
    
      end;
    
      TFeedContentEx = record
      public
        Title: string;
        Description: string;
        Link: string;
        PubDate: Variant;
    
        constructor Create(aTitle, aDescription, aLink: string; const aPubDate: Variant);
    
      end;
    
    implementation
    
    function GetFeeds: TArray<TFeedData>;
    begin
      SetLength(Result, 3);
      Result[0] := TFeedData.Create('TMS', 'https://www.tmssoftware.com/rss/tms.xml', 'tms.gif', false);
        Result[1] := TFeedData.Create('MSDN','http://sxpdata.microsoft.com/feeds/3.0/msdntn/MSDNMagazine_enus', 'msdn.jpg', true);
        Result[2] := TFeedData.Create('SLASHDOT' , 'http://rss.slashdot.org/Slashdot/slashdot', 'slashdot.gif', false);
    end;
    
    { TFeedData }
    
    constructor TFeedData.Create(const aName, aUrl, aLogo: string; const aHasPubDate: boolean);
    begin
      FName := aName;
      FUrl := aUrl;
      FLogo := aLogo;
      FHasPubDate := aHasPubDate;
    end;
    
    { TFeedContentEx }
    
    constructor TFeedContentEx.Create(aTitle, aDescription, aLink: string;
      const aPubDate: Variant);
    begin
      Title := aTitle;
      Description := aDescription;
      Link := aLink;
      PubDate := aPubDate;
    end;
    
    { TFeedContent }
    
    constructor TFeedContent.Create(aTitle, aDescription, aLink: string);
    begin
      Title := aTitle;
      Description := aDescription;
      Link := aLink;
    end;
    
    end.
    

    UMainForm.pas

    unit UMainForm;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics,
      FlexCel.VCLSupport, FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Report, FlexCel.Render,
      {$if CompilerVersion >= 23.0} System.UITypes, {$IFEND}
      ShellApi, DataModel, Generics.Collections,
      XMLDoc, XMLIntf,
      Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
    
    type
      TMainForm = class(TForm)
        btnCancel: TButton;
        btnGo: TButton;
        SaveDialog: TSaveDialog;
        cbFeeds: TComboBox;
        cbOffline: TCheckBox;
        cbShowFeedCount: TCheckBox;
        procedure btnCancelClick(Sender: TObject);
        procedure btnGoClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        Feeds: TArray<TFeedData>;
    
        procedure RunReport;
        function GetDataPath: string;
        function GetLogo: TBytes;
        function CurrentFeed: TFeedData;
        function GetFeedContents: TArray<TFeedContent>;
        function GetFeedContentsEx: TArray<TFeedContentEx>;
        function GetOfflineData: IXmlDocument;
        procedure LoadFeeds(node: IXmlNode; const FeedList: TList<TFeedContent>);
        procedure LoadFeedsEx(node: IXmlNode;
          const FeedList: TList<TFeedContentEx>);
        function GetOnlineData: IXmlDocument;
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      MainForm: TMainForm;
    
    implementation
    uses IOUtils, IdHTTP, IdComponent;
    
    {$R *.dfm}
    
    procedure TMainForm.btnCancelClick(Sender: TObject);
    begin
      Close;
    end;
    
    procedure TMainForm.btnGoClick(Sender: TObject);
    begin
      RunReport;
    
    end;
    
    procedure TMainForm.FormCreate(Sender: TObject);
    var
      i: Integer;
    begin
      Feeds := GetFeeds;
      for i := 0 to High(Feeds) do
      begin
        cbFeeds.Items.Add(Feeds[i].Name);
      end;
      cbFeeds.ItemIndex := 0;
    end;
    
    function TMainForm.GetDataPath: string;
    begin
      Result := TPath.Combine(TPath.GetDirectoryName(ParamStr(0)), '..\..');
    end;
    
    function TMainForm.GetLogo: TBytes;
    var
      fs: TFileStream;
    begin
      fs := TFileStream.Create(
        TPath.Combine(TPath.Combine(GetDataPath, 'logos'), CurrentFeed.Logo), fmOpenRead);
      try
        SetLength(Result, fs.Size);
        if (Length(Result) > 0) then fs.Read(Result[0], Length(Result));
      finally
        fs.Free;
      end;
    end;
    
    function TMainForm.CurrentFeed: TFeedData;
    begin
      if (cbFeeds.ItemIndex < 0) or (cbFeeds.ItemIndex >= Length(Feeds)) then exit(Feeds[0]);
      Result := Feeds[cbFeeds.ItemIndex];
    end;
    
    function TMainForm.GetOfflineData: IXmlDocument;
    begin
      Result := TXMLDocument.Create(
                TPath.Combine(TPath.Combine(GetDataPath, 'data'), CurrentFeed.Name + '.xml'));
    end;
    
    function TMainForm.GetOnlineData: IXmlDocument;
    var
      Http: TIdHTTP;
      ms: TMemoryStream;
    begin
      Http := TIdHTTP.Create(nil);
      try
        ms := TMemoryStream.Create;
        try
          Http.Get(CurrentFeed.Url, ms);
          Result := TXMLDocument.Create(nil);
          Result.LoadFromStream(ms);
        finally
          ms.Free;
        end;
      finally
        Http.Free;
      end;
    
    end;
    
    procedure TMainForm.LoadFeeds(node: IXmlNode; const FeedList: TList<TFeedContent>);
    var
      i: Integer;
    begin
      if (node.LocalName = 'item') then
      begin
        FeedList.Add(TFeedContent.Create(node.ChildValues['title'], node.ChildValues['description'], node.ChildValues['link']));
        exit;
      end;
    
      for i := 0 to node.ChildNodes.Count - 1 do
      begin
        LoadFeeds(node.ChildNodes[i], FeedList);
      end;
    end;
    
    function TMainForm.GetFeedContents: TArray<TFeedContent>;
    var
      doc: IXmlDocument;
      FeedList: TList<TFeedContent>;
    begin
      if cbOffline.Checked then doc := GetOfflineData else doc := GetOnlineData;
      FeedList := TList<TFeedContent>.Create;
      try
         LoadFeeds(doc.DocumentElement, FeedList);
         Result := FeedList.ToArray;
      finally
        FeedList.Free;
      end;
    
    end;
    
    procedure TMainForm.LoadFeedsEx(node: IXmlNode; const FeedList: TList<TFeedContentEx>);
    var
      i: Integer;
    begin
      if (node.LocalName = 'item') then
      begin
        FeedList.Add(TFeedContentEx.Create(node.ChildValues['title'], node.ChildValues['description'], node.ChildValues['link'], node.ChildValues['pubDate']));
        exit;
      end;
    
      for i := 0 to node.ChildNodes.Count - 1 do
      begin
        LoadFeedsEx(node.ChildNodes[i], FeedList);
      end;
    end;
    
    function TMainForm.GetFeedContentsEx: TArray<TFeedContentEx>;
    var
      doc: IXmlDocument;
      FeedList: TList<TFeedContentEx>;
    begin
      if cbOffline.Checked then doc := GetOfflineData else doc := GetOnlineData;
      FeedList := TList<TFeedContentEx>.Create;
      try
         LoadFeedsEx(doc.DocumentElement, FeedList);
         Result := FeedList.ToArray;
      finally
        FeedList.Free;
      end;
    
    end;
    
    procedure TMainForm.RunReport;
    var
      Report: TFlexCelReport;
    begin
      if not SaveDialog.Execute then exit;
    
      Report := TFlexCelReport.Create(true);
      try
        if not CurrentFeed.HasPubDate
          then Report.AddTable<TFeedContent>('item', GetFeedContents)
          else Report.AddTable<TFeedContentEx>('item', GetFeedContentsEx);
    
        Report.SetValue('FeedName', CurrentFeed.Name);
        Report.SetValue('FeedUrl', CurrentFeed.Url);
        Report.SetValue('ShowCount', cbShowFeedCount.Checked);
    
        Report.SetValue('Logo', GetLogo);
    
        Report.Run(
          TPath.Combine(GetDataPath, 'Meta Templates.template.xls'),
          SaveDialog.FileName);
      finally
        Report.Free;
      end;
    
      if MessageDlg('Do you want to open the generated file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
      begin
        ShellExecute(0, 'open', PCHAR(SaveDialog.FileName), nil, nil, SW_SHOWNORMAL);
      end;
    
    
    end;
    
    end.
    
    In This Article
    Back to top FlexCel Studio for VCL and FireMonkey v7.24
    © 2002 - 2025 tmssoftware.com