HTML Template C++
NOTE: this is a modified version of the original HTML::Template documentation, which can be found here.

WHERE TO DOWNLOAD

The project is available on SourceForge for download. The code is developed on Linux and tested against a version of Microsoft Visual Studio compiler.

SYNOPSIS

First you make a template - this is just a normal HTML file with a few extra tags, the simplest being <TMPL_VAR>

For example, test.tmpl:

  My name is <TMPL_VAR NAME=NAME>.
  I live in <TMPL_VAR NAME=CITY>.

Now create a small C++ program:

  #include "html_template.h"

  using namespace std;
  using namespace tmpl;

  int main(int argc, char* argv[])
  {
   html_template templ("test.tmpl");

   templ("NAME") = "Amador";
   templ("CITY") = "New York City";

   cout << templ;
   return 0;
  }

You should see the following output when running this program:

  My name is Amador.
  I live in New York City.

DESCRIPTION

This module attempts to make using HTML templates simple and natural. It extends standard HTML with a few new HTML-esque tags - <TMPL_VAR>, <TMPL_LOOP>, <TMPL_INCLUDE>, <TMPL_IF>, <TMPL_ELSE> and <TMPL_UNLESS>. The file written with HTML and these new tags is called a template. It is usually saved separate from your script - possibly even created by someone else! Using this module you fill in the values for the variables, loops and branches declared in the template. This allows you to separate design - the HTML - from the data, which you generate in the C++ program.

THE TAGS

TMPL_VAR

  <TMPL_VAR NAME="PARAMETER_NAME">

The <TMPL_VAR> tag is very simple. For each <TMPL_VAR> tag in the template you call template("PARAMETER_NAME") = VALUE. When the template is output the <TMPL_VAR> is replaced with the VALUE text you specified. If you don't set a parameter it just gets skipped in the output.

Optionally you can use the "ESCAPE=HTML" option in the tag to indicate that you want the value to be HTML-escaped before being returned from output. This means that the ", <, >, and & characters get translated into &quot;, &lt;, &gt; and &amp; respectively. This is useful when you want to use a TMPL_VAR in a context where those characters would cause trouble. Example:

  <input name=param type=text value="<TMPL_VAR NAME="PARAM">">

If you attempt to assign a value such as sam"my you'll get in trouble with HTML's idea of a double-quote. On the other hand, if you use ESCAPE=HTML, like this:

  <input name=param type=text value="<TMPL_VAR ESCAPE=HTML NAME="PARAM">">

You'll get what you wanted no matter what value happens to be passed in for param. You can also write ESCAPE="HTML", ESCAPE='HTML' ESC=HTML, ESC HTML and ESC=HTML.

There is also the "ESCAPE=URL" option which may be used for VARs that populate a URL. It will do URL escaping, like replacing ' ' with '+' and '/' with '%2F'.

There is also the "ESCAPE=JS" option which may be used for VARs that need to be placed within a Javascript string. All \n, \r, ' and " characters are escaped.

For convenience, ESCAPE=XML was added as well, which does the same thing as ESCAPE=HTML.

TMPL_LOOP

  <TMPL_LOOP NAME="LOOP_NAME"> ... </TMPL_LOOP>

The <TMPL_LOOP> tag is a bit more complicated than <TMPL_VAR>. The <TMPL_LOOP> tag allows you to delimit a section of text and give it a name. Inside this named loop you place <TMPL_VAR>s. Now you pass to your template a list (loop_t) of parameter assignments (row_t) for this loop. The loop iterates over the list of row_t structures, and produces output from the text block for each pass. Unset parameters are skipped. Here's an example:

  <TMPL_LOOP NAME=EMPLOYEE_INFO>
    Name: <TMPL_VAR NAME=NAME>
    Job:  <TMPL_VAR NAME=JOB>
  </TMPL_LOOP>

In the script:

  #include "html_template.h"

  using namespace std;
  using namespace tmpl;

  int main(int argc, char* argv[])
  {
   html_template my_template("test.tmpl");  
   loop_t loop_employee_info;
   row_t row_employee_info;

   row_employee_info("name") = "Sam";
   row_employee_info("job") = "Bunny Farm Owner";
   loop_employee_info += row_employee_info;

   row_employee_info("name") = "Steve";
   row_employee_info("job") = "Senior Keyboard Operator";
   loop_employee_info += row_employee_info;

   my_template("EMPLOYEE_INFO") = loop_employee_info;

   cout << my_template;


 return 0;
}

The output on screen:

   Name: Sam
   Job: Bunny Farm Owner

   Name: Steve
   Job: Senior Keyboard Operator

<TMPL_LOOP>s within <TMPL_LOOP>s are fine and work as you would expect. Here is an example, where we print out the list of nicknames for each name:

<TMPL_LOOP NAME=NAMES>

    Name: <TMPL_VAR NAME=NAME>
    Nicknames:

    <TMPL_LOOP nicknames>
      <TMPL_VAR NAME="nickname">
    </TMPL_LOOP>

</TMPL_LOOP>

In the code:

  #include "html_template.h"

  using namespace std;
  using namespace tmpl;
 
  int main(int argc, char* argv[])
  {
   html_template my_template("test.tmpl");

   loop_t loop_names;
   loop_t loop_nicknames;
   row_t row_name;
   row_t row_nickname;

   row_name("name") = "Bobby";

   row_nickname("nickname") = "the big bad wolf";
   loop_nicknames += row_nickname;

   row_nickname("nickname") = "He-Man";
   loop_nicknames += row_nickname;

   row_name("nicknames") = loop_nicknames;
   loop_names += row_name;

   my_template("NAMES") = loop_names;

   cout << my_template;

   return 0;
  }

Which gives us on screen:

  Name: Bobby
  Nicknames:
      the big bad wolf
      He-Man

Sometimes it is difficult to wrap your head around the syntax, especially with nested loops. Whenever you have to code a loop, think of it this way:

To build a loop, create a loop_t object. To add a row, create a row_t object, and add it to the loop after assigning variables. You can assign another loop_t to a row_t element, creating a nested loop.

Any variable used outside of a loop, in global scope, CAN be used within any other loop scope.

In nested loops, variables from higher-level loop scope "trickle-down" to nested loops.

TMPL_INCLUDE

  <TMPL_INCLUDE NAME="filename.tmpl">

This tag includes a template directly into the current template at the point where the tag is found. The included template contents are used exactly as if its contents were physically included in the master template.

The file specified can be an absolute path (beginning with a '/' under Unix, for example). If it isn't absolute, the system will search for the template relative to the directory of the parent template.

TMPL_IF

  <TMPL_IF NAME="PARAMETER_NAME"> ... </TMPL_IF>

The <TMPL_IF> tag allows you to include or not include a block of the template based on the value of a given parameter name. If the parameter is given a value that is true - like '1' - then the block is included in the output. If it is not defined, or given a false value - like '0' - then it is skipped. The parameters are specified the same way as with TMPL_VAR.

Example template:

  <TMPL_IF NAME="BOOL">
   Some text that only gets displayed if BOOL is true!
  </TMPL_IF>

Now if you call my_template("BOOL") = 1 then the above block will be included by output.

<TMPL_IF> </TMPL_IF> blocks can include any valid HTML::Template construct - VARs and LOOPs and other IF/ELSE blocks. Note, however, that intersecting a <TMPL_IF> and a <TMPL_LOOP> is invalid.

  Not going to work:
   <TMPL_IF BOOL>
      <TMPL_LOOP SOME_LOOP>
   </TMPL_IF>
     </TMPL_LOOP>

If the name of a TMPL_LOOP is used in a TMPL_IF, the IF block will output if the loop has at least one row. Example:

  <TMPL_IF LOOP_ONE>
    This will output if the loop is not empty.
  </TMPL_IF>

  <TMPL_LOOP LOOP_ONE>
    ....
  </TMPL_LOOP>

TMPL_ELSE

  <TMPL_IF NAME="PARAMETER_NAME"> ... <TMPL_ELSE> ... </TMPL_IF>

You can include an alternate block in your TMPL_IF block by using TMPL_ELSE. NOTE: You still end the block with </TMPL_IF>, not </TMPL_ELSE>!

   Example:

   <TMPL_IF BOOL>
     Some text that is included only if BOOL is true
   <TMPL_ELSE>
     Some text that is included only if BOOL is false
   </TMPL_IF>

TMPL_UNLESS

  <TMPL_UNLESS NAME="PARAMETER_NAME"> ... </TMPL_UNLESS>

This tag is the opposite of <TMPL_IF>. The block is output if the CONTROL_PARAMETER is set false or not defined. You can use <TMPL_ELSE> with <TMPL_UNLESS> just as you can with <TMPL_IF>.

  Example:

  <TMPL_UNLESS BOOL>
    Some text that is output only if BOOL is FALSE.
  <TMPL_ELSE>
    Some text that is output only if BOOL is TRUE.
  </TMPL_UNLESS>

If the name of a TMPL_LOOP is used in a TMPL_UNLESS, the UNLESS block output if the loop has zero rows.

  <TMPL_UNLESS LOOP_ONE>
    This will output if the loop is empty.
  </TMPL_UNLESS>
  
  <TMPL_LOOP LOOP_ONE>
    ....
  </TMPL_LOOP>

Loop Context Variables

The following context variables are made available inside a loop: __FIRST__, __LAST__, __INNER__, __ODD__, and __TOTAL__. They can be used with <TMPL_IF>, <TMPL_UNLESS> and <TMPL_ELSE> to control how a loop is output.

In addition to the above, a __COUNTER__ is also made available.

Example:

   <TMPL_LOOP NAME="FOO">
      <TMPL_IF NAME="__first__">
        This only outputs on the first pass.
      </TMPL_IF>

      <TMPL_IF NAME="__odd__">
        This outputs every other pass, on the odd passes.
      </TMPL_IF>

      <TMPL_UNLESS NAME="__odd__">
        This outputs every other pass, on the even passes.
      </TMPL_UNLESS>

      <TMPL_IF NAME="__inner__">
        This outputs on passes that are neither first nor last.
      </TMPL_IF>

      This is pass number <TMPL_VAR NAME="__counter__">.

      <TMPL_IF NAME="__last__">

        This only outputs on the last pass.
      </TMPL_IF>
   </TMPL_LOOP>

One use of this feature is to provide a "separator" similar in effect to the perl function join(). Example:

  <TMPL_LOOP FRUIT>
     <TMPL_IF __last__> and </TMPL_IF>
     <TMPL_VAR KIND><TMPL_UNLESS __last__>, <TMPL_ELSE>.</TMPL_UNLESS>
  </TMPL_LOOP>

Would output something like:

  Apples, Oranges, Brains, Toes, and Kiwi.

NOTE: A loop with only a single pass will get both __FIRST__ and __LAST__ set to true, but not __INNER__.

NOTES

Shorter syntax

The "NAME=" in the tag is optional, so "<TMPL_VAR test>" is acceptable. The same is true for all other tag types.

Case Sensitivity

Variables are case-insensitive, except TMPL_INCLUDE, where operating systems usually expect case-sensitive file names.

METHODS

Set_Template_File()

Set_Template_File() is called to set the template file to be parsed. The same can be done in template constructor, which takes the single parameter as the template path.

Process()

Parse the template and process the variables. Nothing heavy is done by the template until this method is called.

This returns reference to template output, which is an std::string.

std::cout

In an output stream context, a template object will implicitly call Process(), and print the output to standard out.

TODO

AUTHOR

Andrei Taranchenko

LICENSE

  HTML Template C++: A module for using HTML templates with C++
  Copyright (C) 2009 Andrei Taranchenko

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.