Class MarkupBuilder<T>

java.lang.Object
com.googlecode.jatl.MarkupBuilder<T>
Type Parameters:
T - This should always be parameterized with the exact same class that is extending the MarkupBuilder to support fluent style.
Direct Known Subclasses:
GeneratedHtmlBuilder

public abstract class MarkupBuilder<T> extends Object
Fluent styled markup builder that writes to a Writer.

Description

Writes XML markup to a Writer. The Builder part of the name is somewhat misleading as this class does not store or keep track of all the markup objects created but rather writes using the writer as soon as it can. Thus the order of operations performed on this class is very important and should follow the order that you would write the markup.

Usage

You should not use this class directly but rather one of its subclasses that is parameterized with itself (see Extending). You generally define the markup you want to write using Java anonymous classes that extend either a MarkupBuilder or MarkupWriter. Markup builders write immediately to a writer where as a markup writer writes when told to. But again in both cases you generally define the markup with an anonymous class.

For examples of use its best to see Html for an XHTML builder which will write XHTML markup immediatly or HtmlWriter which allows you to define XHTML markup then write it later.

Markup writers are more useful for MVC frameworks and builders are more for convenience.

Extending

If you would you would like to make your own builder you should subclass this class or a subclass that has generic parameter (<T>).

The custom builder should be parameterized to itself to support fluent style.

Example:

public class MyMarkup extends MarkupBuilder<MyMarkup> {

        public MyMarkup(Writer builder) {
                super(builder);
        }
        protected MyMarkup getSelf() {
                return this;
        }
        
        public MyMarkup myTag() {
                return start("myTag");
        }
}
 

Composition

Besides the extending method above you can achieve composition of markup builders by using MarkupWriter's instead. See MarkupWriter.

See write(MarkupWriter...).

Writing tags and attributes

See start(String) and end() for writing tags. See attr(String...) for writting attributes.

Variable expansion

Simple named variable replacements are supported through the
${...}
notation. See bind(String, Object), and text(String).

Pretty Printing aka Indenting

See #indent Indenter. For most cases you can use SimpleIndenter

Namespaces

You can either manually maintain namespaces and namespace prefixes by setting the correct attributes and then writing tags with the namespace prefix. Example: start("prefix:tagName"). Or you can use the namespace methods: ns(), ns(String), xmlns(String, String) The following Nested builders are very helpful for working with multiple XML schemas.

Nested builders

Nested builders are an easy way to allow different markup styles to coexist elegantly. An example might be HTML with in XSL. You would have an HTML builder nested inside the XSL builder.

Example:

 new Xslt(writer) {{
        ns("xsl");
        template().match("stuff");
                new Html(writer) {{
                        html().body().done();
                }}
        done();
 }}
 
See MarkupBuilder(MarkupBuilder).

Thread safety

This class and subclasses are not thread safe. One way to make a builder thread safe is to synchronize on the passed in writer:
 synchronize(writer) {
    new SomeBuilder(writer) {{ }}; 
 }
 

Efficiency and Validation

To keep the builder efficient and elegant there is very little XML validation. There is no guarantee that the markup generated will always be well formed. Generally Text will be escaped appropriately.

For those seriously concerned with performance an appropriate implementation of Writer should be given to the builder.

For example: In a single threaded environment where you are writing to memory Commons IO StringBuilderWriter is a good choice over StringWriter.

On the other hand if you are writing very large XML document to a file or network socket PrintWriter is probably a better choice.

See Also:
  • Field Details

    • tagStack

      private Stack<MarkupBuilder.Tag> tagStack
    • writer

      private Writer writer
    • attributes

      private Map<String,String> attributes
    • bindings

      private Map<String,Object> bindings
    • previousBuilder

      private MarkupBuilder<?> previousBuilder
    • depth

      private int depth
    • namespacePrefix

      private String namespacePrefix
    • previousIndenter

      private Indenter previousIndenter
    • indenter

      private Indenter indenter
    • q

      private static final String q
      See Also:
    • indentOn

      protected static Indenter indentOn
      A default indenter that uses tabs.
    • indentOff

      protected static Indenter indentOff
      An indenter that turns off indenting.
    • indentSameLine

      protected static Indenter indentSameLine
      Indents by keeping a tag pair on the same line.
  • Constructor Details

    • MarkupBuilder

      public MarkupBuilder(Writer writer)
      Create a builder using the given writer.
      Parameters:
      writer - never null.
    • MarkupBuilder

      public MarkupBuilder(MarkupBuilder<?> builder)
      Create a nested builder from given builder. Make sure done() is called when finished with the nested builder so that the parent builder can resume using the writer.
      Parameters:
      builder - parent builder, never null.
      See Also:
    • MarkupBuilder

      protected MarkupBuilder()
      Use for deferred writer. The writer should be set before the builder is used.
      See Also:
    • MarkupBuilder

      public MarkupBuilder(MarkupBuilder<?> builder, boolean nested)
      Create a nested builder from a builder or resume from a builder.
      Parameters:
      builder - never null.
      nested - true means nested, false means resuming.
  • Method Details

    • getSelf

      protected abstract T getSelf()
      Needed for fluent style and Java parameterization limitations. Almost all public methods should return whatever this method returns.

      Most implementations only have to do:

       return this;
       
      Returns:
      the current builder which is usually this object.
    • ns

      public final T ns()
      Restores the current namespace prefix to whatever the surrounding tags prefix is. To set the namespace to the default namespace call:

      ns(null);

      Returns:
      maybe null.
      See Also:
    • ns

      public final T ns(String prefix)
      Sets the current namespace prefix. If a tag is started when the prefix is set to a non-null non-empty string, the prefix will be added in front of the tag.

      Example:

       ns("html").div().end();
       
      Result:

       <html:div></html:div>
       
      Parameters:
      prefix - maybe null
      Returns:
      this, not null.
    • setWriter

      public final void setWriter(Writer writer)
      Sets the writer after the builder has been created. Only useful with the empty constructor.
      Parameters:
      writer - never null
      Throws:
      IllegalArgumentException - if the writer has already been set or the given writer is null.
    • setDepth

      public final void setDepth(int depth)
      Sets the indent depth after the builder has been created. Only useful with the empty constructor.
      Parameters:
      depth - should greater than or equal 0
    • indent

      public T indent(Indenter indenter)
      Sets the indenter.
      Parameters:
      indenter - if null reverts to the previous builder.
      Returns:
      the builder.
      See Also:
    • getAttributes

      private final Map<String,String> getAttributes()
    • text

      public final T text(String text)
      Writes variable expanded escaped text inside a tag.
      Parameters:
      text - the text will be escaped and variables will be expanded.
      Returns:
      never null.
      See Also:
    • raw

      public final T raw(String text)
      Write text with out escaping or variable expansion.
      Parameters:
      text -
      Returns:
      never null.
      See Also:
    • raw

      public final T raw(String text, boolean expand)
      Writes text with out escaping.
      Parameters:
      text -
      expand - true does variable expansion.
      Returns:
      never null.
    • bind

      public final T bind(String name, Object value)
      Binds a named variables to be used for expansion in attributes and text. Variables are represented with by ${...}.

      Example

       bind("name", "Ferris");
       text("${name}");
       

      Variables are expanded in order and can be referred in a later binding.

       bind("firstName", "Adam");
       bind("lastName", "Gent");
       bind("fullName", "${firstName} ${lastName}");
       
      Parameters:
      name - never null or empty.
      value - maybe null.
      Returns:
      never null.
    • unbind

      public final T unbind(String name)
      Removes a binding. There is no failure if the binding does not exist.
      Parameters:
      name - maybe null.
      Returns:
      never null.
      See Also:
    • bind

      public final T bind(Collection<Map.Entry<String,Object>> nvps)
      Convenience for bind(String, Object)
      Parameters:
      nvps - never null.
      Returns:
      never null.
    • start

      public final T start(String tag)
      Starts a tag using the default closing policy MarkupBuilder.TagClosingPolicy.NORMAL.

      Equivalent to: start("tag", TagClosingPolicy.NORMAL).

      Parameters:
      tag -
      Returns:
      this, never null.
      See Also:
    • start

      public final T start(String tag, MarkupBuilder.TagClosingPolicy policy)
      Starts a tag but does not immediately write it till the next tag is started. The MarkupBuilder.TagClosingPolicy dictates whether or not the tag needs to be closed. Thus end() does not need to be called for all tags.
      Parameters:
      tag - never null or empty.
      policy - never null.
      Returns:
      never null.
      See Also:
    • attr

      public final T attr(String... attrs)
      Adds attributes to the last start tag. Attributes do not need an end() call.
      Parameters:
      attrs - name value pairs. Its invalid for an odd number of arguments.
      Returns:
      never null.
      Throws:
      IllegalArgumentException - odd number of arguments.
    • xmlns

      public final T xmlns(String uri)
      Sets the default namespace on the last started tag.
      Parameters:
      uri - if null nothing will happen.
      Returns:
      this, never null.
      See Also:
    • xmlns

      public final T xmlns(String uri, String prefix)
      Sets an XML namespace.
      Parameters:
      uri - if null nothing will happen.
      prefix - if null or blank will act like the default namespace and no prefix.
      Returns:
      this, never null.
    • end

      public final T end(int i)
      Closes the inputed number of open tags.
      Parameters:
      i - less than zero will do nothing.
      Returns:
      never null.
      See Also:
    • end

      public final T end()
      Closes the last start tag. This is equivalent to </tag> or <tag/> depending on the MarkupBuilder.TagClosingPolicy.
      Returns:
      never null.
      See Also:
    • endAll

      public final T endAll()
      Closes all open tags.
      Returns:
      never null.
      See Also:
    • done

      public final void done()
      Call when completely done with the builder. This is required for nested builders.

      If a builder is used again after done() is called an exception (usually IllegalArgumentException) will be thrown.

    • write

      public final T write(MarkupWriter... writers)
      Writes immediately by passing the writer to each MarkupWriter in the order passed in.
      Parameters:
      writers - never null, null elements passed in are ignored.
      Returns:
      never null.
      Since:
      0.2.2
    • writeCurrentTag

      private void writeCurrentTag()
    • writeStartTag

      private void writeStartTag(MarkupBuilder.Tag t)
    • writeTag

      private void writeTag(String tag, boolean close)
    • writeEndTag

      private void writeEndTag(MarkupBuilder.Tag t)
    • writeAttributes

      private void writeAttributes(Map<String,String> attrs)
    • writeAttr

      private void writeAttr(String name, String value)
    • q

      private String q(String raw)
    • expand

      private String expand(String text)
    • write

      private void write(String raw)
    • checkWriter

      private void checkWriter()
    • createMap

      private Map<String,String> createMap()
    • escapeMarkup

      protected String escapeMarkup(String raw)
      DEPRECATED.
      Parameters:
      raw - maybe null.
      Returns:
      maybe null if null for input.
      See Also:
    • escapeElementMarkup

      protected String escapeElementMarkup(String raw)
      The strategy for escaping element markup. The default is escape for XML.
      Parameters:
      raw - maybe null.
      Returns:
      maybe null if null for input.
      See Also:
    • escapeAttributeMarkup

      protected String escapeAttributeMarkup(String raw)
      The strategy for escaping attribute markup. The default escaping is XML. Entities will be used for white space characters: #xD, #xA, #x9

      CR, newline, and tab, respectively.

      Parameters:
      raw - maybe null.
      Returns:
      maybe null if null for input.
    • writeIndent

      private void writeIndent(MarkupBuilder.Tag t, Indenter.TagIndentSpot spot)