B Apache FreeMarker Reference

Built-In String FreeMarker Operations

The following table shows you how to use some of the built-in string operations using a string variable called 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 following text 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 contains('world') expressions returns either true or false. These boolean values are replaced with a string using the string ('string1','string2') function.

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

While The casing of the user input can impact the confidence level of the intent resolution. For example, May might refer to the month or the verb and user input can be erratic (Pizza, piZza, PIZZA). Instead of catching all of the possible case variations as synonyms in the entity definition, you can make the casing uniform using the an FTL operator like 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: {}
toLowercase:
    component: "System.SetVariable"
      properties:
      variable: "userstring"
      value: "${userstring.value?lower_case}"
    transitions: {}
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.

In the following snippet shows different states that get called depending on the user input (wine or beer), which is stored in the choice variable.
switch:
    component: "System.Switch"
    properties:
      variable: "choice"
      values:
      - "wine"
      - "beer"
    transitions:
      actions:
        wine: "serverWine"
        beer: "serveBeer"
        NONE: "serveWater"
The casing of the input collected using the 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

The following snippet shows how concatenating FTL expressions transforms user input UA1234 and UA 1234, to simply 1234.
normalizeFlightNumber:
  component: "System.SetVariable"
  properties:
    variable: "flight"
    value: "${flight.value?trim?lower_case?remove_beginning('ua ')
            ?remove_beginning('ua')}"

Built-In FreeMarker Number Operations

The following table lists the built-in number operations and shows how they output the value set for the 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 ?string.

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.

Array operations return the results from the intent and entity processing. For example:
  • ${iResult.value.entityMatches[‘name of entity’]} returns an array of entities found in a user string that’s passed to the System.Intent component and stored in the iResult: nlpresult variable.

  • ${iResult.value.intentMatches.summary} returns an array of intents and the confidence level for the given user input.

You can use arrays to create mock data for testing, or for defining data structures that persist beyond user sessions. You can save an array in a custom component, in a user-scoped variable, or as shown in the following snippet, a context variable. In it, there are arrays set for the 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 and 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:
  • Jump, Marcelo

  • Normal, Frank

  • Power, Geoff

  • Right, Grant

Note: Unless you save the sorted array in a variable using System.SetVariable, the data remains sorted for a single request only.

${person.value?sort_by('lastName')?reverse[0].firstName} Grant—the values are sorted in descending order:
  • Right, Grant

  • Power, Geoff

  • Normal, Frank

  • Jump, Marcelo

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: ?seq_contains returns a boolean value. This value is then replaced by a string using the ?string(‘...’.’...’) expression.

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

Example: Iterating Arrays

Arrays determine the number of entities in the user input. The following snippet shows how to determine the size of the array held in the person variable and then iterate over its elements so that the bot outputs something like:

    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, no sort_by operation is used).

Built-In FreeMarker Date Operations

The following snippet derives the current date using the FreeMarker special variable reference, .now and the built-in date operator.
PrintToday:
  component: "System.Output"
  properties:
   text: "${.now?date}"
   keepTurn: false
The following table lists some of the built-in date operations that you can use to define properties and manipulate entity values.
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 datetime operator enables FreeMarker to tell if the variable holds a date that contains both date and time information. Similarly, you can use the date or time operators to indicate if the date value contains only the date or only the time, but using datetime?string avoids errors.

Converting the entity value to a string using
  • date

  • long

  • number_to_date

  • formatting styles

  • custom date formats

${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 full, short, long and iso work the same with dates that are derived from entity extraction.

${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

The following snippet is from a bot that manages appointments. When a user asks it, Can you arrange a meeting with Mr. Higgs a day later than tomorrow?, the bot uses a complex entity, 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
context:
  variables:
    iResult: "nlpresult"
    theDate : "DATE"
states:
   intent:
    component: "System.Intent"
    properties:
      variable: "iResult"
    transitions:
      actions:
        unresolvedIntent: "dunno"
        Appointment: "printToday"
printToday:
  component: "System.Output"
  properties:
    text: "Today is: ${.now}"
    keepTurn: true
startAppointement:
  component: "System.SetVariable"
  properties:
    variable: "theDate"
    value: "${iResult.value.entityMatches['DATE'][0]}"
printDateFound:
  component: "System.Output"
  properties:
    text: "Date found is: ${theDate.value.date}"
    keepTurn: true
printDayAfter:
  component: "System.Output"
  properties:
    text: "A day later is ${(theDate.value.date?long + 86400000)?number_to_date}"
  transistions:
    return: "done"

Example: Setting a Default Date (When No Date Value Is Set)

If the user message doesn’t include any date information, your bot can prompt users for the date, or provide a default date, as shown by the following snippet (which augments the dialog flow in the previous example). To perform the latter, your bot needs to check if the date variable has been set after the NLP engine extracts entities from the user input.
  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
context:
  variables:
    iResult: "nlpresult"
    theDate : "DATE"
    #need extra variable for default date input
    defaultDateInput: "string"
states:
 ...

#try to extract date information from user sentence
  startAppointement:
    component: "System.SetVariable"
    properties:
      variable: "theDate"
      value: "${iResult.value.entityMatches['DATE'][0]}"
#set default date if none found
  conditionEquals:
    component: "System.ConditionEquals"
    properties:
      variable: "theDate"
      value: null
    transitions:
      actions:
        equal: "setDefaultDate"
        notequal: "printDateFound"
  setDefaultDate:
    component: "System.SetVariable"
    properties:
     variable: "defaultDateInput"
     value: "${.now?datetime?string.long}"
  matchEntity:
    component: "System.MatchEntity"
    properties:
  sourceVariable: "defaultDateInput"
    variable: "theDate"
    transitions:
      actions:
        match: "printDateFound"
        nomatch: "exit"
  printDateFound:
    component: "System.Output"
    properties:
      text: "Date found is:
             ${theDate.value.date?long?number_to_date?date?string.medium}"
      keepTurn: true
  printDayAfter:
    component: "System.Output"
    properties:
    text: "A day later is ${(theDate.value.date?long + 86400000)?number_to_date}"
    transistions:
      return: "done"

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 available system variables.

Variable Description
system.message Last message received by Oracle Digital Assistant. This variable has the following properties:
  • channelConversation - the channel conversation object, which has the following properties:
    • botId
    • channelType - (in the tester,

      Note:

      When running in the tester, this will return test.
    • channelName
    • channelCategory
    • userId
    • sessionId
    • sessionExpiryDuration
  • messagePayload - the actual message sent by the user. The properties you can access depend on the type of message:
    • Text message: the text property returning the actual message entered by the user
    • Postback message: the properties of the postback object, typically action and variables when using the System.CommonResponse component. For example, when the user taps a button that sets the variable pizzaSize, this value can be retrieved using following expression:${system.message.messagePayload.variables.pizzaSize}
    • Location message: the location property, which holds a location object with following properties:
      • title
      • url
      • latitude
      • longitude
  • stateCount - the number of states executed to process the last user message.
  • platformVersion - the current runtime platform version.
system.entityResolve 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:
  • nextRangeStart - index number of the entity's allowable value list that will be navigated to when tapping the Show More button.
  • updatedEntities - list of composite bag items that were updated based on the last user message.
  • needShowMoreButton - Boolean property that can be used in as an expression for the visible property to conditionally render the Show More button to navigate to the next set of entity values.
  • outOfOrderMatches - list of bag items that were populated with a value based on the last user message when the user was prompted for another bag item.
  • rangeStartVar - name of the variable that holds the current range start of the entity values.
  • validationErrors - for the current bag item, list of error messages caused by an invalid value provided in the last user message.
  • allMatches - list of bag items that got a new or updated values based on the last user message.
  • resolvingField - name of current bag item the user is prompted for.
  • userInput - the last user message.
  • skippedItems - list of bag items where the maximum number of prompts for a value is exceeded.
  • disambiguationValues - list of allowed entity values that have matches in the last user message.
  • enumValues - list of entity allowed values for the current bag item.

See The system.entityToResolve Variable for examples of how to use system.entityResolve.

system.invalidUserInput Boolean value set to true when the user input cannot be matched to the requested variable type.
system.errorState Name of the state that has thrown an unexpected error during execution.
system.errorAction Error message text of an unexpected error thrown during execution of the state.
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.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.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.