Remove lines in Freemarker output - freemarker

I am generating an odt file using Freemarker template.
My code is:
${(addressline1)!}
${(addressline2)!}
${(addressline3)!}
The problem is that when addresline1 or addressline2 or is empty, it generates an empty line. If all the fields are empty it generates three empty lines.
I have tried the following things:
[#if addressline2??]${(addressline2)!} [/#if]
[#if addressline2?has_content]${(addressline2)!} [/#if]
compress directive
[#compress]
${(addressline1)!}
${(addressline2)!}
${(addressline3)!} [/#compress]
but nothing seems to be working.

Do you edit the template in OpenOffice/LibreOffice or such visual editor? Because then the problem is that although you just see a ${something} there, FreeMarker sees <p>${something}</p>. As it's just a general purpose template text engine, it won't remove the <p></p> that remains there when the inserted text was empty. The application that uses it for ODT should give a way of purging empty paragraphs.

You should be able to get it working by doing this:
<#if addressline1 !== ''>${addressline1}</#if>
Just repeat the process to check for all 3 variables. Alternatively, if they don't exist rather than them just being empty, this code should do the work:
<#if addressline1?exists>${addressline1}</#if>
You can find further documentation in the Freemarker Manual website: http://freemarker.org/docs/index.html

Had the same problem. This is what I ended up with:
<#assign i2 = ""?left_pad(2*4)>
<#assign i3 = ""?left_pad(3*4)>
...
<#if dep.version??>${i3}<version>${dep.version}</version>${"\n"}</#if><#t>
...
Copied from my bug report:
I'd like to be able to have the NEW LINE generated conditionally, with 1 line of template source code.
<#if dep.classifier??><classifier>${dep.classifier}</classifier></#if>
This generates the indent spaces and the newline, no matter what.
{{#t}} and {{#rt}} and {{#lt}} apply at compile time, so they don't care about the condition. So they strip even if the content is there, which I don't want.
I could do this:
<#if dep.classifier??>${" "}<classifier>${dep.classifier}</classifier>${"\n"}</#if><#t>
So that's the request. It can also be anything what helps me achieve that.
Until then, I have to do:
<#if dep.classifier??>
<classifier>${dep.classifier}</classifier>
</#if>
Which I don't like because it makes the templates way longer.
Or
<#if dep.classifier??><classifier>${dep.classifier}</classifier>
</#if><#if dep.classifier??><classifier>${dep.classifier}</classifier>
</#if>
...
Which I don't like because it's messy.
Or
<#if dep.classifier??>${" "}<classifier>${dep.classifier}</classifier>${"\n"}</#if><#t>
Which I don't like because it adds superfluous pieces to the template.

The trick is to place starting <#compress> tag in the previous line of the line you need to remove if empty.
${keep this line always}<#compress>
${remove this line if empty}</#compress>
${keep this line always}
Works with freemarker 2.3.31

Related

Remove preceding or following newline if a conditional directive is empty

Suppose I have a template like this:
some long text
<#if some_condition>
more text
<#elseif another_condition>
different more text
</#if>
trailing long text
If some_condition or another_condition is true, then I get expected output:
some long text
more text
trailing long text
But if both conditions are false, then I get an extra empty line:
some long text
trailing long text
I would prefer to have only one empty line in such case:
some long text
trailing long text
I can achieve this by putting an empty line inside each branch of the condition:
some long text
<#if some_condition>
more text
<#elseif another_condition>
different more text
</#if>
trailing long text
But this makes the template really ugly.
Is there a way to make Freemarker remove an empty line before or after an empty directive block?
Nope. Generating output that's truly whitespace-sensitive (like plain-text documents that humans will read) is generally not practical in FreeMarker, unless the template is quite trivial. What you can do sometimes is post-processing the output, like in this case, remove duplicate line-breaks, but of course that only works if you know that there's never a duplicate line-break intentionally.
By the way, it's a problem with template engines in general. The intent of the template author is often not clear, as the template contains both template source code formatting, and output formatting. And the rabbit hole runs deep, if you also want proper indentation, etc.

freemarker - Retrieve value from sequences

Hoping this issue is easy enough to resolve.
I am trying to retrieve a single value from a sequence using FreeMarker via the advanced form PDF functionality in NetSuite.
Here is a snippet of code:
<#assign getOps>
<#list record.item as assembly>
{item: ${assembly.item}, op: ${assembly.operationsequencenumber}}
</#list>
</#assign>
Number of words: ${getOps?word_list?size}
${getOps}
When I print the above, the following is printed:
I want to be able to capture single values from this sequence, using something similar to ${getOps.item} but an error is fired:
For "." left-hand operand: Expected a hash, but this has evaluated to
a string (wrapper: f.t.SimpleScalar):
==> getOps[2] [in template "template" at line 126, column 3]
---- FTL stack trace ("~" means nesting-related):
Failed at: ${getOps[2].item} [in template "template" at line 126, column 1]
Can you identify the issue here?
Any help is appreciated.
Thanks
You are capturing output into a single string there. So it's unstructured, a flat string, therefore you can't traverse it anymore. If you really need to transform the original list, you need to use ?map (see in the FreeMarker Manual). But Netsuite uses a FreeMarker fork, and I'm not sure if they support ?map.

Freemarker and line break white space

I am using Freemarker to create an email template that contains a shipping address. In my my template I am using an <#if> statement that if address_2 or address_3 has content to print it - if not to not print anything in that line. The problem I am having is that I am getting a blank line break where that address would be and would like to avoid this.
I tried adding the <#compress> but that did not work. Is there an alternate way to do this?
My template below:
<#compress>
${transaction.custbody_company}
${transaction.custbody_address_1}
<#if transaction.custbody_address_2?has_content>${transaction.custbody_address_2}</#if> 
<#if transaction.custbody_address_3?has_content>${transaction.custbody_address_3}</#if>
${transaction.custbody_city_cda}, ${transaction.custbody_state_province} ${transaction.custbody_postal_code}
</#if>
</#compress> 
Put the significant line break inside the #if:
<#if transaction.custbody_address_2?has_content>
${transaction.custbody_address_2}
</#if>
The line breaks after the lonely tags will be removed (see white-space tripping: https://freemarker.apache.org/docs/dgui_misc_whitespace.html#dgui_misc_whitespace_stripping).

Length of Assign variable issue in freemarker

I am using freemarker ..want to find the length of assign variable ..i used size and length function ..but it fails and returns the error ..Please help me in how to find length of the assign variable
Please find the below code i have tried...
Input data --- cusID="a-1242" -- I want to split input data by - and want to store in separate variable through assign function
<#list (it.#CusID[0]!"")?split("-") as c><#if ((c?index) ==0)>
<#assign first>${c}</#assign>
<#assign firstlen = c?size>
</#if>
</#list>
Above code firstlen is used to find the length but it fails to find length
ERROR MESSAGES find below
For "?size" left-hand operand: Expected an extended-hash or sequence
or extended collection, but this has evaluated to a markup_output
(wrapper: f.c.TemplateXMLOutputModel):
As the error message says, first stores XML markup, not just a plain text string. You can't get the length of markup with ?length, as it's not obvious what that means (like if the content of which XML elements matter, what if you have an entity reference, etc.). The reason it's markup is that <#assign first>...</#assign> is not a normal assignment, it's for capturing output, and you are using XML output format. Instead, use normal value assignment: <#assign first = c>. Now first will have the same type as c, string.

Issues with Parameters containg whitespaces

i've the following situation with Freemarker.
When returning to a page in .ftl i send from Java a parameter to the url, similar to "AAA% BBB#DDD.COM", in Java it is ok.
When looking at the Url it does instead Write : "AAA%25+BBB#DDD.COM" And then with the following code:
<#if myCase??>
value = ${user}
</#if>
It does write in my html field "AAA%" but not the remaining.
How can i try to solve this issue?
Thanks in advance.
EDIT: After further investigations i do see the code i put before does write this on the Html:
value="AAA%" BBB#CCC.com=""
EDIT2: Let'see if i can give you more informations, first of, here's the relevant Java code :
Map mapping = new HashMap();
if(user != null && !user.isEmpty()){
mapping.put("user",user); //EG: AAA% BBB#DDD.COM (Checked in debug)
}
I have an URL similar to : mysite.xx?user=AAA%25+BBB#DDD.COM so the user it's attached as query param of the url.
I do need to reuse the "user" param to repopulate the Form field relative to the username, this is not a valid email i know, but an alias system already installed by the customer does the aliasing system this way.
What could be the cause of the problem
Given your template:
<#if myCase??>
value = ${user}
</#if>
Output written by Freemarker in output-mode HTML results in following:
value = AAA% BBB#DDD.COM
Freemarker does not understand that (from your context) the value of user should be an attribute-value (assignment). Instead it treats the contents of string user as HTML itself (this could be complete HTML-source as input-field, single tags, etc.). It simply pastes the contents of the model at the position in your template where you have set the variable-interpolation ${user}.
The Freemarker-result is no valid HTML (attribute-value pair), because each attribute should adhere some naming-conventions (i.e. no special-characters). When the attribute has a value, it is followed by an equal-sign and this followed by the value enclosed in double-quotes.
So most browsers convert your result into a valid HTML attribute - actually two attributes: value="AAA%" and BBB#CCC.com="". Opened the output-HTML in Firefox, you will see this in Inspector (NOT IN the raw source-view):
<input type="text" value="AAA%" bbb#ddd.com="">
What is not the cause
FreeMarker is auto-escaping (escpecially when in OutputMode HTML) when it writes the final HTML.
#ddekany Thanks for your comment ! It made me reproduce and discover the real cause.
URL encoding/decoding
In Java you could even encode the string variable user. So it converts % (i.e. percent-sign followed by space) into %25+ which is valid to be used inside an URL.
Run this java snippet online on IDEONE to the effects of URL-encoding and URL-decoding.
Solutions
Use either of these solutions to get desired output by fixing the HTML-attribute value-assignment in your template:
(1) use double-quotes:
<#if myCase??>
value="${user}"
</#if>
(2) use some built-ins to transform the plain string-output:
Use some of FreeMarker's built-ins for strings. In your case you could append ?url to the variable-name and use double-quotes around your variable-interpolation within your template, e.g.:
<#if myCase??>
href="mailto:${user?url}"
</#if>
Caution: validate URL or email-address (even parts of it) as early as possible
BBB#DDD.COM is a valid email-address. But % and whitespaces are not allowed inside an email-address.
On the other side # is typically not part of an URL, except as part inside a query-param value. But your user (URL) does not start with http:// etc.
So depending on the use-case/purpose of your (so called URL) user with value AAA% BBB#DDD.COM it could finally represent part of an URL or email-address.
In your special case, said:
populate the form field relative to the username. Model-variable user does not contain a valid email-address. It is used in conjunction with an alias system already installed by the customer. So aliasing will work this way.
Let's suppose the end-user which does later edit the form-field is responsible of making it valid (or a script does this validation).
Anyway bear in mind that an internet-address (like URL/email) needs some validation:
either before written to the final HTML (using Java or Freemarker)
or after being further processed inside your web-page (using JavaScript).
Otherwise it could possibly not yield the desired effect.
See also
Related questions:
Is there any way to url decode variable on Freemarker?
Java URL encoding of query string parameters

Resources