You need to find a templating engine that supports number formatting, date formatting, and comparison of double values. In addition, you are looking for a templating engine that gives you more control over whitespace and line breaks.
Use FreeMarker, a templating engine with a large built-in feature set that includes support for date and number formatting and intelligent handling of whitespace. The following FreeMarker template creates a summary report for a college course:
<#assign student = enrollment.student > <#assign course = enrollment.course > <#assign exams = enrollment.exams > <#-- This macro assigns a variable named final --> <@final exams=exams/> ${student.firstName} ${student.lastName}, Here is a summary of your performance in ${course.dept} ${course.num} ${course.name}. Class: ${course.name} Professor: ${course.professor} Section: ${enrollment.section?string("000")} Exam, Date, Score, Weight, Grade ----------------------------------------------- <#list exams as exam> <@compress single_line=true> <#assign score = exam.score > ${exam.name}, ${exam.date?date?string.short}, #{exam.score; m1M1}, ${exam.weight}, <@letter score=score/> </@compress> </#list> Final Grade: ${final; m1M1} <@letter score=final/> Your final grade has been submitted to the Registrar. <#macro final exams> <#local num = 0> <#local dem = 0> <#list exams as exam> <#local num = num + (exam.score * exam.weight)/> <#local dem = dem + exam.weight> </#list> <#assign final = num / dem> </#macro> <#macro letter score> <#if (score >= 90)> A <#elseif (score >= 80)> B <#elseif (score >= 70)> C <#elseif (score >= 60)> D <#else> F </#if> </#macro>
To merge this template with data, populate a Map
with named attributes and pass this Map
to the
template.process()
method. The following code creates a
Configuration
object that loads a FreeMarker
template, template.ftl
, from the classpath. An
Enrollment
object is added to the root
Map
, and the output of the template merge is
written to a StringWriter
:
import freemarker.template.Configuration; import freemarker.cache.ClassTemplateLoader; import freemarker.template.ObjectWrapper; import freemarker.template.Template; StringWriter writer = new StringWriter( ); // Create a Configuration object for FreeMarker Configuration cfg = Configuration.getDefaultConfiguration( ); cfg.setTemplateLoader(new ClassTemplateLoader(getClass( ))); cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER); // The root Map serves as a Context for our template engine Map root = new HashMap( ); root.put("enrollment", testEnrollment( )); // A template is processed with a Map and output is sent to a Writer. Template template = cfg.getTemplate("template.ftl"); template.process(root, writer); System.out.println("output: " + writer.toString( ));
The template is rendered, and the following output is printed to the console:
Stefan Winz, Here is a summary of your performance in ECON 201 Macroeconomics. Class: Macroeconomics Professor: Dr. Stephen H. Jones Section: 002 Exam, Date, Score, Weight, Grade ----------------------------------------------- T01, 01/10/03, 93.4, 1.00, A T02, 01/27/03, 85.5, 1.50, B Mid, 02/15/03, 98.0, 2.00, A+ T03, 03/31/03, 71.5, 1.00, C- T04, 04/10/03, 88.5, 1.50, B+ Fin, 05/05/03, 95.0, 4.00, A Final Grade: 91 A- Your final grade has been submitted to the Registrar. Have a great Summer!
In the template for this recipe, three objects are retrieved from an
Enrollment
object: a course
property, a student
property, and a
List
of Exam
objects. Three
variables—course
,
student
, and exam
—are
created with the <#assign>
directive,
<#assign
variable = expression >
. Properties are referenced as they were referenced in
JEXL and Velocity; ${enrollment.student}
is used
to access the student
property on the
enrollment
. A student’s final
course grade is calculated in a macro by calling
<@final
exams=exams/>
.
This macro assigns a global template variable,
final
, which is formatted to one decimal place
with the expression ${final; m1M1}
.
At first glance, a FreeMarker template looks very similar to a Velocity template, but there are several interesting features not available in Velocity:
Our date object was formatted with the expression
${exam.date?date?string.short}
.
?date
instructs the engine to take only the day,
month, and year portion of the date, and
?string.short
tells FreeMarker to use the
locale’s short-date format (12/31/04). You can also
specify your own date format using the same syntax you would use in
SimpleDateFormat
. The expression
${exam.date?string("MM-dd-yyyy hh:mm:ss")}
would
output a string similar to “12-31-2004
04:23:22.”
FreeMarker can compare dates and numbers, both integer and floating point.
Macros can be invoked with named parameters. For example, the
@letter
macro can be invoked with named
parameters: <@letter
team="Boston
Celtics
"
score="34"></@letter>
.
Here are some other interesting FreeMarker features not available in Velocity:
Namespaces for variables and macros
“Built-in” functions for basic types
Access to XML document objects
Improved looping
Local macro variables
Built-in XML and HTML escaping
Velocity has a very large user base, and it is the right tool for a simple job. FreeMarker has some very useful features “out of the box,” while Velocity requires developers to install supporting utilities or write these “extensions” from scratch. Some developers will prefer a templating language that is simple by design, and others need a tool that is substantially more complex. There is a case to be made for simplicity. If you working on a large team, where you have content authors who need to create and maintain your templates, you may want to use a technology like Velocity that embraces simplicity. Open source communities benefit from healthy cross-pollination of ideas and competition, and FreeMarker was developed as an alternative to Jakarta Velocity; they even have a feature comparison page (http://www.freemarker.org/fmVsVel.html).
It is beyond the scope of this book to drill into the details of every FreeMarker feature listed in this recipe. If you are interested in learning more about FreeMarker, take a look at the online documentation (http://www.freemarker.org/docs/index.html).
If you are using Jakarta Velocity and wish to migrate your templates to FreeMarker, the FreeMarker team has written a utility, code named “US Cavalry,” which will automatically translate your VTL templates to FTL templates. To obtain “US Cavalry,” see http://www.freemarker.org/usCavalry.html.
3.143.5.15