Variables are a basic feature of most programming languages. A variable provides a mechanism for the programmer to store and retrieve data by name. Variables typically store data of a particular type. Basic data types include strings, numbers, or boolean (logical) values. Most programming languages support the creation of a collection or list of variables of the same type known as an array. Sophisticated programming languages allow the programmer to create new data types composed of groupings of the more basic data types. These are known as data structures.
Rather than hardcoding strings and numbers throughout a program, variables provide a useful alternative that helps increase the reusability and maintainability of an application. Simply changing the value of a variable in one place can modify the behavior of an entire program. VoiceXML supports the declaration, the setting, and the retrieval of variables.
VoiceXML supports five variable scopes:
|session||a read-only scope containing variables declared by the VoiceXML interpreter and pertaining to the current user session. Session variables are available for the lifetime of the session. See System session variables for a list of system variables declared in this scope.|
|application||a read/write scope containing global variables visible throughout the application and for the lifetime of the application. To create a variable with application scope, declare it in the application root document.|
|document||a read/write scope containing variables visible within the document in which they are declared. To create a variable at document scope, declare it as a child element of the vxml element in the desired VoiceXML document. The variable is initialized each time the VoiceXML interpreter loads the document in which the variable is declared. Once the VoiceXML interpreter navigates to a different VoiceXML document, the variable goes out of scope. Navigating between different dialogs in the same document does not cause the variable to go out of scope.|
|dialog||a read/write scope containing variables visible within the dialog in which they are declared. To create a variable at dialog scope, declare it as the immediate child of the desired form element in a VoiceXML document. If the dialog contains a field, the value of the name attribute defines a variable at dialog scope with that name. Variables with dialog scope are initialized each time the VoiceXML interpreter enters the dialog. Once the VoiceXML interpreter navigates to a different dialog, these variables go out of scope.|
|anonymous||a read/write scope containing variables visible within the block element in which they are declared. The VoiceXML interpreter initializes a variable with anonymous scope when it enters the anonymous block. The interpreter destroys the anonymous variables when it leaves the block.|
Regardless of a variable's scope, the VoiceXML specification requires you to declare a variable before you use it. To declare a variable, do one of the following:
Variable names must conform to the ECMAScript specification:
In addition, VoiceXML adds the following requirements:
Variables beginning with an underscore or terminating with a dollar sign are reserved for internal use by the VoiceXML interpreter.
In the following example, the first declaration creates a variable with an undefined initial value. The second declaration creates a variable with an initial value of false. The third declaration creates a variable with an initial value set to a floating point value. The fourth declaration creates a variable with an initial value set to a string.
<var name="iStudentID" /> <var name="bLoggedIn" expr="false" /> <var name="fSalary" expr="35000.00"/> <var name="sGreeting" expr="'Hi, there.'" />
<var name="sGreeting" expr="'Hello, '" /> <var name="sFullGreeting" expr="sGreeting + 'Mr. President'" />
In a VoiceXML document, variables are initialized in document source order. This allows variables that have already been declared to be referenced in the expr attribute of subsequent variable declarations. In the following example, after declaring the variables audio_dir and welcome_wav, the variable audio_path can be declared with an initial value that concatenates the values of the previously declared variables.
Note. In ECMAScript, the plus (+) operator supports the addition of numbers as well as the concatenation of strings.
<!-- relative location of audio files --> <var name="audio_dir" expr="'ui/misc/'" /> <!-- name of audio file containing welcome prompt --> <var name="welcome_wav" expr="'welcome.wav'" /> <var name="audio_path" expr="audio_dir+welcome_wav" />
In addition to using the var element to declare a variable, you can also declare variables using the script element. The variables assume the scope of the element that contains the script element.
<script> var goodbye_wav = "goodbye.wav"; </script>
Once declared, a variable can be referenced and assigned a new value. To modify the value of a variable, use the assign element or set the value of the variable within a script element.
<var name="sCurrentState" expr="'welcome'" /> <assign name="sCurrentState" expr="'enrolling'" /> <script> sCurrentState = "dropping"; </script>
While the var element is allowed as a child of both the vxml and form elements in order to support the creation of variables at document and dialog scope, the assign element is only supported within executable contexts. An executable context occurs within the following elements: block, filled, catch, help, noinput, nomatch, prompt, foreach, and if.
The previous sections have gone into depth about the declaration and usage of scalar variables. A scalar variable represents a block of data such as an integer, a float, a string, or an object. VoiceXML also supports the declaration and manipulation of ordered lists of data known as arrays. Because variables in ECMAScript are loosely typed, an array can contain elements of different types.
The following code snippet demonstrates several ways to declare an array. The first var element declares an empty array. The second declares an array containing five strings. The third declares an array containing three elements of different types - a number, a string, and a boolean. As shown, you can also declare arrays using a script. Like scalar variables, arrays declared in a script element have the scope of the element in which the script element is contained.
<var name="arrEmpty" expr="new Array()"> <var name="arrWeekdays" expr="new Array('Mon', 'Tue', 'Wed', 'Thu', 'Fri')"/> <var name="arrInfo" expr="[12345, 'Bob', false]"/> <script> var arrPets = new Array("dog", "cat", "ferret"); var arrNames = ["Fido", "Fluffy", "Mario"]; </script>
Once declared, you can modify the contents of an array using the assign element or within a script element. Arrays are indexed starting at 0. You can determine the number of elements in an array by checking the length property exposed by the array.
<assign name="arrInfo" expr="true"/> <!-- modify the 3rd element --> <script> arrPets[arrPets.length] = "turtle"; // add a new pet arrNames.push("Gloria"); // add a name </script>
The following example uses the foreach element to iterate through the elements of an array:
<prompt>You have registered <value expr="arrPets.length"/> pets.</prompt> <foreach item="pet" array="arrPets"> <prompt>a <value expr="pet"/></prompt> <break time="300ms"/> </foreach> <prompt>The name of the <value expr="arrPets"/> is <value expr="arrNames"/>.</prompt>
A form item is one of the following elements:
A form item has an associated form item variable, which, by default, is set to undefined when the containing form is entered. Upon execution of the Form Interpretation Algorithm (FIA), a form item variable will contain the result of interpreting the form item. Form item variables corresponding to the field, initial, record, and transfer elements are also called input item variables because they hold the value collected from the user.
The interpreter creates an implicit variable for any form item that you do not name explicitly. Although the variable names are currently predictable, your application code should not rely upon them since they are likely to change in a future release. To manipulate the variable associated with a form item you must explicitly set its name attribute. If you attempt to reference an implicitly declared form item variable, the following deprecation warning will appear in the Debug Log for your application:
"possible direct access of internal variable"
In your voice applications, you will typically specify the name attribute of a field element to access the result of a recognition. The form item variable that corresponds to the field can be referenced from other elements contained within the dialog that contains the field. To access the value of the variable from other dialogs within the same document, assign the value to a variable at document scope. To access the value in other dialogs from other documents within the same application, assign the value to a variable at application scope.
The following table describes the session variables supported by the Tellme Platform:
|session.call.uuid||The universally unique identifier (UUID) associated with the current call. The UUID is generated as specified in RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace. The variable is commonly used to correlate your Web server's log data with Tellme's logs for a given call. This variable is a Tellme Extension.|
|session.connection.remote.uri||The URI of the remote user's device. For an inbound connection made to the Tellme Voice Application Network, this is the URI of the caller's device. For an outbound connection made from the Tellme Voice Application Network, this is the URI of the callee's device.|
|session.connection.local.uri||The URI of the local interpreter context. For an inbound connection made to the Tellme Voice Application Network, this is the URI specified by the caller. For example, if the user calls 1-800-555-TELL, the value of this variable is "tel:+18005558355".|
|session.telephone.ani||Deprecated. Use session.connection.remote.uri instead.|
|session.telephone.dnis||Deprecated. Use session.connection.local.uri instead.|
According to the VoiceXML 2.0 specification, the telephone object has been deprecated in favor of the more flexible connection object. Tellme, however, maintains support for the telephone object for backwards compatibility with existing voice applications. For more information on Tellme's support for the connection object, see the Connection Object Reference.
In VoiceXML, variable scopes are organized in a hierarchy. The lifetime of variables in some scopes overlap with the lifetime of variables declared in other scopes:
The following example demonstrates how scoping rules impact the state of a program. As execution of the program proceeds to comment A, the variable var1 exists at three different scopes - document, dialog, and anonymous - with three distinct values - 1, 3, and 6 respectively. In this case, the assign element manipulates the var1 declared at anonymous scope because the declaration shadows that of the var1 declared at dialog and document scope.
As execution of the program proceeds to comment B, the variable var1 only exists at two scopes, document and dialog, although it is accessible at the anonymous scope defined by the block that encloses the comment. The value of var1 at document scope is still 1. The value of var1 at dialog scope is now 4. The assign element manipulates the var1 declared at dialog scope because its declaration shadows that of the var1 declared at document scope, and the var1 declared in the anonymous scope that contains comment A has fallen out of scope.
As execution of the program proceeds to comment C, the variable var1 exists at a single scope, document, although it is accessible at dialog and anonymous scope. The value of var1 at document scope is increased to 2.
<?xml version="1.0"?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <var name="var1" expr="1" /> <form id="form1"> <var name="var1" expr="3" /> <block> <var name="var1" expr="5" /> <assign name="var1" expr="var1+1" /> <!-- A --> </block> <block> <assign name="var1" expr="var1+1" /> <!-- B --> </block> </form> <form id="form2"> <block> <assign name="var1" expr="var1+1" /> <!-- C --> </block> </form> </vxml>
If two variables in overlapping scopes are declared with the same name, the VoiceXML interpreter manipulates the variable at innermost scope. The programmer can override this behavior through explicit scoping. To explicitly reference a variable at an outer scope that is hidden, prefix the variable with the name of the desired scope and a period (.).
In the following example, when execution of the program proceeds to comment A, the value of var1 at document scope is increased from 1 to 2, the value of var1 at dialog scope is increased from 10 to 20, and the value of var1 at anonymous scope maintains its initial value of 100.
<?xml version="1.0"?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <var name="var1" expr="1" /> <form id="form1"> <var name="var1" expr="10" /> <block> <var name="var1" expr="100" /> <assign name="document.var1" expr="document.var1+1" /> <assign name="dialog.var1" expr="dialog.var1+10" /> <!-- A --> </block> </form> </vxml>
In the following example, a pause value is assigned to the variable iPause. The timeexpr attribute of the break element accepts the variable. In addition, the value element is used to specify the TTS text of the prompt element.
<var name="sWelcome" expr="'welcome to tell me university'" /> <var name="iPause" expr="300" /> <var name="sPhoneNum" expr="6509309000" /> <var name="xfer_timeout" expr="20"/> <var name="xfer_max" expr="120"/> <prompt> <value expr="sWelcome" /> </prompt> <break timeexpr="iPause" />
The following example declares three variables at document scope and assigns them initial values in an initialization dialog. The second variable assignment references the first variable to establish the path to an audio file. The third variable establishes a standard pause length. The welcome dialog uses the welcome_wav variable as the value of the expr attribute of an audio element. The std_pause variable is used to set the timeexpr attribute of a break element. Because the variables are declared at document scope, they can be referenced by all dialogs contained within that document.
<?xml version="1.0"?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <var name="audio_path" /> <var name="welcome_wav" /> <var name="std_pause" /> <form id="init"> <block> <assign name="audio_path" expr="'ui/'" /> <assign name="welcome_wav" expr="audio_path + 'intro.wav'" /> <assign name="std_pause" expr="300" /> </block> </form> <form id="welcome"> <block> <audio expr="welcome_wav" /> <break timexpr="std_pause" /> </block> </form> </vxml>
In the following example, the return value from a grammar is used to formulate the path to an audio file that explicitly confirms the user's selection. The get_class dialog accepts the name of a class from the user. The return value corresponding to the class name is stored in selected_class, a variable scoped to the document. Control transfers to the confirm_class dialog, another interactive dialog, which contains a prompt that uses the selected_class variable to reference an audio file that contains the recorded name of the class.
<?xml version="1.0"?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <var name="selected_class" /> <form id="get_class"> <field name="class_id"> <!-- Say a class name. --> <prompt> <audio src="ui/sayclass.wav" /> </prompt> <grammar mode="voice" root="root_rule" tag-format="semantics/1.0" type="application/srgs+xml" version="1.0" xml:lang="en-US"> <rule id="root_rule" scope="public"> <one-of> <item> <one-of> <item> build <item repeat="0-1"> me </item> </item> </one-of> <tag>out.class_id = "1";</tag> </item> <item> <one-of> <item> design <item repeat="0-1"> me </item> </item> </one-of> <tag>out.class_id = "2";</tag> </item> <item> <one-of> <item> produce <item repeat="0-1"> me </item> </item> </one-of> <tag>out.class_id = "3";</tag> </item> <item> <one-of> <item> tune <item repeat="0-1"> me </item> </item> </one-of> <tag>out.class_id = "4";</tag> </item> </one-of> </rule> </grammar> <catch event="nomatch noinput"> <prompt>Sorry. I didn't get that.</prompt> <reprompt /> </catch> <filled> <assign name="selected_class" expr="class_id" /> <goto next="#confirm_class" /> </filled> </field> </form> <form id="confirm_class"> <field name="yesno" type="boolean"> <prompt> <!-- I heard you say XXX. Is that correct? --> <audio src="ui/heardsay.wav" /> <audio expr="'ui/classes/cn' + selected_class + '.wav'" /> <audio src="ui/iscorrect.wav" /> </prompt> <catch event="nomatch noinput"> <prompt>Sorry. I didn't get that.</prompt> <reprompt /> </catch> <filled> <if cond="yesno"> <goto next="#class_detail" /> <else /> <goto next="#get_class" /> </if> </filled> </field> </form> <form id="class_detail"> <!-- code to output detail about the class goes here --> </form> </vxml>
The Tellme VoiceXML interpreter supports playback of recorded and synthesized audio through the audio element. In the following example, the VoiceXML interpreter plays the audio in the file intro.wav in a ui directory. If the audio is unavailable, the VoiceXML interpreter converts the text between the opening and closing audio elements to speech and plays it back to the user.
<audio src="ui/intro.wav"> welcome to tell me university </audio>
The Tellme VoiceXML interpreter also supports the use of expressions to refer to recorded audio through the expr attribute.
<var name="sPathEarcons" expr="'http://naturalsound.svc.tellme.com/common-audio/'" /> <audio expr="sPathEarcons + 'intellipause.wav'" />
By using a variable to specify the path portion of your audio, you can more easily version your audio. Changing the server upon which your audio is located only requires updating the value of the variable where its value is assigned. You will typically declare a variable with this purpose at application scope so that it is visible throughout your application.
To use a variable in place of hard-coded text for the TTS portion of an audio element, use the value element.
<var name="sTTS" expr="'welcome to tell me university'" /> <var name="sWav" expr="'ui/intro.wav'" /> <audio expr="sWav"> <value expr="sTTS" /> </audio>
VoiceXML supports several elements that allow interaction with an HTTP server:
|data||Provides programmatic access to data in XML format from an HTTP server without transitioning to a new VoiceXML document.|
|goto||Jumps to the specified URI.|
|submit||Obtains a new document via an HTTP GET or POST request.|
|subdialog||Jumps to and executes an encapsulated dialog|
While you can use these elements to retrieve a static document, you can also use them to retrieve dynamic content from an application server (e.g. CGI script). You can parameterize your request by submitting variables using one of two mechanisms. The first uses the namelist attribute and is supported by the data, submit, and subdialog elements. Simply set the value of the namelist attribute to space-delimited list of the variables that you want to submit.
The following example uses a submit element to send the variables fname and ssn to a CGI script named collect.cgi.
<var name="fname" expr="'John'"/> <var name="ssn" expr="'033761234'"/> <submit next="collect.cgi" namelist="fname ssn"/>
Since the goto element doesn't support the namelist attribute, you can use the expr attribute to construct the query string manually. Note, however, that the goto element always submits an HTTP GET request while you can set the method attribute of the submit element to the value POST to send an HTTP POST request.
<goto expr="'collect.cgi?fname=' + escape(fname) + '&ssn=' + escape(ssn)" />