Freemarker: assign interpreted variable to other variable - freemarker

I would like to assign the result of an interpreted variable to another varialbe.
Freemarker provides the built-in ?interpret to interpret a variable holding an ftl expression. See http://freemarker.sourceforge.net/docs/ref_builtins_expert.html#ref_builtin_interpret
If I do
[#if var1?has_content && var1?starts_with(r"${")]
[#assign interpretedValue = var1?interpret!""]
[#interpretedValue/]
[/#if]
The [#interpretedValue/] will output the interpreted value.
However, I'd like to assign the value of the interpreted value to a variable (in order to do some things such as ?has_content in the rest of my code). I tried [#assign varInterpretedValue = #interpretedValue] but this does not work.
Is this possible?

Yes, like this:
[#assign capturedOutput][#(var1!'')?interpret /][/#assign]
${capturedOutput} [#-- Attention! Put this into #noescape if you are inside #escape! --]
Note that the !'' suff has to before the ?interpret, otherwise it doesn't do anything (since the result of ?interpret is always non-null).

Related

How to have ruby conditionally check if variables exist in a string?

So I have a string from a rendered template that looks like
"Dear {{user_name}},\r\n\r\nThank you for your purchase. If you have any questions, we are happy to help.\r\n\r\n\r\n{{company_name}}\r\n{{company_phone_number}}\r\n"
All those variables like {{user_name}} are optional and do not need to be included but I want to check that if they are, they have {{ in front of the variable name. I am using liquid to parse and render the template and couldn't get it to catch if the user only uses 1 (or no) opening brackets. I was only able to catch the proper number of closing brackets. So I wrote a method to check that if these variables exist, they have the correct opening brackets. It only works, however, if all those variables are found.
here is my method:
def validate_opening_brackets?(template)
text = %w(user_name company_name company_phone_number)
text.all? do |variable|
next unless template.include? variable
template.include? "{{#{variable}"
end
end
It works, but only if all variables are present. If, for example, the template created by the user does not include user_name, then it will return false. I've also done this loop using each, and creating a variable outside of the block that I assign false if the conditions are not met. I would really, however, like to get this to work using the all? method, as I can just return a boolean and it's cleaner.
If the question is about how to rewrite the all? block to make it return true if all present variable names have two brackets before them and false otherwise then you could use something like this:
def validate_opening_brackets?(template)
variables = %w(user_name company_name company_phone_number)
variables.all? do |variable|
!template.include?(variable) || template.include?("{{#{variable}")
end
end
TL;DR
There are multiple ways to do this, but the easiest way I can think of is to simply prefix/postfix a regular expression with the escaped characters used by Mustache/Liquid, and using alternation to check for each of your variable names within the template variable characters (e.g. double curly braces). You can then use String#scan and then return a Boolean from Enumerable#any? based on the contents of the Array returned by from #scan.
This works with your posted example, but there may certainly be other use cases where you need a more complex solution. YMMV.
Example Code
This solution escapes the leading and trailing { and } characters to avoid having them treated as special characters, and then interpolates the variable names with | for alternation. It returns a Boolean depending on whether templated variables are found.
def template_string_has_interpolations? str
var_names = %w[user_name company_name company_phone_number]
regexp = /\{\{#{var_names.join ?|}\}\}/
str.scan(regexp).any?
end
Tested Examples
template_string_has_interpolations? "Dear {{user_name}},\r\n\r\nThank you for your purchase. If you have any questions, we are happy to help.\r\n\r\n\r\n{{company_name}}\r\n{{company_phone_number}}\r\n"
#=> true
template_string_has_interpolations? "Dear Customer,\r\n\r\nThank you for your purchase. If you have any questions, we are happy to help.\r\n\r\n\r\nCompany, Inc.\r\n(555) 555-5555\r\n"
#=> false

Apache freemarker template assign and compare values

I am assigning value to a variable i_type using below assign statement.
<#assign i_type>
<#if x.has("type")>
<#if x.type == "ABC">"ABC"<#else>"${x.type?lower_case}"</#if>
<#else>"pqr"</#if>
</#assign>
Then I want to assign a variable in ftl conversion as:
"final_type" : <#if i_type?has_content && i_type == "pqr">1<#else>0</#if>
But value of final_type is always coming out to be 0 in all cases.
I explicitly printed value of i_type and even though it was "pqr" but condition is always coming out to be false.
what should be changed?
Why the original example doesn't work is that you have quotation marks in <#else>"pqr"</#if>, and on the other similar places. That way the captured value itself will contain the quotation marks, because the nested content of FreeMarker directives is not expressions, instead it's just like top-level template content. So just write <#else>pqr</#if>.
Anyway, a better way to write what you did is this:
<#assign i_type =
x.has("type")?then(
(x.type == "ABC")?then(x.type, x.type?lower_case),
"pqr"
)
>
You also don't need the i_type?has_content condition in the second piece of code, since something is always assigned to i_type. (But even if in reality it isn't, you can write i_type! to default a missing value to "".) So that can be written like this:
"final_type" : ${(i_type == "pqr")?then("1", "0")}
Once I used
"final_type" : <#if i_type?has_content && i_type?eval == "pqr">1<#else>0</#if>
it worked fine.

Freemarker assigning escaped ${expression} to a variable

I need to assign an escaped ${expression} to a variable in Freemarker
From the question here, it's clear that we can escape the $ sign in this way
${r"${expression}"}
This works perfectly outside Freemarker context, but doesnot working inside. I am trying to do
<#assign x = "${r"${expression}"}">
But getting the following error:
Template inclusion failed:
You can't use "${" here as you are already in FreeMarker-expression-mode. Thus, instead of ${myExpression}, just write myExpression. (${...} is only needed where otherwise static text is expected, i.e, outside FreeMarker tags and ${...}-s.)
What is the way to achieve this? Thanks in advance.
I had to spent some time to figure out the following scenarios to escape ${expression} -
In Freemarker assignment:
<#assign var = r"${expression}">
In html attribute:
Some link
In Freemarker concatenation:
<#assign x = "something&"+r"${expression}"/>
Like this:
<#assign x = r"${expression}">

Assigning empty string if XML node doesn't exist in Freemarker

I have an XML document passed as root to a Freemarker template. I want some values from this XML to be assigned to variables as a string and later concatenate/print them out.
<#assign MyVar = root.child1.child2.child3.mynode>
The issue here is that even when a path doesn't exist MyVar gets assigned with a sequence+hash which cannot be printed out or converted to string. This variable although returns false for ?has_content, it needs an extra step for these checks and I have this same issue with many variables and across template files and modules.
The only solution I have been able to find was
<#assign MyVar = root.child1.child2.child3.mynode>
<#assign MyVar = MyVar ?has_content?then(MyVar , "")>
I am looking for something like the Default Value Operator which also checks for nulls like ?has_content.
Does Freemarker provide any simpler one line function to check if a variable has no content and assign it with a default?
In short:
<#assign myVar = root.child1.child2.child3.mynode[0]!''>
Or just <#assign myVar = root.child1.child2.child3.mynode[0]!> if the implicit multi-typed default value doesn't cause problems (like when you just print it with ${}).
Why: XML queries (just like XPath queries) always return a sequence of matching nodes. There are maybe 0 such nodes (or 1, or multiple). An empty sequence is not a "missing value" according the template language. It's an inconvenient mismatch with the XML data-model. But while the sequence always exists, its 1st element ([0]) doesn't, so you can use all the missing value handler operators with it as usual.

Print smarty var in link file param

One simple thing:
I want to combine the {s name="*"} and {link file="*"} blocks.
src="{link file='{s name='sFooterPaymentsIcon'}{/s}'}"
The problems should be the
'
signs.
How can I do that?
You can try assign a new variable and pass that on file parameter, like:
{assign var="my_file" value="{s name='sFooterPaymentsIcon'}{/s}"}
and then
src="{link file="$my_file"}"
You can do it this way:
//Assign snippet value to variable $snippetLink, in case variable is empty - assign LinkInCaseSnippetEmpty
{assign var='snippetLink' value='LinkInCaseSnippetEmpty'|snippet:'TheNameOfSnippet':"Namespace/If/Need"}
//assign source from variable $snippetLink
src="{link file=$my_file}"
In one line:
src="{link file='LinkInCaseSnippetEmpty'|snippet:'TheNameOfSnippet':'Namespace/If/Need'}"
{s} is for for text-snippets and should not be used for configuration-variables. If you need to make an include configurable, you should create a plugin for that.
The plugin should have a frontend-subscriber and make the file-include configurable via backend configuration-form. In the subscriber you can pass the configuration-value for the file-include to the frontend-view.

Resources