Writing custom taglibs
can easily become messy - explicit HTML, appending ad-hoc strings to a
StringBuilder, adding attributes based on tag arguments can easily turn
relatively simple code into an unmaintainable mess. Not to mention trying to
trace logic paths to track down bugs..
One strategy I have used to simplify construction of HTML in taglibs is to use
to create content is a cleaner way than raw Strings.
which is a base class to provide support to arbitrary nested objects, allowing
the ability to create DSL-like trees.
In this case
MarkupBuilder can help to create structured, nested additions
to an object tree that when rendered to a
String, outputs valid HTML to be
used in place of the tag.
An example (taken from the class documentation):
When rendered to a
StringWriter, will output:
Notice that there are tags (
c), attributes (
a2), and text content included in the objects added to the builder.
If we take the following code:
MarkupBuilder equivalent could be:
I reckon this looks much cleaner, simplier and maintainable.
You can pass in whatever attributes you want to the parameters, and a node
will be attached to the tree with the element name and attributes. The
omitNullAttributes setting I find useful for when an attribute might be
missing (e.g. a value being passed to an input field) without disturbing the
FYI: mkp is a reference to the MarkupBuilderHelper class.
Another example, with nested elements using Twitter Bootstrap CSS classes:
Many of the attributes here are variables passed to the tag function.
So how does using MarkupBuilder help make the code more testable?
Probably the most pain from maintaining taglib tests comes from inconsistencies in formatting - namely:
- Whitespace, indents - makes maintaining text matching assertions tedious
- Use of different quote marks around attributes - while syntactically correct, more tedium, and potentially causing rendering issues when mixed with grails
- Validating HTML At the very least, using MarkupBuilder makes the generated HTML more reliable and consistent, meaning that tests can be more resilient. It is difficult enough when some tests must be reduced to textual comparisons.
By the way, the official grails documentation here outlines the basic ways of testing output using Spock Specification framework.