blob: 0caffbfea32b6f44ffb24ca1f147d4732e863c4c [file] [log] [blame]
= Template engines
== Introduction
Groovy supports multiple ways to generate text dynamically including `GStrings`, `printf` if you are using Java 5, and <<_markupbuilder, MarkupBuilder>> just to name a few. In addition to these, there is a dedicated template framework which is well-suited to applications where the text to be generated follows the form of a static template.
== Template framework
The template framework in Groovy consists of a `TemplateEngine` abstract base class that engines must implement and a `Template` interface that the resulting templates they generate must implement.
Included with Groovy are several template engines:
- `SimpleTemplateEngine` - for basic templates
- `GStringTemplateEngine` - stores the template as writeable closures (useful for streaming scenarios)
- `XmlTemplateEngine` - works well when the template and output are valid XML
- `MarkupTemplateEngine` - a very complete, optimized, template engine
== SimpleTemplateEngine
Shown here is the `SimpleTemplateEngine` that allows you to use JSP-like scriptlets (see example below), script, and EL expressions in your template in order to generate parametrized text. Here is an example of using the system:
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine1,indent=0]
----
While it is generally not deemed good practice to mix processing logic in your template (or view), sometimes very simple logic can be useful. E.g. in the example above, we could change this:
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine2,indent=0]
----
to this (assuming we have set up a static import for capitalize **inside** the template):
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine3,indent=0]
----
or this:
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine4,indent=0]
----
to this:
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine5,indent=0]
----
=== Advanced Usage Note
If you happen to be embedding your template directly in your script (as we did above) you have to be careful about backslash escaping. Because the template string itself will be parsed by Groovy before it is passed to the the templating framework, you have to escape any backslashes inside GString expressions or scriptlet 'code' that are entered as part of a Groovy program. E.g. if we wanted quotes around __The Big Apple__ above, we would use:
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine6,indent=0]
----
Similarly, if we wanted a newline, we would use:
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine7,indent=0]
----
in any GString expression or scriptlet $$'code'$$ that appears inside a Groovy script. A normal "`\n`" is fine within the static template text itself or if the entire template itself is in an external template file. Similarly, to represent an actual backslash in your text you would need
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine8,indent=0]
----
in an external file or
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine8,indent=0]
----
in any GString expression or scriptlet $$'code'$$. (Note: the necessity to have this extra slash may go away in a future version of Groovy if we can find an easy way to support such a change.)
== GStringTemplateEngine
As an example of using the `GStringTemplateEngine`, here is the example above done again (with a few changes to show some other options). First we will store the template in a file this time:
[source,groovy]
.test.template
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=gstring_template_engine1,indent=0]
----
Note that we used `out` instead of `print` to support the streaming nature of `GStringTemplateEngine`. Because we have the template in a separate file, there is no need to escape the backslashes. Here is how we call it:
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=gstring_template_engine2,indent=0]
----
and here is the output:
----
Dear "Sam Pullara",
So nice to meet you in "The Big Apple".
See you in December,
Groovy-Dev
----
== XmlTemplateEngine
`XmlTemplateEngine` for use in templating scenarios where both the template source and the expected output are intended to be XML. Templates may use the normal `${expression}` and `$variable` notations to insert an arbitrary expression into the template. In addition, support is also provided for special tags: `<gsp:scriptlet>` (for inserting code fragments) and `<gsp:expression>` (for code fragments which produce output).
Comments and processing instructions will be removed as part of processing and special XML characters such as `<`, `>`, `"` and `'` will be escaped using the respective XML notation. The output will also be indented using standard XML pretty printing.
The xmlns namespace definition for gsp: tags will be removed but other namespace definitions will be preserved (but may change to an equivalent position within the XML tree).
Normally, the template source will be in a file but here is a simple example providing the XML template as a string:
[source,groovy]
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=xml_template_engine,indent=0]
----
This example will produce this output:
[source,xml]
----
<document type='letter'>
Dearest
<foo:to xmlns:foo='baz'>
Jochen &quot;blackdrag&quot; Theodorou
</foo:to>
How are you today?
</document>
----
include::{rootProjectDir}/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc[leveloffset=+1]
== Other solutions
Also, there are other templating solutions that can be used along with Groovy, such as http://freemarker.org[FreeMarker], http://velocity.apache.org[Velocity], http://stringtemplate.org[StringTemplate] and others.