Output Filters

Output Filters

Version 2.0 introduced the notion of an StringTemplateWriter/IStringTemplateWriter. All text rendered from a template goes through one of these writers before being placed in the output buffer. Terence added this primarily for auto-indentation for code generation, but it also could be used to remove whitespace (as a compression) from HTML output. Most recently, in 2.3, Terence updated the interface to support automatic line wrapping. If you don't care about indentation, you can simply subclass AutoIndentWriter and override write()/Write():

Java

public interface StringTemplateWriter {
    public static final int NO_WRAP = -1;

    void pushIndentation(String indent);

    String popIndentation();

    void pushAnchorPoint();

    void popAnchorPoint();

    void setLineWidth(int lineWidth);

    /** Write the string and return how many actual chars were written.
     *  With autoindentation and wrapping, more chars than length(str)
     *  can be emitted.  No wrapping is done.
     */
    int write(String str) throws IOException;

    /** Same as write, but wrap lines using the indicated string as the
     *  wrap character (such as "\n").
     */
    int write(String str, String wrap) throws IOException;

    /** Because we might need to wrap at a non-atomic string boundary
     *  (such as when we wrap in between template applications
     *   <data:{v|[<v>]}; wrap>) we need to expose the wrap string
     *  writing just like for the separator.
     */
    public int writeWrapSeparator(String wrap) throws IOException;

    /** Write a separator.  Same as write() except that a \n cannot
     *  be inserted before emitting a separator.
     */
    int writeSeparator(String str) throws IOException;
}

C#

public interface IStringTemplateWriter 
{
    void PushIndentation(string indent);

    string PopIndentation();

    void Write(string str);
}

Python

class StringTemplateWriter(object):
    NO_WRAP = -1
    
    def __init__(self):
        pass

    def pushIndentation(self, indent):
        raise NotImplementedError

    def popIndentation(self):
        raise NotImplementedError

    def pushAnchorPoint(self):
        raise NotImplementedError

    def popAnchorPoint(self):
        raise NotImplementedError

    def setLineWidth(self, lineWidth):
        raise NotImplementedError

    def write(self, str, wrap=None):
        raise NotImplementedError

    def writeWrapSeparator(self, wrap):
        raise NotImplementedError

    def writeSeparator(self, str):
        raise NotImplementedError

Here is a "pass through" writer that is already defined:

Java

/** Just pass through the text */
public class NoIndentWriter extends AutoIndentWriter {
    public NoIndentWriter(Writer out) {
        super(out);
    }

    public void write(String str) throws IOException {
	    out.write(str);
    }
}

C#

/** Just pass through the text */
public class NoIndentWriter : AutoIndentWriter 
{
    public NoIndentWriter(TextWriter output) :base(output) 
    {
    }

    public void Write(string str)
    {
	    output.Write(str);
    }
}

Python

class NoIndentWriter(stringtemplate3.AutoIndentWriter):
    """Just pass through the text"""
    def __init__(self, out):
        super(NoIndentWriter, self).__init__(out)

    def write(self, str):
        self.out.write(str)
        return len(str)

Use it like this:

Java

StringWriter out = new StringWriter();
StringTemplateGroup group =
                new StringTemplateGroup("test");
group.defineTemplate("bold", "<b>$x$</b>");
StringTemplate nameST = new StringTemplate(group, "$name:bold(x=name)$");
nameST.setAttribute("name", "Terence");
// write to 'out' with no indentation
nameST.write(new NoIndentWriter(out));
System.out.println("output: "+out.toString());

C#

StringWriter output = new StringWriter();
StringTemplateGroup group = new StringTemplateGroup("test");
group.DefineTemplate("bold", "<b>$x$</b>");
StringTemplate nameST = new StringTemplate(group, "$name:bold(x=name)$");
nameST.SetAttribute("name", "Terence");
// write to 'out' with no indentation
nameST.Write(new NoIndentWriter(output));
Console.Out.WriteLine("output: "+output.ToString());

Python

out = StringIO()
group = stringtemplate3.StringTemplateGroup("test")
group.defineTemplate("bold", "<b>$x$</b>")
nameST = stringtemplate3.StringTemplate("$name:bold(x=name)$", group=group)
nameST["name"] = "Terence"
# write to 'out' with no indentation
nameST.write(NoIndentWriter(out))
print "output:", str(out)

Instead of using nameST.toString(), which calls write with a string write and returns its value, manually invoke write with your writer.

If you want to always use a particular output filter, then use

Java

StringTemplateGroup.setStringTemplateWriter(Class userSpecifiedWriterClass);

C#

StringTemplateGroup.SetStringTemplateWriter(Type userSpecifiedWriterClass);

Python

stringtemplate.StringTemplateGroup.setStringTemplateWriter(userSpecifiedWriterClass)

The StringTemplate.toString() method is sensitive to the group's writer class.