Creating non-trivial documents

In the previous article we've established that basic building block of Templater is context detection and mapping. Context can be simple such as whole document, a single row in a table or list, but it can be a lot more complex, like multiple rows in a table, nested range inside nested range and etc.

The other two basic elements of Templater are formatters and data processors. Let's look more closely at formatters.

Formatters are used for runtime formatting of data and conditional look and feel of document. The simplest example of formatter is :format(XX) metadata. This formatter is useful when you want to pass XX argument to ToString function for currently processed property.

For example: tag [[Item.Price]] can be displayed in Templater with two decimals in multiple ways:

  • If available it's probably best to use document formatting features to format this number with two decimals. While Excel has such formatting features, they can only be used when single tag is used per cell.
  • Using format(N2) in .NET or format(2f) in JVM metadata on tag. This would make tag look like: [[Item.Price]:format(N2)]
  • By preformatting data in object model. If we add GetPrice2() method which returns Price field with two decimals we can use it with [[Item.GetPrice2]] tag.

    This option should be last resort to formatting. If we find ourselves constantly using this option for same feature, this indicates a missing feature in Templater which you can build yourself. Smaller features can be added as plugins, while more complicated can be done with source code licensing.

Another kind of formatter (besides redirecting method call) is conditional look and feel of document. Let's say that we have a collection of objects and wan't to display them in a table. But we wan't to hide the table if it's empty. For this collapse formatter is available. When collapse metadata is found it will inspect provided value and if it's null, empty collection or None it will invoke collapsing of it's context.

How this works in practice? Let's say that we have this model of Loan with Applicant and CoApplicant where Applicant is mandatory, but CoApplicant is optional. Our model looks like:

public class Applicant
{
    public string Name;
    public decimal Income;
}
public class Loan
{
    public decimal Amount;
    public Applicant Applicant;
    public Applicant CoApplicant;
}

From the model we can recognize our context. Since CoApplicant is optional we will add it to resizable object (like table) and add collapse metadata inside it. Here is an example of template for this model:

Loan applicant

So when we run Templater with out data it will populate or remove table for CoApplicant depending on wheater it exists or not.

Templater evolved in .NET so it levreges it's strong points like reification. Since JVM uses erasure Templater can't implement all the features on JVM and some hacks are required when building documents in JVM. If we have a table which we wan't to expand or shirnk depending on the provided data, everything works fine when provided collection has data in it, but when it's empty erasure starts making problems. In .NET Templater can detect tags in a table even when provided collection is empty, but in JVM when empty collection is provided Templater will leave tags unmodified.

We have two options to fix this problem: we can resize this table manually by using low level api ITemplater.resize(int) or we can provide helper tag with collapse metadata which will remove this row.

Let's take a look when it would be useful to add new formatters. Templater supports pictures which means that if you have Image as your property it can replace that tag with provided picture. But what if we have pictures as urls in our model. Let's say that our model looks like:

public class Player
{
    public string Name;
    public Uri RemotePicture;
}

If we wan't to download and insert this picture when we proces our template document we have two options. One is to extend our model and add an Image Picture property in it. This is probably the preferred way in this case. But we could also add link to picture formatter which would read the Uri value and return an Image object from the downloaded stream. In our document tags would look (depending on how we implemented our formatter) like [[RemotePicture]:linkToPicture].

TL;DR

  • formatters are snippets of functionality applied to data
  • they are redirected method calls to reoccurring patters


Back to Documents