LaTeX and template engines, revisited

Some time ago, I wrote a blog post about generating LaTeX code with a template engine. Yesterday, I finished an application for a client which had a lot of templates; since my hands were already dirty in the template clay, I decided to revisit the whole idea and come up with some sort of merging tool. And yes, there’s also a duck involved.

I was playing with some code and, all of a sudden, I actually came up with something interesting: what if we have a tool that merges a list of datasources into a template and generate the output? Of course, I was aiming at TeX and friends, but the tool could be used for other contexts as well. Everything was ready, but I needed a name. Then:

and duckity was born. I wrote it in Java, and I plan to release it soon. I still need to improve some parts of the code, but the tool is already finished. Let’s see an example of use. Consider the following code:

The input file is divided in two parts: the definition of datasources and the template itself. The definition part is written in the JSON format, while the template can be written in any format (.tex for example), and supported by Apache Velocity.

In the definition part, there are at least two mandatory elements: file and identifier. Two formats are supported: JSON and CSV. The file element contains the actual data, and the identifier is used to refer to this data in the template. Let’s say we have the following grades.csv file:

In our example, students refer to the content of the grades.csv file. Merging our template with our data file:

If I omit the --output flag, the output name would be rep1.new.tex instead. Let’s take a look at the generated file:

Cool, it works! Now, let’s try something more neat: what if, when typesetting the grades, if the value is below 5.0, the number is displayed in the red colour? Leave it to the template, the helper $math class and some conditionals:

After applying duckity rep2.tex, the newly created rep2.new.tex will have the following content:

Let’s compile it, shall it?

Yay! But we can get more intricate stuff. Let’s add a new datasource, this time, a JSON file. Consider the following template:

Two datasources for the price of only one. The subject.json has the following structure:

Note that we map each key of the JSON file to identifier + . + key in the template to get its value. We can even iterate through elements of a list (in our JSON file, schedule has a list of dates) and add conditionals according to their positions. Let’s see the result:

Now we want the final note. We can easily tell the template to calculate the value for us, and even apply the colour conditional:

Here we go! After merging the data and the template, we have the following file:

Let’s compile it!

We can add an arbitrary number of datasources (JSON or CSV). Let’s add another one:

A list of tutors will be added at the end of the document. This is the JSON file:

Let’s see the final code:

And of course, the output:

I know that Velocity’s syntax (including the $) might sound like a mess in an editor (you can already tell what it did to my Vim). But the nice thing about it is that the template engine is actually smart enough to know what to resolve and what to leave intact. And besides, we don’t compile templates, but their results. :)

Consider the following example:

Note that this file doesn’t have the declaration part. If we run duckity on it, nothing will be merged. On the other hand, we can provide the datasources via command line. Thanks to Aditya for the suggestion!

We provide both --datasource/--identifier pairs (or its shorter form -d/-i and duckity does the dirty job for us:

That’s it. I plan to release this humble tool in a few days, under the New BSD license. I’ll update this blog post with the link to the proper GitHub repository, with the binary available for download and also the sources. :)

6 thoughts

  1. hi, that is great–I need to look at Velocity. I do something like this, but using Cheetah templates, and tags that look like this:
    \Template[student=Bob, grade=71]{student}

    Cheetah applies the first argument as the data dictionary to the template named as the argument. Your way is more flexible.
    thanks,
    –Tim

Leave a Reply

Your email address will not be published. Required fields are marked *