Freemarker Xml Extension (FMX)
FMX stands for Freemarker XML extension. Freemarker is a famous templating engine which has been used in various products such as Magnolia CMS , CoreMedia CMS or various other applications/tools. Freemarker has an easy to use and most of all a quite intutitive syntax and it provides easy mechanisms for extensions. In contrast to languages such as StringTemplates or Handlebars it’s not logic less. Some people consider this to be a disadvantage as I myself did in my early days of using templating languages. Nevertheless the term logic less is used loosely in my opinion because in general you always end up in writing helper functions to cover the logic so the problem itself has only been moved. But why is the term “logic less” attractive? The answer herefore is quite clear as the support for logic means that the templates might get overloaded with control statements, data manipulation etc and thus the code that’s supposed to be rendered becomes more or less obfuscated. This makes it harder for these templates to be maintained as they are ugly to read (as usual it depends on the skills of the template author to restrict the used logic to a minimum).
That’s where FMX comes into play. FMX is an XML based representation of Freemarker templates. This introduces the following advantages:
- Most of the time we’re only rendering XML like data anyway, so it essentially looks more like the generated outcome.
- It allows us to use special constructs allowing to reduce the usage of common templating scenarios while adding some XML constructs implying these logics (it might become clearer in the following examples).
- FMX comes as a TemplateLoader which means the setup costs and the usage costs are quite low (explained later).
Setup
Using the FMX extension requires the following dependency:
<dependency>
<groupId>com.kasisoft</groupId>
<artifactId>com.kasisoft.libs.fmx</artifactId>
<version>0.7</version>
</dependency>
compile 'com.kasisoft:com.kasisoft.libs.fmx:0.7'
libraryDependencies += "com.kasisoft" % "com.kasisoft.libs.fmx" % "0.7"
The following example demonstrates the usage in case you are using Freemarker directly. It essentially boils down to register the FmxTemplateLoader which actually does the whole work. Apart from the marked lines (NOTE) the other code is pretty standard.
ClassTemplateLoader baseLoader = new ClassTemplateLoader(MyClass.class, "/");
// !!! NOTE: This is the Freemarker TemplateLoader which does the work
FmxTemplateLoader fmxLoader = new FmxTemplateLoader(baseLoader);
// choose the version according to your needs !
Configuration config = new Configuration(Configuration.VERSION_2_3_23);
// !!! NOTE: Here comes the integration of the FmxTemplateLoader
config.setTemplateLoader(fmxLoader);
Template template = config.getTemplate("dodo.fmx", Locale.ENGLISH);
StringWriter writer = new StringWriter();
TemplateModel model = ... // a bean or a hashmap depending on your needs
template.process(model, writer);
System.out.println("generated: " + writer.toString());
Usage
The usage is essentially the same as for ordinary Freemarker templates. The only difference is the .fmx suffix. If you attempt to load a normal .ftl template the loading process is delegated to the parental template loader instance, so the difference is not even recognizable from a developers point of view.
Requirements for fmx templates
- FMX specific elements are using dedicated namespaces and prefixes. They can be changed but it’s best to use the defaults. Furthermore it’s not necessary to explicitly define these namespaces since the templates are artificially being wrapped in order to provide these namespaces. These are the namespaces currently being used (their usage will be explained in later chapters)
- FMX templates must contain wellformed XML which means that a legal HTML construct such as "<meta … >" is invalid. Instead you need to write "<meta …/>" .
- As long as you are not familiar with FMX templates you can enable the debug option on the FmxTemplateLoader. This debug option essentially generates log outputs containing the originally loaded FMX template followed by the translated FTL template.
FMX Constructs
- Handling of empty attributes
- FMX:DEPENDS - Conditional rendering
- FMX:WRAP - Conditional wrapping of content
- FMX:LIST - Iteration of list elements
- FMX:WITH - Abbrevation of expressions
- FMX:DIRECTIVE - Support for Freemarker Directives/Macro calls
- FMX:XESCAPE - Render XML structures and use FMX functionalities
- FMX:INCLUDE - Freemarker Include
- FMX:IMPORT - Freemarker Import
- FMX:SWITCH - Freemarker Switch
- FMX:MACRO - Freemarker Macro
- FMX:DOCTYPE - Doctype generation
- FMX:COMPRESS - Freemarker Compress
- FMX:ESCAPE - Freemarker Escape
Technical overview
The logic is quite simple. The FmxTemplateLoader uses the FmxTranslator to perform the conversions from FMX to FTL. The FmxTranslator itself just invokes a SAX Parser with the DefaultHandler implementation TranslationContext. The TranslationContext is writing the necessary Freemarker code depending on the callback invocation generated by the actual FMX template.
Performance impact
As the FMX functionality is located within the TemplateLoader it only adds a minor time delay when a template is actually being loaded. After that it’s sitting within the Freemarker cache. Since the parsing happens using a SAX parser and the rendering happens to a StringBuilder the conversion process is quite fast. There is a obviously additional time and member required to render a template but I could make out a signifikant difference while profiling (nothing real distinguishable from normal fluctuations). So it’s obvious that the use of FMX has negligible costs (regarding speed and memory).