Dynamic Data Objects

Objects are a data structure that can hold multiple values within a single variable. They're useful when you have a collection of values that all relate to a "thing" in your script. For example, you might have a set of data relating to a contact, such as name, phone number, and email address.  You can store all of these values in an object. The benefit of this is that it can reduce the number of variables used in your scripts.

Studio supports objects of the DynamicData type. This type can work with data that doesn't have a static format or type, such as XML or JSON.

You can create dynamic data objects by declaring them in Snippet code or by parsing JSON or XML. They are also created from responses from API calls and certain Framework actions.

You can use a dynamic data object in any Studio action where you can use a standard variable. Dynamic data objects can be used to hold data, just like standard variables. They have other uses, too. For example, you can use them to: 

The number of dynamic data variables and objects in a script can impact tracing. You may see performance issues for scripts that contain a large number of dynamic variables. The more data they contain, the longer it can take to process each action.

Key Facts about Dynamic Data Objects

  • The values that a dynamic data object holds are called members.
  • Each member is identified by a name. For example, in beowulfCharacteristics.occupation, beowulfCharacteristics is the object and occupation is the name of one of its members.
  • The type of the object's members is determined at run time. The compiler saves the information about the properties. At run-time, the information is examined and acted on. Because of this, the compiler doesn't catch errors with dynamic data objects. Instead, errors cause run-time exceptions.
  • Dynamic data objects can have dynamically-created members. After declaring a dynamic data object in your script, you assign values to members of the object on subsequent lines. You can even assign values to members in other snippets. If the members don't exist, they're automatically created and the specified values assigned to them.
  • Dynamic data objects can store many types of data. Standard Snippet variables are implicitly typed, which means the type is determined when the Studio compiler compiles the code.  Dynamic data objects are type DynamicData. An object's members are implicitly typed.
  • Case-sensitivity matters when referencing the members of a dynamic data object. For example, if you attempted to parse the value of beowulfCharacteristics.files.file with ASSIGN fileContent = "{beowulfcharacteristics.Files.file}", it would return nothing. This is because the dynamic object member Files.file is not the same as files.file.
  • All members of dynamic data objects have a special property, $value. You cannot assign a value to this property. It allows you to perform certain actions with the member that otherwise wouldn't work.
  • Dynamic data objects and their members must be less than 32 KB. When converting an object to JSON or XML, the resulting content must be less than 32 KB. If a converted object's content exceeds that limit, it is truncated.

Try it Out

Download the Object Examples script and import it into Studio. Some of the examples from this help page are available in Snippet actions in the example script. You can open the Snippet editor window and run the debugger to see how each example works.

Object Members

Dynamic data objects hold their properties, also called members, in the form of key/value pairs. The key is the name of the member and is like the name of a variable within the object. In the following example, the keys are name, occupation, and foe. Each key has a value associated with it, which is enclosed in double quotes on the right side of the equal sign.

DYNAMIC beowulfCharacteristics
beowulfCharacteristics.name = "Beowulf"
beowulfCharacteristics.occupation= "Hero" 
beowulfCharacteristics.foe = "Grendel" 

Dynamic data objects allow you to reduce the number of variables you use in a script. The preceding example shows how you can use a single object to hold three values instead of creating three unique variables. 

The members of dynamic data objects can have their own sets of members. These submembers follow the same rules as the first-level members. For example: 

DYNAMIC beowulfFoes
beowulfFoes.foe1.name = "Grendel"
beowulfFoes.foe1.type = "monster"
beowulfFoes.foe1.status = "defeated"
beowulfFoes.foe2.name = "Grendel's mother"
beowulfFoes.foe2.type = "monster"
beowulfFoes.foe2.status = "defeated" 

Dynamic Data Object Syntax Summary

This section summarizes the syntax related to using dynamic data objects in Studio scripts. You can learn more in the other sections on this page.

Declare a dynamic data object using this syntax:

DYNAMIC <objectName> [FROM 'string' | var]

The <objectName> must follow the same naming guidelines as standard variables in Studio. Object names are case-sensitive.

The FROM clause is optional. You can use it to create an object from the contents of a string 'string'or a script variable varthat contains a JSON or XML string. If you use a 'string' it must be entirely on a single line and enclosed in single quotes.

Add members to an object using this syntax:

<objectName>.<memberName> = "value".

Member names are case-sensitive. You don't have to use a keyword to add members to an object, but you can use ASSIGN if you want to.

Create an array in a dynamic data object using this syntax:

DYNAMIC <object>

ASSIGN <object>.<member>[<index>].<sub-member>= "value"

Declare Dynamic Data Objects

To declare a dynamic data object, use the keyword DYNAMIC in your code before the variable name, then add properties to it. For example: 

DYNAMIC beowulfCharacteristics
ASSIGN beowulfCharacteristics.name = "Beowulf"
ASSIGN beowulfCharacteristics.occupation= "Hero" 
ASSIGN beowulfCharacteristics.foe = "Grendel"

You don't need a keyword to declare object members. You can use ASSIGN, if you want to. Referencing a member dynamically creates the member if it doesn't already exist.

Refer to a Dynamic Data Object Member

When you need to use a value that a dynamic data object contains, you must refer to the member that holds the value. Use the following syntax: 

<dynamicObjectName>.<memberName>

You can use this in the same way you would a standard variable. You can reference dynamic data objects in any Studio action property that accepts variable substitution, as well in snippets.

For example, to refer to the name member of the following object, you would use beowulfCharacteristics.name.

DYNAMIC beowulfCharacteristics
beowulfCharacteristics.name = "Beowulf"
beowulfCharacteristics.occupation= "Hero" 
beowulfCharacteristics.foe = "Grendel" 

Special Object Property $value

Dynamic data objects have a special property, $value. This property allows you to do things with objects and their values in ways that otherwise wouldn't be possible. You can use it to: 

  • Use a function with a member of an object. For example: beowulfCharacteristics.name.first.$value.length(). You can learn more about running functions with objects in the next section.
  • Copy a value from a dynamic data object property into a regular variable using the $value property: x = name.first.$value.

You cannot assign a value to $value. It's read-only.

Functions with Objects

Functions are blocks of code that can be called and run in your script. Functions allow you to interact with the values in a variable or object. Functions can modify values or tell you something about them. For example, there are functions that can transform the case of a variable or object member's value. There are other functions that can count the number of elements in an array or tell you if a value is numeric.

There are a number of functions available that you can use with the dynamic data objects in your scripts. You can only run functions on object members, not on the objects themselves.

To use a function with an object, use the special object property $value. This property is read-only and does not result in a $value property being created in the object. It prevents the name of the function from being made a property of the object. It returns the literal string value of the object member it's used with.

Use the following syntax to run a function on an object member: obj.member.$value.function().

For example, to run the length() function on name.first, you would use:

 ASSIGN length = name.first.$value.length().

Copy Object Values to another Object or Variable

You can create a copy of the data an object holds if you want two versions of the data. This allows you to change one without affecting the other. To do this, use the built-in copy() function following this syntax:  

DYNAMIC <object1>

DYNAMIC <object2>

<object1> = copy(<object2>)

The variable you copy data into can be a dynamic object or a standard Studio variable. If it's a standard variable, it's automatically converted into a dynamic object.

The copy() function uses more system resources than assigning a reference does. It performs a deep copy by converting the object into a textual representation, and then back into an object. If the object you're working with contains a large amount of data, this process could impact the functioning of the script.

You can copy the value from a dynamic object's submember into the submember of another dynamic object. The copy() function doesn't work with submembers, so you need to set the variables equal to each other: 

DYNAMIC currentContact
currentContact.who = beowulfCharacteristics.name

You can copy the value from a dynamic object's submember into a standard variable. This automatically causes the variable to be converted into a dynamic object. To prevent this, the name of the dynamic object and submember you're copying must be enclosed in double quotes and curly braces. This prevents the variable from being converted into a dynamic object. For example: 

ASSIGN currentContact = "{beowulfCharacteristics.foe}"

An alternative to formatting the name of the object is adding the $value property:

ASSIGN currentContact = beowulfCharacteristics.foe.$value

Assign a Reference to an Object Value to Another Object or Variable

You can assign a reference to a dynamic data object to another dynamic object. For example: 

DYNAMIC beowulfCharacteristics
ASSIGN beowulfCharacteristics.name = "Beowulf"
ASSIGN beowulfCharacteristics.occupation= "Hero" 
ASSIGN beowulfCharacteristics.foe = "Grendel"

DYNAMIC currentContact

ASSIGN currentContact = beowulfCharacteristics

After the above assignment, currentContact and beowulfCharacterics both reference the same physical data. If you change the value of a submember in either dynamic object, the value also changes in the other object. For example, if you change currentContact.name to Beowulf Herot, the value of beowulfCharacteristics.name automatically updates to Beowulf Herot. Similarly, if you change the value of beowulfCharacteristics.name to Sparky, the value of currentContact.name automatically updates to Sparky.

You cannot assign a reference to an individual submember. You can copy the value of a submember from one dynamic object to another. This duplicates the value. If you change value of one, it does not automatically change the other value.

Create a Dynamic Data Object from JSON or XML

You can use a dynamic data object to parse JSON or XML. 

Define the dynamic data object and use the FROM command to specify the JSON or XML data with this syntax: 

DYNAMIC <objectName> [FROM 'string' | var]

You can specify a 'string' that contains JSON or XML data. You can also specify the name of a script variable var that contains a JSON string or XML data. If you use a 'string' it must be entirely on a single line. If the 'string' breaks to a second line, it causes an error.

For example: 

DYNAMIC beowulfWeapons FROM '{ "key1": "Hrothgars gift", "key2": "Hrunting", "key3": "Naegling"}'

The results of this are: 

beowulfWeapons.key1 = "Hrothgars gift"  
beowulfWeapons.key2 = "Hrunting" 
beowulfWeapons.key3 = "Naegling"

If the JSON key-value pairs used in the preceding example were contained in a variable called famousSwords, you could create the dynamic data object like this instead: 

DYNAMIC epicMonsterDoom FROM famousSwords

The results are the same with both methods of creating the object.

In Studio, __type (with two underscore characters) is used when parsing JSON. It cannot be used as a key name in dynamic data variables, because they can parse JSON. If you use it as a key name in a dynamic data variable, it will cause an error when you save the script or when the script executes the action.

Assign a JSON String to a Variable

Another option when working with JSON strings is to assign them to a variable instead of a dynamic object. This is not the preferred method of working with JSON strings. It doesn't give you the flexibility of managing and working with your code that having JSON in dynamic objects does. However, there may be times when it's necessary.

Before you can assign a JSON string to a variable, you must replace the curly brace ( { ) and double quote ( " ) characters with escaped characters. You can use a text editor to replace the characters manually or the replace() function to do it in the script. In the variable assignment, the JSON string must be prefixed with a dollar sign ( $ ), as shown in the following example. The dollar sign indicates a value that contains escaped characters.

ASSIGN customPayloadFromBotJson = $"\{\"prompts\": [\{\"mediaSpecificObject\": \{\"dfoMessage\": \{\"messageContent\": \{\"type\": \"PLUGIN\", \"payload\": \{\"elements\": [\{\"id\": \"bf2521f4-5e85-413f-b6ed-815d1c3905f0\", \"type\": \"FILE\", \"filename\": \"photo.jpg\", \"url\": \"https://www.nice.com/-/media/niceincontact/layout/nice-logo-web-header/nice-web-logo.ashx\", \"mimeType\": \"image/jpeg\"}]}}}}}]}"
		

Create a Dynamic Data Object from a REST Response

Dynamic data objects are automatically created from responses from REST API calls. These responses can be in JSON or XML. Studio converts them to dynamic data objects in the script. For example:

ASSIGN GetRequest = "<API Endpoint>"
ASSIGN DynamicReturn = Proxy.MakeRestRequest(GetRequest,"",0,"GET")
ASSIGN fileContent = "{DynamicReturn.files.file}"

In this example, the MakeRestRequest() function returns a dynamic data object, DynamicReturn. You don't need to use the DYNAMIC keyword with this variable because the script automatically makes it a dynamic data object.

To parse the dynamic data object that contains the REST response, use ASSIGN fileContent = "{DynamicReturn.files.file}". This assigns the extracted value ({DynamicReturn.files.file}) to the fileContent variable. You can also use ASSIGN fileContent = DynamicReturn.files.file.$value to parse the response.

Prepare Payload Data for REST API Calls

You can prepare payload data for REST API calls and send them as JSON using the asjson() function. The preferred method for this task is to use the REST API action. However, you can also accomplish it in a snippet. For example:

DYNAMIC tokenInput
ASSIGN tokenInput.grant_type = "password"
ASSIGN tokenInput.username = "Grendel.Cainson"
ASSIGN tokenInput.password = "MadeUpPassword"
	<additional tokenInput properties> 
ASSIGN tokenJsonInput = "{tokenInput.asjson()}"
ASSIGN proxy = GETRESTProxy()
<ASSIGN additional variables as needed>
ASSIGN tokenResponse = proxy.MakeRestRequest(TokenRequestURL,TokenJsonInput, 0, "POST")

In this example, TokenInput is declared as a dynamic object with three members, grant_type, username, and password. TokenJsonInput is declared to hold TokenInput in a stringified form using the asjson() function. In the last line of the example, the variable TokenResponse is declared to hold the REST request, which can then be used in the script code to send the request.

Convert a Dynamic Data Object to JSON or XML

You can convert the contents of a dynamic object to a JSON or XML string. This serializes the data in the object and puts it into a format that can be transmitted over the Internet.

To do this, use the asjson() or asxml() function with the object you want to convert. In Studio, you can do this in one of two places, either in a Snippet action or in the action property that needs the converted data from the object.

Both approaches work the same. However, the benefit of creating a variable in a Snippet to hold the converted object is that it makes it easier to see where the conversion is happening. You don't need to know which action requires the converted contents of the object.

To convert an object in a Snippet, use the following syntax:

ASSIGN varJSON="{myDynamic.asjson()}"

In the property of the Studio action where you need the JSON or XML data, use the name of the variable you used in the Snippet. From the syntax example, you would configure the action property with varJSON.

To convert an object in the action property, configure the action property with the name of the object and the asjson() or asxml() function in curly braces. For example: {myDynamic.asjson()}.

All members of a dynamic object are treated as string values, including numeric and BooleanClosed A data type that has two possible values: true and false. values. For values that aren't strings, you need to manually parse the JSON to remove the double quotes. You can do this using the replace() function.

Handle Special Characters in JSON Keys

Special characters in variable names causes errors in Studio. If the JSON you're working with has keys with special characters in the name, you must work around this limitation. For example, this can be an issue when working with headers that contain the CONTENT-TYPE key-value pair. When in a dynamic object, an object member such as requestPayload.HEADERS.CONTENT-TYPE = "APPLICATION/JSON" would cause an error.

One solution is to replace the special character with text in the dynamic object. After converting the object to JSON, replace the text with the correct special character. The following example shows a dynamic object member that holds a CONTENT-TYPE key where the text HYPHENPLACEHOLDER has been used in place of the hyphen ( - ):

ASSIGN requestPayload.HEADERS.CONTENTHYPHENPLACEHOLDERTYPE = "APPLICATION/JSON"
ASSIGN requestPayloadJSON = "{requestPayload.asjson()}"
ASSIGN requestPayloadJSON = "{requestPayloadJSON.replace("HYPHENPLACEHOLDER", "-")}"

The second and third lines in the preceding example show the dynamic object being converted to JSON, then the replace() function being used to replace HYPHENPLACEHOLDER with the hyphen character.

View Contents of Dynamic Objects

You can view the contents of dynamic objects in the Snippet editor window when you run the debugger. This allows you to verify that the object holds the data it's supposed to at each step in your code.

  1. In Studio, double-click on a Snippet action.
  2. Add snippet code, if necessary.
  3. On the Debugger tab, click the Variables as Tree tab.
  4. On the Debugger tab, click the down arrow next to the Start Debugging icon An image of a triangular green play buttonand select Step Into A series of horizontal lines with an arrow pointing from one line to the one beneath it. . If you don't want to step through the code line by line, click the Start Debugging icon.
  5. Click the Step A series of horizontal lines with an arrow pointing from one line to the one beneath it. icon and observe the contents on the Variables as Tree tab. Each time you click Step, this field updates with the variables and objects in the script after the previous line of code. Skip this step if you clicked Start Debugging.
  6. When you have stepped through all lines of code or if you clicked Start Debugging, the Variables as Tree tab displays all variables, objects, and their contents at the end of the snippet.
  7. You can click the + icon next to any string arrays or dynamic objects in the code to expand them. If the content is another array or object, you can continue to expand the tree to see what each entity contains.

Script Validation Error and Dynamic Objects

When you save a script, Studio validates all the information in it. One of the things it checks for is that all dynamic objects referenced in the script are declared in the script. Studio requires an object declaration for all objects referenced in the script being validated. Even if the object is declared in another script and passed into the one being validated, it still causes the error. If you have an undeclared object in your script, you see a "Function '[name]' has not been defined " error when you save.

There are two ways you can avoid this. One option is to add an IF statement with a TEST variable to the snippet where you reference the object. In the curly braces of the IF statement, declare the dynamic object. For example: 

IF TEST = 1
{
	DYNAMIC dynaObject
}
DYNAMIC dynaObject.prop = 1

The second option is to add a SNIPPET to the script that contains the object declaration and nothing else. If multiple objects are passed into the script, you can declare them all in a single SNIPPET. This is helpful to keep the other SNIPPET actions in your script uncluttered. You don't need to connect this action to other actions in the script. Its existence in the script is enough to satisfy the script's need for object declarations during validation.