Skip to content

String Interpolation and JSON Flatten/Unflatten

Introduction

When defining properties for a trigger or workflow step, String Interpolation uses variable values to create new values.

String Interpolation can be used in:

  • Trigger Property Values
  • Trigger Property Names
  • Workflow Step Properties and Output Properties
    • Command
    • Set
    • Start Workflow
    • Send Event
    • End
  • Workflow Property Names
  • Workflow Conditional Execution Statements

Examples

Properties are defined by setting a name to a value. By default the value is treated as a literal string.

Name Value Final Value
fullName John Smith John Smith

Curly brackets are used to indicate that variable replacement should be performed. if firstName is John and lastName is Smith then:

Name Value Final Value
fullName {firstName} {lastName} John Smith

If the variable does not exist then it is evaluated as empty string. If middleName does not exist:

Name Value Final Value
fullName {firstName}-{middleName}-{lastName} John--Smith

Functions

A function can be used in the string interpolation by preceding the function name with a question mark:

Name Value Final Value
fullName {?Left(firstName, 'h')} Jo

Any variable name used in a function must not need to be surrounded by curly brackets. For example the variable first-name would not be valid as the parameter to the function in the example above.

Objects and Arrays

The variables in a trigger or workflow are simple string dictionaries but the syntax of an array or object as used in other languages can be used. To make it easy pass an entire "object" or "array" in a trigger or workflow step the value syntax of a single variable in curly brackets (e.g. name = "newname", value = "{name}") will perform these steps in order to find a value:

  1. Lookup the variable "name". If found - use its value.
  2. Look for all variables that start with "name." or "name[".
    1. If any are found copy each value to the destination variables and remove any existing variables that start with the destination prefix ("newname." and "newname[")
    2. If the destination name is different from the source name the name is changed (see examples below)
  3. Use the default value of empty string

Object Example

The following variables could be set for a "person" object:

Name Value
person.firstName John
person.lastName Smith
person.fullName John Smith
person.office 102

In a trigger or workflow step to pass all of the "person" variables, changing the name to "value", use the following syntax:

Name Value Destination Values
value {person} value.firstName = "John"
value.lastName = "Smith"
value.fullName = "John Smith"
value.office = "102"

Array Example

The following variables could be set for an array of attachments:

Name Value
attachments.count 2
attachments[0].name data1.txt
attachments[0].data abc123
attachments[1].name data2.txt
attachments[1].data def456

In a trigger or workflow step to pass the entire "attachment" array, leaving the name the same:

Name Value Destination Values
attachments {attachments} attachments.count = "2"
attachments[0].name = "data1.txt"
attachments[0].data = "abc123"
attachments[1].name = "data2.txt"
attachments[1].data = "def456"

Array Indexing

All variable names are strings: name, index, etc. During condition evaluation the variable name is resolved by looking up the variable name to retrieve the value.

Variable names can contain square brackets such as name[0] or attachments[1].data. If a variable name lookup fails because it does not exist and the variable name contains square brackets, an attempt is made to do variable substitution and attempt the lookup again. This allows using variables as array indexes.

The variable name inside of the array index must not start with a number: digit (0-9), plus: +, minus: -, or dot (.).

Functions can be used inside of an array index but:

  • The expression must be inside of curly brackets to be parsed correctly
  • The function must be preceded by a question mark (?)

Example:

The variables are:

index = '2'
name[0] = 'name_zero'
name[1] = 'name_one'
name[2] = 'name_two'
name[3] = 'name_three'
data[2] = '1'
Value Final Value Variable Lookups Performed
{name[2]} name_two name[2] - succeeded
{name[index]} name_two name[index] - failed
name[2] - succeeded (name_two)
{name[?Add(index, 1)]} name_three name[3] - succeeded (name_three)

Arrays can be nested up to five levels deep:

Value Final Value Variable Lookups Performed
{name[data[index]]} name_one name[data[index]] - failed
data[index] - succeeded (1)
name[1] - succeeded (name_one)

Multiple array replacements can be performed in one variable name. Up to ten replacements can occur.

Added variables:

index2 = '1'
name[2].titles[1] = 'foo'
Value Final Value Variable Lookups Performed
{name[index].titles[index2]} foo name[index].titles[index2] - failed
name[2].titles[1] - succeeded (foo)

JSON Flattening and Unflattening

Flattening Output Data

The data returned from the request, if it is json, will be flatten and added to the response as multiple properties prefixed with "content".

Here are some example of flattening:

HttpContent WF Response

Example of data flattened from https://randomuser.me/api/:


Count = 30
     [0]: {[content.results[0]gender, male]}
     [1]: {[content.results[0]name.title, mr]}
     [2]: {[content.results[0]name.first, owen]}
     [3]: {[content.results[0]name.last, peterson]}
     [4]: {[content.results[0]location.street, 6138 valwood pkwy]}
     [5]: {[content.results[0]location.city, shepparton]}
     [6]: {[content.results[0]location.state, victoria]}
     [7]: {[content.results[0]location.postcode, 3579]}
     [8]: {[content.results[0]email, owen.peterson @example.com]}
     [9]: {[content.results[0]login.username, brownmeercat795]}
    [10]: {[content.results[0]login.password, moritz]}
    [11]: {[content.results[0]login.salt, CoikrY5a]}
    [12]: {[content.results[0]login.md5, f191b1ce65e48e1f602083a1be548732]}
    [13]: {[content.results[0]login.sha1, d0560a523f4a4d3f30284743b2ec735c88f5a634]}
    [14]: {[content.results[0]login.sha256, e1a24b69f2a5826c28db580cc54ff408416985522cdfc1b91417a78ed2249725]}
    [15]: {[content.results[0]dob, 1952-02-10 01:10:00]}
    [16]: {[content.results[0]registered, 2008-08-29 21:12:50]}
    [17]: {[content.results[0]phone, 00-9453-0604]}
    [18]: {[content.results[0]cell, 0408-614-731]}
    [19]: {[content.results[0]id.name, TFN]}
    [20]: {[content.results[0]id.value, 866645537]}
    [21]: {[content.results[0]picture.large, https://randomuser.me/api/portraits/men/44.jpg]}
    [22]: {[content.results[0]picture.medium, https://randomuser.me/api/portraits/med/men/44.jpg]}
    [23]: {[content.results[0]picture.thumbnail, https://randomuser.me/api/portraits/thumb/men/44.jpg]}
    [24]: {[content.results[0]nat, AU]}
    [25]: {[content.results.count, 1]}
    [26]: {[content.info.seed, 6ef563bd947a1202]}
    [27]: {[content.info.results, 1]}
    [28]: {[content.info.page, 1]}
    [29]: {[content.info.version, 1.1]}


Unflattening Input Data

Data passed as payload for the POST command of the HttpRequest Adapter must be set as multiple properties of the command step, just like a reverse flatten of the json.

All properties that must be part of the payload, must be prefixed with 'content'. The JSON will be constructed from them.

Here are some example of unflattening:

WF Request HttpContent

Rules for unflattening data:

  • Properties can be set either simple, complex or collections
  • Once a property has been set of a type, it cannot be set to another type (collections cannot have nested properties, simple properties cannot be collections, etc)
  • The order in which the properties are set is not important, but when specifying collections, all indexes must be provided (cannot unflatten collection if only items 0, 1 and 4 are provided)
  • When unflattening data, all values are string; there are no int, bool and no null values (string empty is allowed)