C Apache FreeMarker Reference
Built-In String FreeMarker Operations
tester
as an example. As shown in the following snippet, its value is set to "hello world "
(with three trailing blank spaces):context:
variables:
tester: "string"
…
states:
setVariable:
component: "System.SetVariable"
properties:
variable: "tester"
value: "hello world "
Note:
The followingtext
property
definition allows the bot to output either the tester
value, or, no
string found
if no value has been set for the
variable.printVariable:
component: "System.Output"
properties:
text: "${tester.value!'no string found'}"
transitions:
...
Built-In Operation | Usage | Output |
---|---|---|
capitalize |
${tester.value?capitalize} |
Hello World |
last_index_of |
${tester.value?last_index_of('orld')} |
7 |
left_pad |
${tester.value?left_pad(3,'_')} |
___hello world |
length |
${tester.value?length} |
14 |
lower_case |
${tester.value?lower_case} |
hello world |
upper_case |
${tester.value?upper_case} |
HELLO WORLD |
replace |
${tester.value?replace('world', 'friends')} |
hello friends |
remove_beginning |
${tester.value?remove_beginning('hello')} |
world |
trim |
${tester.value?trim} |
hello world (the trailing three spaces are removed)
|
ensure_starts_with |
${tester.value?ensure_starts_with('brave new ')} |
brave new hello world |
ensure_ends_with |
${tester.value?ensure_ends_with(' my friend')}$ |
hello world my friend |
contains |
${tester.value?contains('world')?string ('You said world', 'You did not say world')} |
You said world The |
ends_with |
${tester.value?ends_with('world')?string ('Ends with world', 'Doesn't end with world')} |
Ends with world |
starts_with |
${tester.value?starts_with('world')?string ('Starts with world', 'Doesn't start with world')} |
Doesn't start with world |
matches (regular expression returns true or false)
|
${tester.value?matches('^([^0-9]*)$')} |
The regular expression returns true or false depending on whether the value contains a number (in which case the boolean value is returned as false ). The tester value returns true .
|
matches (regular expression returns a string)
|
${tester.value?matches('^([^0-9]*)$')?} |
Same as above, but this time, true is returned as a string. The matches('regular expression') function returns true or false as boolean types. To print true or false in a System.Output component, use ?string to perform a to-string conversion.
Note: You can’t use regular expression to return a group of values; use them to return a single matching value (or no match). |
Example: Improving the Confidence Level with Casing
lower_case
in the following snippet.
getIntent:
component: "System.Text"
properties:
prompt: "Hi, I am a the Pizza Palace bot. How can I help?"
variable: "userstring"
transitions:
next: "toLowercase"
toLowercase:
component: "System.SetVariable"
properties:
variable: "userstring"
value: "${userstring.value?lower_case}"
transitions:
next: "intent"
intent:
component: "System.Intent"
properties:
variable: "iResult"
sourceVariable: "userstring"
transitions:
actions:
orderPizza: "orderPizza"
cancelOrder: "cancelOrder"
unresolvedIntent: "handleUnresolved"
To implement this, you first ask the for the user input using the System.Text
component. In this example, the System.Text
component saves the user input in the userstring
variable. The Sytem.SetVariable
uses FTL to change the case of the user input string to lower case and saves the modified string to the same userstring
variable. Finally, the userstring
variable is referenced by the System.Intent
component using the sourceVariable
property to run the modified user string against the intent engine.
Example: Transforming Case with the System.Switch Component
Another component that can be simplified with FTL is System.Switch.
choice
variable.switch:
component: "System.Switch"
properties:
variable: "choice"
values:
- "wine"
- "beer"
transitions:
actions:
wine: "serverWine"
beer: "serveBeer"
NONE: "serveWater"
System.Text
component may inconsistent, even within a word (WiNE). Instead of adding all possible variations to the System.Switch
definition, use an FTL operation like upper_case
to make the casing uniform:switch:
component: "System.Switch"
properties:
source: "${choice.value?upper_case}"
values:
- "WINE"
- "BEER"
transitions:
actions:
WINE: "serveWine"
BEER: "serverBeer"
NONE: "serveWater"
Example: Concatenating FTL Expressions
normalizeFlightNumber:
component: "System.SetVariable"
properties:
variable: "flight"
value: "${flight.value?trim?lower_case?remove_beginning('ua ')
?remove_beginning('ua')}"
Built-In FreeMarker Number Operations
negativeValue
(-2.5) and positiveValue
(0.5175) context variables in the following snippet. context:
variables:
negativeValue: "float"
positiveValue: "float"
states:
setNegativeValue:
component: "System.SetVariable"
properties:
variable: "negativeValue"
value: -2.5
setPositiveValue:
component: "System.SetVariable"
properties:
variable: "positiveValue"
value: 0.5175
Operation | Example | Output |
---|---|---|
abs |
${negativeValue.value?abs} |
2.5
The operator turns the negative numeric value into a positive value. |
string (used with a numerical value)
|
${negativeValue.value?abs?string.percent} |
250%
The operator first changes the negative value to a positive. Then it converts it into percent, implicitly multiplying the value by 100. |
string (with the decimal format value and various currencies)
Tip: Check out Charbase for other currency symbols. |
${positiveValue.value?string['###.##']} |
0.51 |
${positiveValue.value?string['###.##%']} |
51%
The operator adds adding a percentage character after multiplying the value by 100. |
|
${positiveValue.value?string['##.###\u00A4']} |
0.51 $ | |
${positiveValue.value?string['##.###\u20AC']} |
0.51 € | |
${positiveValue.value?string['##.###\u00A3']} |
0.51 £ | |
round |
${negativeValue.value?round} |
-2
The operator rounds to the nearest whole number. If the number ends with .5, then it rounds upwards. |
${positiveValue.value?round} |
1
The operator rounds to the nearest whole number. If the number ends with .5, then it rounds upwards. |
|
floor |
${positiveValue.value?floor} |
0
The operator rounds downwards. |
ceiling |
${positiveValue.value?ceiling} |
1
The operator rounds upwards. |
lower_abc |
${negativeValue.value?abs?round?lower_abc} |
c
The operator turns the negative value into a positive, then rounds it to 3. It returns c, the third letter of the alphabet. |
upper_abc |
${negativeValue.value?abs?round?upper_abc} |
C
The operator turns the negative value into a positive, then rounds it to 3. It returns C, the third letter of the alphabet. |
is_infinite |
${positiveValue.value?is_infinite?string} |
false
The operator returns false, because a float value is not infinite according to IEEE 754 (Standard for Floating-Point Arithmetic). Note: The returned value would be a boolean without |
Built-In FreeMarker Array Operations
Array (or sequence) operations enable your bot to, among other things, determine the size of an array, sort arrays, or find content within an array.
person
and colors
variables.context:
variables:
person: "string"
colors: "string"
...
setPerson:
component: "System.SetVariable"
properties:
variable: "person"
value:
- firstName: "Frank"
lastName: "Normal"
- firstName: "Grant"
lastName: "Right"
- firstName: "Geoff"
lastName: "Power"
- firstName: "Marcelo"
lastName: "Jump"
...
setColors:
component: "System.SetVariable"
properties:
variable: "colors"
value:
- "yellow"
- "blue"
- "red"
- "black"
- "white"
- "green"
These
colors
and person
arrays are used to illustrate the array
operations in the following table and in Example: Iterating Arrays.
Operator | Example | Output |
---|---|---|
size |
${person.value?size?number} |
4 —The size (four members) of the person array
|
array index | ${person.value[1].firstName} |
Grant —It’s the value of the second firstName property in the person array.
|
${person.value[1].firstName !'unknown'} |
Same as the above, but in this case, the bot outputs unknown if the second firstName property has no value.
|
|
first |
${person.value?first.firstName} |
Frank —The first entry of the person array. This operation doesn’t use the array index.
|
last |
${person.value?last.firstName} |
Marcelo —The final lastName value in the person array.
|
sort_by |
${person.value?sort_by('lastName') [0].firstName} |
Marcelo This operator sorts the
person array by the lastName property in ascending order. It then prints the value of the corresponding firstName property for final entry in the person array:
Note: Unless you save the sorted array in a variable using |
${person.value?sort_by('lastName')?reverse[0].firstName} |
Grant —the values are sorted in descending order:
|
|
seq_index_of |
${colors.value?seq_index_of('red')} |
2 —The index value for red in the colors array.
|
seq_last_index_of |
${colors.value?seq_last_index_of('red')} |
2 —The last index value for red in the
|
join |
${colors.value?join(',')} |
Returns the colors array as a comma-separated string: yellow, blue, red, black, white, green |
seq_contains |
${colors.value?seq_contains('red')? |
Returns Yes because the array contains red.
Note: |
sort |
${colors.value?sort?join(',')} |
Returns the colors array as a comma-separated string in ascending order: black, blue, green, red, white, yellow |
reverse |
${colors.value?sort?reverse?join(',')} |
Returns the colors array as a comma-separated string in descending order: yellow, blue, red, black, white, green |
Returning Intents and Scores
-
${iResult.value.entityMatches[‘name of entity’]}
returns an array of entities found in a user string that’s passed to theSystem.Intent
component and stored in theiResult: nlpresult
variable. -
${iResult.value.intentMatches.summary[n].intent}
returns the name of the intent that has a confidence ranking ofn
, where0
represents the top-ranked intent,1
represents the second ranked intent, etc. ${iResult.value.intentMatches.summary[n].score}
returns the confidence score for the given intent.
n
is the index of the item you want to
look up. For example, the expression to return the top-resolved intent name would
be:${iResult.value.intentMatches.summary[0].intent}
For the top intent's score, the expression would
be:${iResult.value.intentMatches.summary[0].score}
You can use these expressions for intents that scored above the confidence
threshold, but you can also use them to return intents whose score falls below the
confidence threshold. These expressions are not dependent on the confidence threshold
value that's configured in the Skill's Settings page, so you can
use them to return the candidate intents and their scores even when no intent could be
resolved and an unresolvedIntent
action has been triggered. In this
case, you can, for example, use these expressions to return the top three intents and
their sub-confidence threshold scores.
Note:
If you need to refer to the intent that a user has selected after being asked to disambiguate, you can use${system.intent.name}
.
(${iResult.value.intentMatches.summary[0].intent}
always returns
the intent with the top score, which might not be the intent that the user selects when
disambiguating.
Example: Iterating Arrays
person
variable and
then iterate over its elements so that the skill outputs something like:
stateName
component: "System.CommonResponse"
properties:
metadata:
responseItems:
- type: "text"
text: "${person?index+1}. ${person.firstName} ${person.lastName}"
name: "Sorry"
separateBubbles: true
iteratorVariable: "person"
processUserMessage: false
Note:
The output described in this code is not sorted (that is, nosort_by
operation is used).
Built-In FreeMarker Date Operations
.now
and the built-in date
operator. PrintToday:
component: "System.Output"
properties:
text: "${.now?date}"
keepTurn: false
Operation(s) | Example | Output |
---|---|---|
date |
${.now?date} |
The current date |
time |
${.now?time} |
The time of day, like 5:46:09 PM |
datetime |
${.now?datetime} |
Prints current date and time, like Jan 17, 2018 5:36:13 PM. |
long and number_to_date |
${(.now?long + 86400000)?number_to_date } |
Adds 24 hours to the current date. If the call is made on January 17, 2018, FreeMarker outputs January 18, 2018. |
string (with formatting styles)
|
${.now?string.full} |
Converts the current date to string formatted as Wednesday, January 17, 2018 6:35:12 PM UTC. |
${.now?string.long} |
Converts date to string with the following formatted output: January 17, 20186:36:47 PM UTC. | |
${.now?string.short} |
Converts date to string with the following formatted output: 1/17/18 6:37 PM | |
${.now?string.medium} |
Converts date to string with the following formatted output: Jan 17, 2018 6:38:35. | |
${.now?string.iso} |
Prints the date in the ISO 8601 standard like 2018-01-17T18:54:01.129Z. |
|
string (with specified output formats)
|
${.now?string['dd.MM.yyyy, HH:mm']} |
Prints the current date in a custom format, like 17.01.2018, 18:58. |
${.now?string['yyyy']} |
2018 |
|
datetime (with string and formatting style)
|
${date_variable?datetime?string.short} |
Converts the date to a string formatted as 1/17/18 6:37 PM.
The |
Converting the entity value to a string using
|
${dateVar.value.date?long?number_to_date?date?string.short} |
Converts the date from the entity extraction to a string formatted as 11/17/18.
The date operator tells FreeMarker that the variable only holds a date, not time information. Using this format avoids errors. |
${dateVar.value.date?long?number_to_date?string.medium} |
Converts the date that’s derived from entity extraction to a string formatted as Jan 17, 2018.
Note: All other formats like |
|
${dateVar.value.date?long?number_to_date?string['dd.MM.yyyy']} |
Prints the date in custom format. For example: 17.01.2018, 18:58. | |
${dateVar.value.date?long?number_to_date?string['yyyy']} |
Prints the date derived from the entity in a custom format. |
Example: Extracting Dates from User Input
DATE
, to extract tomorrow from the request. It outputs the requested date using ${(theDate.value.date?long + 86400000)?number_to_date}
to add 24 hours (or 86,400,000 milliseconds) to the current date.
OBotML Code | Output |
---|---|
|
Outputs the following messages in response to the user message, Can you arrange a
meeting with Mr. Higgs a day later than tomorrow?:
|
Example: Setting a Default Date (When No Date Value Is Set)
conditionEquals:
component: "System.ConditionEquals"
properties:
variable: "theDate"
value: null
transitions:
actions:
equal: "setDefaultDate"
notequal: "printDateFound"
If no date value has been set, the System.SetVariable
component defines a default value in a variable and transform it into a string. setDefaultDate:
component: "System.SetVariable"
properties:
variable: "defaultDateInput"
value: "${.now?datetime?string.long}"
The System.MatchEntity
component verifies that this value is a date and then sets the theDATE
variable: matchEntity:
component: "System.MatchEntity"
properties:
sourceVariable: "defaultDateInput"
variable: "theDate"
transitions:
actions:
match: "printDateFound"
nomatch: "exit"
OBotML | Output |
---|---|
|
The skill outputs the following messages in response to the user message, Can
you arrange a meeting with Mr. Higgs a day later than tomorrow?:
|
FreeMarker-Accessible System Variables
Oracle Digital Assistant has a set of system variables through which you can retrieve useful information in your dialog flows through FreeMarker expressions.
In their simplest forms, these expressions take the following form:
${system.variableName}
Some variables can hold objects with nested properties that can be accessed using dot notation after the variable name in the following form.
${system.variableName.propertyName}
In addition, the nested property values can also be objects with nested properties.
Here are the system variables that are available through FreeMarker expressions.
Variable | Description |
---|---|
system.actualState |
Name of the state the user has navigated to by tapping an older "out-of-order" button. If the postback payload contains a system.state property, the dialog engine will navigate to this state and sets this variable to the name of that state. See also Configure the Dialog Flow for Unexpected Actions.
|
system.authorizedUsers |
A list of all of the users that have been authorized for a given group chat. |
system.channelType |
The type of channel of the current user session. Allowable values:
facebook , androidsdk ,
iossdk , websdk ,
slack , twilio ,
msteams , cortana ,
webhook , and test .
If the session is running in the tester, the value corresponds to the channel type being simulated. |
system.entityToResolve |
Object representing the current composite bag item to resolve in the System.CommonResponse component when the variable property of the component is referring to a composite bag entity.The object has the following properties:
See The system.entityToResolve Variable for examples of how to use |
system.errorAction |
Error message text of an unexpected error thrown during execution of the state. |
system.errorState |
Name of the state that has thrown an unexpected error during execution. |
system.expectedState |
When user scrolls up the message history, and taps on an older "out-of-order" button this variable is populated with the name of the state that was expected to be executed, but never got executed because the user decided to tap on this "out-of-order" button. See also Configure the Dialog Flow for Unexpected Actions. |
system.intent.name |
Use to refer to the intent that a user has selected after
being asked to disambiguate.
(
always returns the intent with the top score, which might not be the
intent that the user selects when disambiguating.) |
system.invalidUserInput |
Boolean value set to true when the user input cannot be matched to the requested variable type.
|
system.message |
Last message received by Oracle Digital Assistant. This variable has the following properties:
|
system.requestedState |
If a users enters a conversation at a state that requires authorization and the user is not in the list of users stored in system.authorizedUsers , the dialog engine stores the state it intended to execute in this variable.
|
system.selectedCardIndex |
This variable holds the index of the selected card when using the facility to optimize card rendering for text-only channels like Twilio. This optimization allows the user to select a card in a two step process: first a list of cards is presented, then the user can enter the number of the cards he wants to select. The corresponding index number of this card is stored in this variable. |
Note:
The system variables in the above table are the only ones that you can use in FreeMarker expressions. Other system variables are not public and their use is subject to change, which means your skills can't rely on them.
For example, the system.routingFromSkill
,
system.routingToSkill
,
system.routingFromIntent
, and
system.routingToIntent
variables are only available for
specific digital assistant settings. See System Variables for Digital Assistants.