I'm trying to write an #if statement with a sequence of numbers. Basically, if a certain field matches any of a subset of numbers (shown below with || or operators) then assign it as "bayarea", elseif a different subset, then a different name, etc. Is this possible without a bunch of nested "or" statements?
I'm getting a syntax error saying that it's expecting a boolean yes/no statement.
<#if TEST_CONTACTS_LIST.PREFERRED_STORE ==
{12||21||22||38||46||67||71||74||76||77||83||86||104||113||119||143>
{bayarea}
<#elseif TEST_CONTACTS_LIST.PREFERRED_STORE ==
{34||62||84||91||137||144||152||169}>
{blueridge}
<#elseif TEST_CONTACTS_LIST.PREFERRED_STORE ==
{18||44||49||50||61||68||121||182}>
{frontrange}
<#else>
</#if>
You don't need nesting:
<#if TEST_CONTACTS_LIST.PREFERRED_STORE == 12
|| TEST_CONTACTS_LIST.PREFERRED_STORE == 21 || ...>
Though that's surely too verbose, but you can do this:
<#assign store = TEST_CONTACTS_LIST.PREFERRED_STORE>
<#if store == 12 || store == 21 || ...>
But I think what you are looking for is this (or this combined with the #assign, if you have several #elseif-s):
<#if [12, 21, ...]?seq_contains(TEST_CONTACTS_LIST.PREFERRED_STORE)>
This is a possibility too (just don't forget the #break-s):
<#switch TEST_CONTACTS_LIST.PREFERRED_STORE>
<#case 12><#case 21>...
{bayarea}
<#break>
<#case 34><#case 62>...
{bluebridge}
<#break>
...
</#switch>
Those are four good answers above. To expand on it, I'd do something like this:
<#assign pref_store = TEST_CONTACTS_LIST.PREFERRED_STORE>
<#assign area = "">
<#assign group1 = [12,21,22,38,46,67,71,74,76,77,83,86,104,113,119,143]>
<#assign group2 = [34,62,84,91,137,144,152,169]>
<#assign group3 = [18,44,49,50,61,68,121,182]>
<#if group1?seq_contains(pref_store)>
<#assign area = "bayarea">
<#elseif group2?seq_contains(pref_store)>
<#assign area = "blueridge">
<#elseif group3?seq_contains(pref_store)>
<#assign area = "frontrange">
<#else>
<#assign area = "whatever">
</#if>
Your Preferred Store Area is ${area}.
Alternatively, instead of Sequences / Arrays, you could also set these values as a string.
For example:
<#assign pref_store = "${TEST_CONTACTS_LIST.PREFERRED_STORE}">
<#assign group1 = "12,21,22,38,46,67,71,74,76,77,83,86,104,113,119,143">
then the if statement would be the following:
<#if group1?contains(pref_store)>
(Notice the ?contains instead of ?seq_contains)
etc..
Related
I'm trying to convert a HTML table to plain text. To have the "columns" aligned correctly I'd like to insert as many whitespaces to every cell content to match the max length of all cell contents.
The cell content is extracted from the HTML using a RegEx Replace using a captureGroup. When I'm applying the ?right_pad on the captureGroup the actual length of the captureGroup isn't considered but just 2 characters ($1), thus the columns of the plain text aren't aligned but shifted.
Any other approaches? Or if a Freemarker Contributor/Dev is reading - could you register this as a bug or invite me to the project's Jira so I can register it myself?
Template:
<#-- DETERMINE MAX TABLE CELL CHARACTER LENGTH -->
<#assign tableCells = htmlTable?matches("<td>([\\w\\d\\s]*)</td>") >
<#assign cellSizes = []>
<#list tableCells as t>
<#assign cellSizes += [t?groups[1]?length]>
</#list>
<#assign maxCellSize = cellSizes?max>
Max Cell Character length: ${maxCellSize}
${htmlTable
<#-- REPLACE HTML TABLE WITH PLAINTEXT -->
<#-- REMOVE OUTER TABLE ELEMENTS -->
?replace("<table.*<tbody>(.*)</tbody></table>", "$1", "rgi")
<#-- REPLACE TABLE HEADERS -->
?replace("<th[\\w\\d\\s=\\\"]*>(<p>)*(<strong>)*([\\w\\d\\s=\\\"]*)(</strong>)*(</p>)*", "<b>" + "$3"?right_pad(maxCellSize, "-") + "</b>", "rgi")
<#-- ADD SPACERS BETWEEN TABLE HEADERS -->
?replace("</th>(?!</tr>)", " ", "rgi")
<#-- REPLACE TABLE CELLS-->
?replace("<td[\\w\\d\\s=\\\"]*>(<p>)*(<strong>)*([\\w\\d\\s=\\\"]*)(</strong>)*", "$3"?right_pad(maxCellSize, "-"), "rgi")
<#-- ADD SPACERS BETWEEN TABLE CELLS -->
?replace("</td>(?!</tr>)", " ", "rgi")
<#-- REPLACE "TABLE LINE BREAKS" (END OF ROW) WITH REGULAR LINE BREAKS-->
?replace("</tr>", "<br>")
<#-- REMOVE REMAINING <tr>|</th>|</td> ELEMENTS -->
?replace("<tr>|</th>|</td>", "", "rgi")
}
Data model
htmlTable = "<table><tbody><tr><th>col1</th><th>column 2</th><th>very long col header 3</th></tr><tr><td>text</td><td>some text</td><td>last col text</td></tr><tr><td>longer text</td><td>text</td><td>last col text 2</td></tr><tr><td>even longer text</td><td>yet another fairly long text</td><td>last col text 3</td></tr></tbody></table>"
Result
Max Cell Character length: 28
<b>col1--------------------------</b> <b>column 2--------------------------</b> <b>very long col header 3--------------------------</b><br>text-------------------------- some text-------------------------- last col text--------------------------<br>longer text-------------------------- text-------------------------- last col text 2--------------------------<br>even longer text-------------------------- yet another fairly long text-------------------------- last col text 3--------------------------<br>
So I found a solution to my problem, here it is if someone else can use it:
TL;DR: "flag" the table headers and contents, copy those without the flags and padding into an array and later replace flagged stuff with right padded stuff.
Template:
<#-- DETERMINE MAX TABLE CELL CHARACTER LENGTH -->
<#assign tableHeaders = htmlTable?matches("<th[\\w\\d\\s=\\\"]*>(<p>)*(<strong>)*([\\w\\d\\s=\\\"]*)(</strong>)*(</p>)*")>
<#assign tableCells = htmlTable?matches("<td[\\w\\d\\s=\\\"]*>(<p>)*(<strong>)*([\\w\\d\\s=\\\"]*)(</strong>)*") >
<#assign cellSizes = []>
<#assign cellContents = []>
<#list tableCells as t>
<#assign cellSizes += [t?groups[3]?length]>
<#assign cellContents += [t?groups[3]]>
</#list>
<#assign headerContents = []>
<#list tableHeaders as h>
<#assign cellSizes += [h?groups[3]?length]>
<#assign headerContents += [h?groups[3]]>
</#list>
<#assign maxCellSize = cellSizes?max>
<#assign flaggedCellContents = [] paddedCellContents = []>
<#list cellContents as c>
<#assign flaggedCellContents += ["###"+c+"###"]>
<#assign paddedCellContents += [c?right_pad(maxCellSize+3, "-")]>
</#list>
<#assign flaggedHeaderContents = [] paddedHeaderContents = []>
<#list headerContents as h>
<#assign flaggedHeaderContents += ["§§§"+h+"§§§"]>
<#assign paddedHeaderContents += [h?right_pad(maxCellSize+3, "-")]>
</#list>
Max Cell Character length: ${maxCellSize}
<#assign convertedTable = htmlTable
<#-- REPLACE HTML TABLE WITH PLAINTEXT -->
<#-- REMOVE OUTER TABLE ELEMENTS -->
?replace("<table.*<tbody>(.*)</tbody></table>", "$1", "rgi")
<#-- REPLACE TABLE HEADERS -->
?replace("<th[\\w\\d\\s=\\\"]*>(<p>)*(<strong>)*([\\w\\d\\s=\\\"]*)(</strong>)*(</p>)*", "§§§$3§§§", "rgi")
<#-- REPLACE TABLE CELLS-->
?replace("<td[\\w\\d\\s=\\\"]*>(<p>)*(<strong>)*([\\w\\d\\s=\\\"]*)(</strong>)*", "###$3###", "rgi")
<#-- REPLACE "TABLE LINE BREAKS" (END OF ROW) WITH REGULAR LINE BREAKS-->
?replace("</tr>", "\n")
<#-- REMOVE REMAINING <tr>|</th>|</td> ELEMENTS -->
?replace("<tr>|</th>|</td>", "", "rgi")
>
<#list 1..cellContents?size as i>
<#assign convertedTable = convertedTable?replace(flaggedCellContents[i?index], paddedCellContents[i?index])>
</#list>
<#list 1..headerContents?size as i>
<#assign convertedTable = convertedTable?replace(flaggedHeaderContents[i?index], paddedHeaderContents[i?index])>
</#list>
${convertedTable}
Data Model:
htmlTable = "<table><tbody><tr><th>col1</th><th>column 2</th><th>very long col header 3</th></tr><tr><td>text</td><td>some text</td><td>last col text</td></tr><tr><td>longer text</td><td>text</td><td>last col text 2</td></tr><tr><td>even longer text</td><td>yet another fairly long text</td><td>last col text 3</td></tr></tbody></table>"
Result:
Max Cell Character length: 28
col1---------------------------column 2-----------------------very long col header 3---------
text---------------------------some text----------------------last col text------------------
longer text--------------------text---------------------------last col text 2----------------
even longer text---------------yet another fairly long text---last col text 3----------------
I am trying to write a Numeric and Alphabetic Series in Free-marker. However I am not able to implement it.
I have tried various portal and Freemarker website itself, but was not able to find a proper solution.
<#assign count = 0>
<#assign seq = ['a','b','c','d','e','f',]>
<#list params_list as test_param>
${count} ${seq[count]}
<#assign count = count + 1>
</#list>
It will print data in
1 a
2 b
3 c
You can use ?lower_abc (or ?upper_abc) to convert a number to a letter, where 1 corresponds to letter "a". If this is inside #list, then you can get the 1-based item counter with itemVariable?counter. For example:
<#list items as item>
${item?counter} ${item?counter?lower_abc}
</#list>
I'm setting up a synesty flow and I need to know how many ArticleNumber in the ArticleNumber list.
E.g
Here are the ArticleNumber list
35361,35361,35361,205,09308943528,093089435281,093089435281
I want to know how many ArticleNumber "09308943528" in the list
I've tried the ?contains but its only a boolean value.
<#if MainArticleNumberList!?contains('${ArticleNumber!}')>true<#else>false</#if>
I expect the output number depends on how many ArticleNumber in the list, in the example above it will show 1.
Use filter with size to calculate count:
${MainArticleNumberList?filter(x -> x=="09308943528")?sequence?size}
Use seq_contains freemarker builtin for sequences:
<#if MainArticleNumberList?seq_contains("09308943528")>true<#else>false</#if>
Tells if the sequence contains the specified value (according the == operator of the template language, not according Java's Object.equals). It has 1 parameter, the value to find.
If you are before FreeMarker 2.3.29, and thus can't use ?filter, you can still do this:
<#assign cnt = 0>
<#list MainArticleNumberList as articleNumber>
<#if articleNumber == '09308943528'>
<#assign cnt++>
</#if>
</#list>
${cnt}
out = [1,2,3,1,1,1]
print(out.count(1))
code:
[#assign numbers = [1,1,2,3,4,4,0,5,0,6,0,8,9]]
[#assign words = ["hello","bye","hello"]]
[#function getOccurrencesCount sequence item]
[#local occurrencesCount = 0]
[#list sequence as i]
[#if i == item]
[#local occurrencesCount++]
[/#if]
[/#list]
[#return occurrencesCount]
[/#function]
0 in numbers: ${getOccurrencesCount(numbers,0)}
6 in numbers: ${getOccurrencesCount(numbers,6)}
9 in numbers: ${getOccurrencesCount(numbers,9)}
"hello" in words: ${getOccurrencesCount(words,"hello")}
"bye" in words: ${getOccurrencesCount(words,"bye")}
output:
0 in numbers: 3
6 in numbers: 1
9 in numbers: 1
"hello" in words: 2
"bye" in words: 1
Is there a better way to write this IF statement for testing multiple options of a variable?
<#if PRINTER_PET.RETAILER_NAME = 'BEST BUY' || PRINTER_PET.RETAILER_NAME = 'Best Buy Purchasing LLC'>
document 1
<#elseif PRINTER_PET.RETAILER_NAME = 'AMAZON' || PRINTER_PET.RETAILER_NAME = 'Amazon Fulfillment Services Inc Attn: Amazon.com' >
document 2
</#if>
Thank you,
Erica
You can extract PRINTER_PET.RETAILER_NAME into a variable, like <#assign retName = PRINTER_PET.RETAILER_NAME>, and then it's somewhat shorter (<#if retName == 'foo' || retName == 'bar'>, etc.). Also, if you have a lot of strings to compare with, <#if ['foo', 'bar', 'baaz']?seq_contains(retName)> might be nicer.
Follow Freemrker Comparison example and use == and ":
<#if PRINTER_PET.RETAILER_NAME == "BEST BUY" || PRINTER_PET.RETAILER_NAME == "Best Buy Purchasing LLC">
document 1
<#elseif PRINTER_PET.RETAILER_NAME == "AMAZON" || PRINTER_PET.RETAILER_NAME == "Amazon Fulfillment Services Inc Attn: Amazon.com" >
document 2
</#if>
The user == "Big Joe" expression in the <#if ...> will evaluate to the boolean true, so the above will say "It is Big Joe".
Logical or: ||
How to write loop with odd sequence in Apache FreeMarker template?
for example:
<#list seq as n>
...?
${n_index}
</#list>
As result: 1,3,4,5..
Use the Modulus operator.
<#list seq as n>
<#if n % 2 == 1>
<#-- your code here -->
</#if>
</#list>
Assuming you actually want to print the 1st, 3rd, 5th, etc. item of the sequence, as opposed to filter by the parity of the list item (n) itself...
If the result is 1, 2, etc., then either you actually want the even items, or you want n?counter that is 1-based, not n?index that is 0-based. Assuming the last (plus I also print the item itself):
<#list seq as n>
<#if n?is_odd_item>
${n?counter}: ${n}
</#if>
</#list>
Related page in the manual: http://freemarker.org/docs/ref_builtins_loop_var.html