Search code examples
stringtemplatestringtemplate-4

Custom format functions for StringTemplate4


I would like to know how to create a custom format function for string template. Let say I have the following code:

render(attributes) :: <<
<html>
    $atributes: {
        <div> $customformat(atribute.name)$</div>
    }


</html>
>>

customformat(name) ::= <<
    $name; format="upper"$
>>

Currently the behaviour of the function customformat is:

Input: "hello world" -> Output: "HELLO WORLD"

And I would like to modify the customformat function so the output is something like the following:

Input: "hello world" -> Output: "HELLO_WORLD"


Solution

  • As far as I'm aware this isn't possible, since StringTemplate is all about strict model-view separation.

    Instead, I think you'd be better off having a getter in the controller that returned the formatted string.

    You might find this question useful: embed java code inside a template


    Actually, I found a simple way of doing this which avoids the need for the formatted string getters:

    You need to create a new StringRenderer which can format the string in the way you want.

    public class MyStringRenderer extends StringRenderer
    {
        @Override
        public String toString(Object o, String formatString, Locale locale) {
            if (!("upperAndUnder".equals(formatString)))
                return super.toString(o, formatString, locale);
           // we want upper case words with underscores instead of spaces
            return ((String) o).replaceAll(" ", "_").toUpperCase(locale);
        }
    }
    

    Then you'll need to let the template group know about the new renderer:

    public static void main(String[] args) {
        STGroup templates = new STGroupFile("test.stg");
        templates.registerRenderer(String.class, new MyStringRenderer());
        ST renderTemplate = templates.getInstanceOf("render");
        renderTemplate.add("attributes", new String[]{"blahh blahh I'm a string", "I'm another string"});
        System.out.println(renderTemplate.render());
    }
    

    Then you can call the format function like you did before, but pass "upperAndUnder" as the parameter:

    group test;
    
    delimiters "$","$"
    
    render(attributes) ::= <<
    <html>
        $attributes:{ attribute | <div> $customFormat(attribute)$</div>}; separator="\n"$
    
    
    </html>
    >>
    
    customFormat(name) ::= <<
        $name; format="upperAndUnder"$
    >>
    

    which prints:

    <html>
        <div> BLAHH_BLAHH_I'M_A_STRING</div>
        <div> I'M_ANOTHER_STRING</div>
    
    
    </html>
    

    FYI:

    Here's the original StringRenderer code

    More info on Renderers