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>\n<ul>\n"
    L"{% for place in places %}"
    L"<li>{$place}</li>\n"
    L"{% endfor %}"
    L"</ul>" ;

// 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 %}

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 %}

{% 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.

8 comments to cpptempl: A string templating library for C++

  • You might want to call this a templating engine, instead of a template language, as C++ already has a template language, which means something completely different in context.

  • @John

    Thanks for the feedback. I used the term “template language” because that’s what the Google CTemplate project calls it:

    CTemplate is a simple but powerful template language for C++.

    (Emphasis added)

    But I’m certainly not married to the term used to describe it.

  • Anonymous Cowherd

    What John Haugeland said. Except that I wouldn’t even call it a “templating engine”, since it’s not much of an “engine”; I’d just call it a “string interpolation library”. Unless I’m missing something very basic, it looks like cpptempl::parse() is just a function that executes at runtime (i.e. not template-based), and when it executes, all it does is some fairly simple string substitution.

  • @Cowherd

    I appreciate your feedback. Although I think that the support for loops and conditionals makes this more than just a string interpolation library, what major features do you think are missing? Please note that I made a conscious decision to keep arbitrary code execution out of my templates.

  • Have you considered using iostreams instead of strings for input and output?
    If you support the generic stream types (istream, ostream) then you could apply the templating engine directly on streams without having to temporarily store the input and output in strings. e.g. reading from a template file and sending the output directly to an http stream.

  • That’s a very good idea, thanks. I will plan to update the library to use iostreams.

  • – +1 for ‘templating engine’
    – syntax and usage looks good
    – I’d rather not have a boost dependency, since boost is really horrible to build/distribute on Windows, and whilst I use linux solely myself, lots of people do use Windows, and I’d prefer to make it easy for my library to work on Windows too

    Something we can do to remove the boost dependency?

  • Hi Hugh. Sorry for the late reply, but yes: with C++11, I think it is quite possible to drop the boost dependency.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>