String replace in FTL with a specific word - freemarker

I need to replace a specific string in a URL in FTL.
Code 1:
<#assign pageUrlWithParams= "https://sample.com/category?filter=low&navParam=Appliances&skrLocale=en_US&t=1"/>
<#if pageUrlWithParams?? && pageUrlWithParams != '' && pageUrlWithParams?contains("skrLocale")>
<#assign pageUrlWithParams = pageUrlWithParams?replace('skrLocale','')/>
</#if>
${pageUrlWithParams}
Code 2 :
<#assign pageUrlWithParams= "https://sample.com/category?filter=low&navParam=Appliances&skrLocale=en_FR&t=2"/>
<#if pageUrlWithParams?? && pageUrlWithParams != '' && pageUrlWithParams?contains("skrLocale")>
<#assign pageUrlWithParams = pageUrlWithParams?replace('skrLocale','')/>
</#if>
${pageUrlWithParams}
I need to remove "skrLocale=en_US" and "skrLocale=en_FR" from pageUrlWithParams.
Known text is "skrLocale", using this I need to remove "skrLocale=en_US" and "skrLocale=en_FR".
Because of en_US and en_FR, i dont know how to take that that part after equals.
Some suggest an answer please. Thanks in advance

Using regular expressions ('r' as 3rd parameter to ?replace) is the key. Note that due to the complexity of URL syntax, we need to handle two edge cases (skrLocale is the first parameter, and skrLocale is the only parameter), which the below function fulfills. However, it doesn't handle %xx escapes in the parameter name (which you might don't care about):
<#function removeSkrLocale url>
<#return url?replace(r'([&\?])skrLocale=[^&]*&?', '$1', 'r')?remove_ending('?')>
</#function>
${removeSkrLocale(pageUrlWithParams)}
Of course you can do this without #function as well, directly inside the ${}, but it's reusable and more self documenting this way.

I would use a Freemarker function (this is a simple version, can be improved)
<#function remove_param_if_value_equals pageUrlWithParams paramName, paramValues >
<#if pageUrlWithParams?has_content && pageUrlWithParams?contains(paramName)>
<#list paramValues as paramValue>
<#local paramNameAndValue = paramName + "=" + paramValue />
<#local pageUrlWithParams = pageUrlWithParams?replace(paramNameAndValue,'')/>
</#list>
</#if>
<#return pageUrlWithParams />
</#function>
<#assign pageUrlWithParams= "https://sample.com/category?filter=low&navParam=Appliances&skrLocale=en_US&t=1"/>
<#assign pageUrlWithParams = remove_param_if_value_equals(pageUrlWithParams, "skrLocale", ["en_US", "en_FR"]) />
${pageUrlWithParams}
The code that does the business remains isolated and can be altered/improved later on.
(For example there is that double "&" that could be cleaned)

I don't know about FTL. But if you need to replace parameter skrLocale in your URL, I think below is good pattern you can use:
(skrLocale(.*?)&)
With (.*?) is called lazy, it match from skrLocale to nearest &. Therefore, with your case, it will match skrLocale=en_US& and skrLocale=en_FR& .

Related

Freemarker assign value to variable

I'm having trouble while trying to assign value to a variable using Freemarker.
<#if size??>
<#assign num=size?number>
<#if (num>0)>
<#list 0..num-1 as i>
<#if .vars['abc'+i?c] = "test">
<#assign .vars['abc'+i?c] = .vars['abc'+i?c]?replace("test","Test")>
</#if>
</#list>
</#if>
This is the error message: Encountered ".", but was expecting one of:
STRING_LITERAL
RAW_STRING
ID
Can anyone help me with this?
Thank you.
You can only write top-level variables in a FreeMarker template. Also you can't assign to a variable with dynamically constructed name, except with an ?interpret hack: <#"<#assign abc${i?c} = abc${i?c}?reaplce('test', "Test")>"?interpret />. Obviously that's horrid... BTW, what's the use case here? Why do you need to assign to dynamically constructed variable names?

Freemarker check if variable exists and is different than zero

${something.id!} can help me check the variable exists. But what if I also want to check if it is not 0?
[#if something.id?? && something.id!=0]
${something.id}
[/#if]
Or with the standard freemarker syntax:
<#if something.id?? && something.id!=0>
${something.id}
</#if>
You could use an if statement such as
<#assign id0=0>
<#assign id1=1>
id0=<#if id0?? && id0 != 0>${id0}</#if>,
id1=<#if id1?? && id1 != 0>${id1}</#if>,
idx=<#if idx?? && idx != 0>${idx}</#if>
Output
id0=, id1=1, idx=
Or better yet use a function. This function uses a default of zero for the value so that it can handle missing/null values. It will return a zero length string if the value is zero or null otherwise the original value.
<#function existsNotZero value=0>
<#if value == 0>
<#return "">
<#else>
<#return value>
</#if>
</#function>
<#assign id0=0>
<#assign id1=1>
id0=${existsNotZero(id0)},
id1=${existsNotZero(id1)},
idx=${existsNotZero(idx)}
Output
id0=, id1=1, idx=
Like this:
<#if (something.id!0) != 0>${something.id}</#if>

How to check if a given value is a number or not in Freemarker?

In freemarker how do I find out if a particular value is a number or not. Is there any specific method to check if a given value is a number or not in freemarker?
<#if (link_data.canonical)!?matches(".*/sites/.*") && (pageData.ar.gP)?has_content >
<#if (pageData.ar.gP)?is_number >
<link rel="author" href="https://plus.google.com/${(pageData.ar.gP)!}" />
<#else>
<link rel="ar" href="https://plus.google.com/+${(pageData.ar.gP)!}" />
</#if>
</#if>
The above code does not work for me.
Yeah, Freemarker has some built-ins for that. You can do id?is_number or ?is_string or ?is_boolean, etc.
source: http://freemarker.org/docs/ref_builtins_expert.html#ref_builtin_isType
Try id?is_number?c or ?is_string?c or ?is_boolean?c
just add ?c at the end
You can check if the number is Integer with this function:
<#assign test = 2>
${isInteger(test)?c}
<#function isInteger number>
<#return number?floor == number>
</#function>
returns true

does freemarker support show all variable in data-model?

I want to see all variables in freemarker data-model, just like struts2 debug tag to show value stack.
Is there a way for freemarker to do this ?
There's no universal solution possible for that, but you can try
<#list .data_model?keys as key>
${key}
</#list>
This works if the data-model is just a usual Map or JavaBean, but for more sophisticated data-models it's up to the data-model implementation if it supports ?keys and if it indeed returns everything.
You also have the variables that you set in the templates, which can be listed like above, only instead of .data_model use .globals, .namespace (which means the current template namespace) and .locals.
You may also have Configuration-level shared variables, and there's no way to list those purely from FTL (you could write a custom TemplateMethodModel for it that reads Configuration.getSharedVariableNames() though, and call it from the template).
Of course, ideally, FreeMarker should have a <#show_variables> directive or something, that does a best effort to show all this... but sadly there is no such thing yet.
An even more detailed way would be this macro:
<#macro dump_object object debug=false>
<#compress>
<#if object??>
<#attempt>
<#if object?is_node>
<#if object?node_type == "text">${object?html}
<#else><${object?node_name}<#if object?node_type=="element" && object.##?has_content><#list object.## as attr>
${attr?node_name}="${attr?html}"</#list></#if>>
<#if object?children?has_content><#list object?children as item>
<#dump_object object=item/></#list><#else>${object}</#if> </${object?node_name}></#if>
<#elseif object?is_method>
#method
<#elseif object?is_sequence>
[<#list object as item><#dump_object object=item/><#if !item?is_last>, </#if></#list>]
<#elseif object?is_hash_ex>
{<#list object as key, item>${key?html}=<#dump_object object=item/><#if !item?is_last>, </#if></#list>}
<#else>
"${object?string?html}"
</#if>
<#recover>
<#if !debug><!-- </#if>LOG: Could not parse object <#if debug><pre>${.error}</pre><#else>--></#if>
</#attempt>
<#else>
null
</#if>
</#compress>
</#macro>
<#dump_object object=.data_model/>
This gives you a full dump of your data model.
Here is #lemhannes macro definition modified to emit JSON. Lightly tested on a fairly simple datamodel
<#macro dump_object object debug=false>
<#compress>
<#if object??>
<#attempt>
<#if object?is_node>
<#if object?node_type == "text">${object?json_string}
<#else>${object?node_name}<#if object?node_type=="element" && object.##?has_content><#list object.## as attr>
"${attr?node_name}":"${attr?json_string}"</#list></#if>
<#if object?children?has_content><#list object?children as item>
<#dump_object object=item/></#list><#else>${object}</#if>"${object?node_name}"</#if>
<#elseif object?is_method>
"#method"
<#elseif object?is_sequence>
[<#list object as item><#dump_object object=item/><#if !item?is_last>, </#if></#list>]
<#elseif object?is_hash_ex>
{<#list object as key, item>"${key?json_string}":<#dump_object object=item/><#if !item?is_last>, </#if></#list>}
<#else>
"${object?string?json_string}"
</#if>
<#recover>
<#if !debug>"<!-- </#if>LOG: Could not parse object <#if debug><pre>${.error}</pre><#else>-->"</#if>
</#attempt>
<#else>
null
</#if>
</#compress>
</#macro>

regular expression in freemarker to check if first character in a string is lower case

I am using freemarker to generate a Java class. I am stuck to convert a first character of a string to lower case.
Following is what i tryed but no luck :(
<#function methodName attName >
<#if attName?length > 1 >
<#if attrName(0)?matches([a-z])>
<#return attName>
</#if>
</#if>
</#function>
Thanks.
Try uncap_first:
${"Test"?uncap_first} yields test

Resources