cpptempl: A string templating library for C++

cpptempl is a simple string templating language (or templating engine) for C++. It has loops, conditionals, and variable interpolation. cpptempl relies on the boost libraries (shared_ptr, string_algo, and lexical_cast).

I originally wrote this engine because I was generating HTML files in C++, and generating the HTML right in the C++ quickly got very hairy, besides the fact that it made the content very hard to maintain. If all you need is string interpolation, something like Boost.Format would probably be enough, but I quickly found myself wanting to include lists of objects (e.g. search results), include content conditionally, and so on.

I was inspired to write this library by the approach of the major web frameworks like django and rails.

Here's a quick example:

// The text template

wstring text = L "I heart {$place}!" ;

// Data to feed the template engine

cpptempl:: data_map data ;

// {$place} => Okinawa

data [ L "place" ] = cpptempl:: make_data ( L "Okinawa" ) ;

// parse the template with the supplied data dictionary

wstring result = cpptempl:: parse ( text, data ) ;

The result will be:

I heart Okinawa!

Here's how you might generate an HTML unordered list:

// You'd probably load this template from a file in real life.

wstring text = L "<h3>Locations</h3>

<ul>

"

L "{% for place in places %}"

L "<li>{$place}</li>

"

L "{% endfor %}"

L "</ul>" ; wstring text = L // Create the list of items

cpptempl::data_list places;

places.push_back(cpptempl::make_data(L"Okinawa"));

places.push_back(cpptempl::make_data(L"San Francisco"));

// Now set this in the data map

cpptempl::data_map data ;

data[L"places"] = cpptempl::make_data(places);

// parse the template with the supplied data dictionary

wstring result = cpptempl::parse(text, data) ;

The result will be:

<h3>Locations</h3>

<ul>

<li>Okinawa</li>

<li>San Francisco</li>

</ul>

Syntax

The template syntax is fairly simple and highly influenced by Python. You can use loops, conditionals, and variables. You can use dotted notation (item.thing) for dictionary-like variables. The only data type is string.

Variable Syntax

Use {$variable_name} for variables. You can use dotted notation for sub-fields.

His name is { $name } .

His telephone is { $person. telephone } .



Loop Syntax

{ % for item in items % }

{ $loop } . { $item }

{ % endfor % } itemitems %$loop$item% endfor % Friends:

{% for friend in person.friends %}

{$loop}. {$friend.name}

{% endfor %}

Note the " loop " variable that provides a counter in all loops. loop0 is zero-indexed.

If Syntax

{ % if name == "Bob" % }

( His name is really Robert )

{ % endif % } name ==His namereally Robert% endif % {% if name != "Bob" %}

(His name is not Bob)

{% endif %} {% if name %}

(He has a name)

{% endif %} {% if not name %}

(He has no name)

{% endif %}

Note that not means empty: If the variable name doesn't exist, then an exception will be thrown.

API Example

Here's a slightly more involved example of using the API, showing dot notation and loop syntax.

using namespace cpptempl ; // The text template. Loop through person's friends

wstring text = L"{% for friend in person.friends %}"

L"{$loop}. {$friend.name} "

L"{% endfor %}" ; // Bob

data_map bob ;

bob[L"name"] = make_data(L"Bob") ;

// Betty

data_map betty ;

betty[L"name"] = make_data(L"Betty") ;

// List of friends

data_list friends ;

friends.push_back(make_data(bob)) ;

friends.push_back(make_data(betty)) ;

// Person and person's list of friends

data_map person ;

person[L"friends"] = make_data(friends) ;

// The data

data_map data ;

data[L"person"] = make_data(person) ; // Resolve the template

wstring result = cpptempl::parse(text, data) ;

The output will be:

1. Bob 2. Betty

See the bitbucket wiki page for more details.