theHacker
theHacker

Reputation: 4043

Using FreeMarker built-ins with assigned variables over multiple lines

I am trying to use a built-in in FreeMarker, but I am having problems with a certain situation.

Why does this work

<#assign foo="bar" />
${foo?trim}

but not that

<#assign foo>
    bar
</#assign>
${foo?trim}

?

I am getting this exception:

FreeMarker template error:
For "?trim" left-hand operand: Expected a string or something automatically convertible to string (number, date or boolean), but this has evaluated to a markup_output (wrapper: f.c.TemplateXHTMLOutputModel):
==> foo  [in template "template.ftl" at line 23, column 7]

----
FTL stack trace ("~" means nesting-related):
    - Failed at: ${foo?trim}  [in template "faq.ftl" at line 23, column 5]
----

Java stack trace (for programmers):
----
freemarker.core.NonStringException: [... Exception message was already printed; see it above ...]
    at freemarker.core.EvalUtil.coerceModelToTextualCommon(EvalUtil.java:494)
    at freemarker.core.EvalUtil.coerceModelToStringOrUnsupportedMarkup(EvalUtil.java:407)
    at freemarker.core.Expression.evalAndCoerceToStringOrUnsupportedMarkup(Expression.java:107)
    at freemarker.core.BuiltInForString.getTargetString(BuiltInForString.java:34)
    at freemarker.core.BuiltInForString._eval(BuiltInForString.java:29)
    at freemarker.core.Expression.eval(Expression.java:81)
    at freemarker.core.DollarVariable.calculateInterpolatedStringOrMarkup(DollarVariable.java:96)
    at freemarker.core.DollarVariable.accept(DollarVariable.java:59)
    at freemarker.core.Environment.visit(Environment.java:362)
    at freemarker.core.Environment.visitAndTransform(Environment.java:460)
    at freemarker.core.BlockAssignment.accept(BlockAssignment.java:55)
    at freemarker.core.Environment.visit(Environment.java:326)
    at freemarker.core.Environment.visit(Environment.java:332)
    at freemarker.core.Environment.process(Environment.java:305)
    at freemarker.template.Template.process(Template.java:384)
    ...

I need the second form because bar can be multiple lines long.
How can I accomplish this?

Upvotes: 2

Views: 2764

Answers (1)

ddekany
ddekany

Reputation: 31112

Capturing assignments are not for creating multi-line string values. That can be achieved with <#assign foo="line 1\nline 2">, or you can just use a real line-break instead of the \n (unlike Java, FreeMarker allows that):

<#assign foo="
  bar
  baaz
">
${foo?trim}

Capturing was made for capturing fragments of output, so that it can be passed around and eventually printed. You have captured markup because of your output_format (XHTML), and it doesn't mater if it happens to only contains Character Data, it's not plain text anymore, and so string operations (which aren't aware of the rules of the captured markup and hence could corrupt it) are banned on it.

If you really need to do this, you can force the captured markup to string and so you can trim it: ${foo?markup_string?trim}. But know that bad things will happen if you have captured any tags or entity references, unless you also apply ?no_esc on the trimmed result.

Upvotes: 6

Related Questions