Lesson 7 -- VoiceXML Scripting Elements and Subdialogs

This lesson covers several more VoiceXML elements that you need to know about. The following subjects are included:

  • Using VoiceXML's own scripting elements—sometimes more convenient than JavaScript.

  • Subdialogs—a way of writing reusable VoiceXML code.

  • A new version of app-root.vxml—that uses a subdialog for confirmation prompting.

Using VoiceXML's own scripting elements

We have seen that JavaScript can be used in VoiceXML applications by enclosing the JavaScript code in <script> tags. Legal parents for the <script> element are: <block>, <catch>, <error>, <filled>, <foreach>, <form>, <help>, <if>, <menu>, <noinput>, <nomatch>, <prompt>, and <vxml>. This means that you can use JavaScript almost anywhere in your VoiceXML application.

Apart from declaring variables, assigning values to them, and referencing them (as discussed in Lesson 1), VoiceXML has some limited scripting capabilities of its own that can be used to perform conditional logic or to iterate through an array. These scripting capabilities use the <if>, <elseif/>, <else/>, and <foreach> elements. Legal parents for these elements are: <block>, <catch>, <error>, <filled>, <foreach>, <help>, <if>, <noinput>, <nomatch>, and <prompt>.

Comparing the two lists of parents, you can see that you can use the VoiceXML scripting elements everywhere you can use JavaScript, except in the <form>, <menu>, and <vxml> elements. You can use the VoiceXML scripting elements in a <form> element if you enclose them in <block>...</block> tags.

The <if>, <elseif/>, and <else/> elements

The <if> and <elseif/> elements each have a single, required attribute, cond, which must be equal to a JavaScript expression that evaluates to true or false. For example:

<if cond="JavaScriptExpression">{
   <!-- VoiceXML statements -->
}
<elseif cond="JavaScriptExpression"/>{
   <!-- VoiceXML statements -->
}
<elseif cond="JavaScriptExpression"/>{
   <!-- VoiceXML statements -->
}
.....<!-- more elseif statements, as needed -->

<else/>{
   <!-- VoiceXML statements -->
}
</if>

Note

The brackets, { and }, that are used when there is more than one statement following an <if>, <elseif/>, or <else/> element are required in JavaScript. In the VoiceXML elements, they are optional.

The <elseif/> and <else/> elements are optional. If their JavaScriptExpression evaluates to true, the immediately following VoiceXML statements are executed and all subsequent <elseif/> or <else/> statements are ignored.

Note

The <if> element uses opening and closing tags: <if>...</if>. The <elseif/> and <else/> elements are standalone tags that are used between the <if>...</if> tags—they do not have independent closing tags.

The cond attribute considers expressions that evaluate to 0, -0, null, false, NaN, undefined, and the empty string to be false. All other values (including the strings "0" and "false") are equivalent to true.

Important

JavaScript included within a cond attribute is first evaluated as XML, so XML special characters must be written as XML entities. Use the entities &lt;, &gt;, or &amp;&amp; in place of the less-than (<), greater-than (>), or and (&&) symbols in an <if> element.

The VoiceXML construct above is entirely equivalent to conditional JavaScript like this:

<script> <![CDATA[
if (JavaScriptExpression) {
      JavaScript statements;
}
else if (JavaScriptExpression){
      JavaScript statements;
}
else if (JavaScriptExpression) {
      JavaScript statements;
}
........
more else if statements, as needed
........
else{
      JavaScript statements;
}
   ]]> </script>

As with the VoiceXML code, JavaScriptExpression must be a JavaScript expression that evaluates to true or false.

Replacing the switch statement for main_selection

In app-root.vxml, we have been using JavaScript switch statements in the <filled> elements for the main_selection and new_reservation_type fields. These could be replaced with VoiceXML code that uses the <if>, <elseif/>, and <else/> elements.

Here is the switch statement code we have been using in the main_selection field:

<script><![CDATA[
   var next_destination = " ";
   switch (main_selection){

      case "new reservation" :
         next_destination = "#new_reservation";
         break;

      case "1" :
         next_destination = "#new_reservation";
         break;

      case "change reservation" :
         next_destination = "change-reservation.vxml";
         break; 

      case "2" :
         next_destination = "change-reservation.vxml";
         break;

      case "restaurant recommendation" :
         next_destination = "restaurant.vxml";
         break;

      case "3" :
         next_destination = "restaurant.vxml";
         break;

      default:
         next_destination = "error.vxml";
         break;
   }

]]></script>

All this JavaScript code can be replaced with this VoiceXML code:

<var name="next_destination" expr="' '"/>
<if cond="main_selection == 'new reservation' ||
          main_selection == '1'">
   <assign name="next_destination" expr="'#new_reservation'"/>
<elseif cond="main_selection == 'change reservation' ||
              main_selection == '2'"/>
   <assign name ="next_destination" expr="'change-reservation.vxml'"/>
<elseif cond="main_selection == 'restaurant recommendation' ||
              main_selection == '3'"/>
   <assign name ="next_destination" expr="'restaurant.vxml'"/>
<else/>
   <assign name ="next_destination" expr="'error.vxml'"/>
</if> 

Replacing the switch statement for new_reservation_type

Here is the switch statement code we have been using in the new_reservation_type field:

<script>
<![CDATA[
   var next_destination = "";
   switch (new_reservation_type){

      case "plane" :
        next_destination = "new-plane.vxml";
        break;

      case "hotel" :
        next_destination = "new-hotel.vxml";
        break;

      case "car" :
        next_destination = "new-car.vxml";
        break;

      case "plane and hotel" :
        next_destination = "new-plane.vxml";
        doNewHotelRes = true;
        break;

      case "plane and car" :
        next_destination = "new-plane.vxml";
        doNewCarRes = true;
        break;

      case "hotel and car" :
        next_destination = "new-hotel.vxml";
        doNewCarRes = true;
        break;

      case "plane and hotel and car" :
        next_destination = "new-plane.vxml";
        doNewHotelRes = true;
        doNewCarRes = true;
        break;

      default:
        next_destination = "error.vxml";
        break;
   }
]]>
</script>

All this JavaScript code can be replaced with this VoiceXML code:

<var name="next_destination" expr="' '"/>
<if cond="new_reservation_type == 'plane'"/>
   <assign name ="next_destination" expr="'new-plane.vxml'"/>
<elseif cond="new_reservation_type == 'hotel'"/>
   <assign name ="next_destination" expr="'new-hotel.vxml'"/>
<elseif cond="new_reservation_type == 'car'"/>
   <assign name ="next_destination" expr="'new-car.vxml'"/>
<elseif cond="new_reservation_type == 'plane and hotel'"/>{
   <assign name ="next_destination" expr="'new-plane.vxml'"/>
   <assign name ="doNewHotelRes" expr="true"/>
}
<elseif cond="new_reservation_type == 'plane and car'"/>{
   <assign name ="next_destination" expr="'new-plane.vxml'"/>
   <assign name ="doNewCarRes" expr="true"/>
}
<elseif cond="new_reservation_type == 'hotel and car'"/>{
   <assign name ="next_destination" expr="'new-hotel.vxml'"/>
   <assign name ="doNewCarRes" expr="true"/>
}
<elseif cond="new_reservation_type == 'plane and hotel and car'"/>{
   <assign name ="next_destination" expr="'new-plane.vxml'"/>
   <assign name ="doNewHotelRes" expr="true"/>
   <assign name ="doNewCarRes" expr="true"/>}
<else/>
   <assign name ="next_destination" expr="'error.vxml'"/>
</if>

The <foreach> element

The <foreach> element has a single, required attribute, cond, which must be equal to a JavaScript expression that evaluates to true or false. The purpose of the <foreach> element is to iterate through the elements of an array.

Since JavaScript and VoiceXML variables are interchangeable, any variable type that is allowed in JavaScript (for example, an object or an array) is allowed in VoiceXML. A VoiceXML variable named xxxx can be given the value yyyy in one of three ways:

  • <var name="xxxx" expr="yyyy"/>

  • <assign name="xxxx" expr="yyyy"/>

  • <field name="xxxx" expr="yyyy"/> (or any other form item)

In each case, yyyy must be a valid JavaScript variable type. This can be any primitive data type, an object, or an array.

When a variable is an array, the <foreach> element can be used to iterate through the array like this:

<foreach item="value" array="values">
   <!—VoiceXML markup to do something with each item in the 
      array (that is, each variable in the array named values) -->
</foreach>

Here, values is the name of a JavaScript array and value is the name of the variable that stores each array item during each iteration of the loop.

Subdialogs

We introduced confirmation prompting in Lesson 6 for the new_reservation form in app-root.vxml. We accomplished the confirmation prompting in a simple way by adding a new confirm field to the new_reservation form. We can also accomplish the confirmation prompting by using the <subdialog> element to transfer to another form called a "subdialog." While using a subdialog is slightly more complicated, it offers a major benefit: reusable code.

As you might imagine, a confirmation prompt can be used at many different places in a single VoiceXML application. For example,

  • I understood your credit card number to be xxxx-xxxx-xxxx-xxxx. Is that correct?"

  • You want to fly from Saint Louis to Milwaukee. Is that correct?

  • You want to fly on April 23 and return May 6. Is that correct?

  • I understood your account number to be R05793.77 Is that correct?

This is a perfect situation for using a subdialog. The <subdialog> element is VoiceXML's version of the subroutine call in other programming languages. Here, it allows us to write a confirmation prompt dialog (the reusable subdialog) that we can use repeatedly throughout our application (and, with little or no modifications, in other, completely different applications). The VoiceXML subdialog mechanism allows us to:

  1. suspend execution and leave the form (dialog) at a specific location,

  2. enter and execute a new dialog (the subdialog) in a completely independent execution context, and then

  3. return to the exact location where we were in the original form and resume execution there.

Note

We distinguish between the subdialog (a form) and the <subdialog> element that calls it.

Invoking a subdialog

You invoke a subdialog at a specific point in the execution of a form by inserting the <subdialog> element at that point. The <subdialog> element can be used in different ways and has a large number of attributes (see https://msdn.microsoft.com/en-us/library/ff929007.aspx). We will use the <subdialog> element to transfer control to another form (the subdialog) in the same document (app-root.vxml). This is a simple use of a <subdialog> element and only requires two attributes

  • name – the name of the variable that will hold the value or values returned from the subdialog.

    Important

    The name variable is an object.

  • src – the URI of the subdialog, which can be in the same document or in a different document.

The <subdialog> element can have a number of different child elements. We will use two:

  • The <param> element, which specifies a value to pass to the subdialog.

  • The <filled> element, which contains code to be executed when the subdialog returns a value or values.

The subdialog

A subdialog is just like any other dialog, except that it includes a mechanism (the <return> element) to return control and data to the dialog that called it. For example, a simple subdialog might look like this, with the <return> element in bold font:

<form id="subDiag">
   <var name="input"/>  <!-- variable must have the same name as the name used in the <param> element -->
   <field name="value">
      <prompt>..........</prompt>
      <grammar>..........</grammar>
      <filled>
         <! --  some code here-->
         <return namelist="value"/>
      </filled>
   </field>
</form>

Using a confirmation prompt subdialog in app-root.vxml

As noted at the end of Lesson 6, we are going to replace the new_reservation form in the version of app-root.vxml at the end of that lesson with a new_reservation form that uses a subdialog. To do this, we are going to revert to the new_reservation form that we used in the version of app-root.vxml at the end of Lesson 4.

Then, we are going to:

  1. Add a new <form> element to app-root.vxml with name="confirmation". This form will be the subdialog.

  2. Add a <subdialog> element to the new_reservation form (the only legal parent for a <subdialog> element is the <form> element ) just after the new_reservation_type field. This <subdialog> element will transfer to the confirmation form (the subdialog).

  3. Remove the <filled> element in the new_reservation_type field and save its contents.

  4. Add a <param> element (see https://msdn.microsoft.com/en-us/library/ff929023.aspx) as a child of the <subdialog> element to transfer the value of the new_reservation_type form item variable to the subdialog.

    Important

    Variables transferred to the subdialog form using the <param> element must be declared as children of the subdialog <form> element, using the same name as used in the <param> element. Here, for example, we will have <param name="caller_response" expr="new_reservation_type"/> in the <subdialog> element, so we must include <var name="caller_response"/> as a child of the subdialog's <form> element.

  5. Ask for confirmation in the confirmation form, using Tellme's public grammar http://grammar.svc.tellme.com/yesno/mss/v2/confirm.grxml.

  6. Return the match result of the confirmation form, using the <return> element (see https://msdn.microsoft.com/en-us/library/ff929045.aspx).

  7. Use an <if> element in the <subdialog> element's <filled> element that clears the value of the new_reservation_type variable if the confirmation form matches "no." This causes the FIA to revisit the new_reservation_type field and ask for input again. The value of objAnswer is also cleared so that the <subdialog> element can be revisited by the FIA if necessary. If the confirmation form matches "yes," the <subdialog> element's <clear> statement is not executed and the application proceeds to the <else/> statement, which contains the code that was removed from the new_reservation_type field's <filled> element (the subdialog's <filled> element takes the place of the <filled> element that had previously been in the new_reservation_type field.)

Here is the new code

The <subdialog> element that will be placed just after the new_reservation_type field is:

<subdialog name="objAnswer" src="#confirmation">
   <param name="caller_response" expr="new_reservation_type"/>
   <filled>
      <if cond="objAnswer.confirmation == 'no'">
        <clear namelist="new_reservation_type objAnswer"/>
      <else/>
         <var name="next_destination" expr="' '"/>
            <if cond="new_reservation_type == 'plane'">
               <assign name ="next_destination" expr="'new-plane.vxml'"/>
            <elseif cond="new_reservation_type == 'hotel'"/>
               <assign name ="next_destination" expr="'new-hotel.vxml'"/>
            <elseif cond="new_reservation_type == 'car'"/>
               <assign name ="next_destination" expr="'new-car.vxml'"/>
            <elseif cond="new_reservation_type == 'plane and hotel'"/>{
               <assign name ="next_destination" expr="'new-plane.vxml'"/>
               <assign name ="doNewHotelRes" expr="true"/>
            }
            <elseif cond="new_reservation_type == 'plane and car'"/>{
               <assign name ="next_destination" expr="'new-plane.vxml'"/>
               <assign name ="doNewCarRes" expr="true"/>
            }
            <elseif cond="new_reservation_type == 'hotel and car'"/>{
               <assign name ="next_destination" expr="'new-hotel.vxml'"/>
               <assign name ="doNewCarRes" expr="true"/>
            }
            <elseif cond="new_reservation_type == 'plane and hotel and car'"/>{
               <assign name ="next_destination" expr="'new-plane.vxml'"/>
               <assign name ="doNewHotelRes" expr="true"/>
               <assign name ="doNewCarRes" expr="true"/>
            }
            <else/>
               <assign name ="next_destination" expr="'error.vxml'"/>
            </if>
            <goto expr="next_destination"/>
      </if>
   </filled>
 </subdialog>

The subdialog (the reusable code!) that will be added to app-root.vxml as a new form is:

<form id="confirmation">
   <var name="caller_response"/>
   <field name="confirmation">
      <prompt>
         I think I heard you say <value expr="caller_response"/>. 
         Is that correct?
      </prompt>
      <grammar
       src="http://grammar.svc.tellme.com/yesno/mss/v2/confirm.grxml"/>
         <catch event="noinput nomatch">
            Sorry. Didn't get that. Please try again.
            <reprompt/>
         </catch>

      <filled>
         <return namelist="confirmation"/>
      </filled>
   </field>
</form>

Here is how it works:

  1. The <subdialog> element calls the confirmation subdialog, by means of the src (=#confirmation) attribute, and sends it the value of a variable named caller_response that contains the value of the new_reservation_type variable (the grammar match found in the new_reservation_type field). The name of the caller_response variable was chosen so that the confirmation subdialog can be used in a variety of situations without having to be rewritten. The <subdialog> element's name attribute is the name of the variable (objAnswer) that will hold the value of the response returned by the subdialog. This response will be "yes" or "no".

    Important

    objAnswer is named in such a way as to emphasize that it is an object variable. When the subdialog returns a namelist of variables, such as <return namelist="var1 var2 var3"/>, they will be placed in properties of objAnswer, namely objAnswer.var1, objAnswer.var2, and objAnswer.var3. In our case, the subdialog returns confirmation and it is placed in the <subdialog> element's objAnswer.confirmation variable.

  2. The confirmation subdialog (form) prompts the caller, asking if the value of the caller_response variable is what the caller intended. The Tellme confirm.grxml grammar is used and the match to this grammar ("yes" or "no") is placed in the confirmation variable. The confirmation form (the subdialog) returns the confirmation variable to the <subdialog> element's objAnswer.confirmation variable and then exits.

  3. The <if> element in the <subdialog> element's <filled> element tests the value of the objAnswer.confirmation variable. If it is no, the new_reservation_type variable is cleared and the FIA revisits the new_reservation_type field, where the caller is asked once again what type of new reservation is desired. The object variable objAnswer is also cleared so that it can be refilled. If the value of objAnswer.confirmation is yes, the new_reservation_type variable is not cleared, and the FIA proceeds to execute the code that was previously in the <filled> element of the new_reservation_type field.

A new version of app-root.vxml

Taking the version of app-root.vxml that we had at the end of Lesson 4 as a starting point, we make four changes:

  1. Replace the switch statement in the main_selection field with the VoiceXML scripting code above (see Replacing the switch statement for main_selection).

  2. Replace the switch statement in the new_reservation_type field with the VoiceXML scripting code above (see Replacing the switch statement for new_reservation_type).

  3. Add the <subdialog> element to the new_reservation form.

  4. Add the confirmation form (subdialog).

Here is the result (new code in bold font):

<?xml version="1.0" encoding="UTF-8"?>
<vxml xmlns="http://www.w3.org/2001/vxml" version="2.1" xml:lang="en-US"
      revision="4"
      xml:base="https://studio.tellme.com/vxml-tutorial/">

   <script><![CDATA[

      var doNewPlaneRes = false;
      var doNewHotelRes = false;
      var doNewCarRes = false;
      var doChangePlaneRes = false;
      var doChangeHotelRes = false;
      var doChangeCarRes = false;
      var doRestaurantRec = false;
      var new_res_type = "placeholder";

   ]]></script>
   <form id="main">
      <field name="main_selection">
         <prompt bargein="true" bargeintype="speech">
            Welcome to Contoso Travel<break/>
            Say new reservation<break size="small"/> or press 1<break/>
            Say change reservation<break size="small"/> or press 2<break/>
            Say restaurant recommendation<break size="small"/> or press 3
         </prompt>

         <grammar version="1.0" root="top" tag-format="semantics/1.0">
            <rule id="top">
               <item><ruleref uri="#nonsense"/></item>
                  <one-of>
                     <item>new reservation
                     <tag>out="new reservation";</tag></item>

                     <item>change reservation
                     <tag>out="change reservation";</tag></item>

                     <item>restaurant recommendation
                     <tag>out="restaurant recommendation";</tag></item>
               </one-of>
               <item><ruleref uri="#nonsense"/></item>
            </rule>
            <rule id="nonsense">
               <one-of>
                  <item><ruleref special="GARBAGE"/></item>
                  <item><ruleref special="NULL"/></item>
               </one-of>
            </rule>
         </grammar>

         <grammar mode="dtmf" version="1.0" root="top">
            <rule id="top">
               <one-of>
                  <item>1</item>
                  <item>2</item>
                  <item>3</item>
               </one-of>
            </rule>
         </grammar>

         <catch event="noinput nomatch">
            Sorry. Didn't get that. Please try again.
            <reprompt/>
         </catch>

         <filled>
            <var name="next_destination" expr="' '"/>
            <if cond="main_selection == 'new reservation' || main_selection == '1'">
               <assign name="next_destination" expr="'#new_reservation'"/>
            <elseif cond="main_selection == 'change reservation' || main_selection == '2'"/>
               <assign name ="next_destination" expr="'change-reservation.vxml'"/>
            <elseif cond="main_selection == 'restaurant recommendation' || main_selection == '3'"/>
               <assign name ="next_destination" expr="'restaurant.vxml'"/>
            <else/>
               <assign name ="next_destination" expr="error.vxml"/>
            </if>
            <goto expr="next_destination"/>
         </filled>
      </field>
   </form>
   <form id ="new_reservation">
      <field name="new_reservation_type">
         <prompt bargein="true" bargeintype="speech">
            What type of reservation do you want to make<break/>Say
            plane<break size="small"/>, hotel
            <break size="small"/>, or car<break/>
            You may choose more than one.
         </prompt>
         <grammar version="1.0" root="top" tag-format="semantics/1.0">
            <rule id="top">
               <one-of>
            <!--single choice -->
                  <item><ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane";</tag></item>

                  <item><ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>
                  <tag>out="hotel";</tag></item>

                  <item><ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>
                  <tag>out="car";</tag></item>

            <!--double choice -->
                  <item><ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and hotel";</tag></item>

                  <item><ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and hotel";</tag></item>

                  <item><ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and car";</tag></item>

                  <item><ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and car";</tag></item>

                  <item><ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>
                  <tag>out="hotel and car";</tag></item>

                  <item><ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>
                  <tag>out="hotel and car";</tag></item>

            <!--triple choice -->
                  <item><ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and hotel and car";</tag></item>

                  <item><ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and hotel and car";</tag></item>

                  <item><ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and hotel and car";</tag></item>

                  <item><ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and hotel and car";</tag></item>

                  <item><ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and hotel and car";</tag></item>

                  <item><ruleref uri="#nonsense"/>car
                  <ruleref uri="#nonsense"/>hotel
                  <ruleref uri="#nonsense"/>plane
                  <ruleref uri="#nonsense"/>
                  <tag>out="plane and hotel and car";</tag></item>
               </one-of>
            </rule>
            <rule id="nonsense">
               <one-of>
                  <item><ruleref special="GARBAGE"/></item>
                  <item><ruleref special="NULL"/></item>
               </one-of>
            </rule>
         </grammar>

         <catch event="noinput nomatch">
            Sorry. Didn't get that. Please try again.
            <reprompt/>
         </catch>

      </field>

      <subdialog name="objAnswer" src="#confirmation">
         <param name="caller_response" expr="new_reservation_type"/>
         <filled>
            <if cond="objAnswer.confirmation == 'no'">
              <clear namelist="new_reservation_type objAnswer"/>
              
            <else/>
               <var name="next_destination" expr="' '"/>
               <if cond="new_reservation_type == 'plane'">
                  <assign name ="next_destination" expr="'new-plane.vxml'"/>
               <elseif cond="new_reservation_type == 'hotel'"/>
                  <assign name ="next_destination" expr="'new-hotel.vxml'"/>
               <elseif cond="new_reservation_type == 'car'"/>
                  <assign name ="next_destination" expr="'new-car.vxml'"/>
               <elseif cond="new_reservation_type == 'plane and hotel'"/>{
                  <assign name ="next_destination" expr="'new-plane.vxml'"/>
                  <assign name ="doNewHotelRes" expr="true"/>
               }
               <elseif cond="new_reservation_type == 'plane and car'"/>{
                  <assign name ="next_destination" expr="'new-plane.vxml'"/>
                  <assign name ="doNewCarRes" expr="true"/>
               }
               <elseif cond="new_reservation_type == 'hotel and car'"/>{
                  <assign name ="next_destination" expr="'new-hotel.vxml'"/>
                  <assign name ="doNewCarRes" expr="true"/>
               }
               <elseif cond="new_reservation_type == 'plane and hotel and car'"/>{
                  <assign name ="next_destination" expr="'new-plane.vxml'"/>
                  <assign name ="doNewHotelRes" expr="true"/>
                  <assign name ="doNewCarRes" expr="true"/>
               }
               <else/>
                  <assign name ="next_destination" expr="'error.vxml'"/>
               </if>

               <goto expr="next_destination"/>
            </if>
         </filled>
      </subdialog>
   </form>
   
   <form id="confirmation">
      <var name="caller_response"/>
      <field name="confirmation">
         <prompt>
            I think I heard you say <value expr="caller_response"/>.
            Is that correct?
         </prompt>
         <grammar src= "http://grammar.svc.tellme.com/yesno/mss/v2/confirm.grxml"/>

         <catch event="noinput nomatch">
            Sorry. Didn't get that. Please try again.
            <reprompt/>
         </catch>

         <filled>
            <return namelist="confirmation"/>
         </filled>
      </field>
   </form>

</vxml>

You should paste this code into the Tellme Studio Scratchpad and run it.

What's next?

This lesson has introduced two new concepts: VoiceXML's own scripting elements and subdialogs.

You may find that VoiceXML scripting elements are more convenient than JavaScript in some situations.

Subdialogs are important because they make it possible to create reusable dialogs, analogous to the subroutines, methods, functions, etc. of other programming languages. By way of example, we created a confirmation prompting subdialog that could be used in many different places throughout a complex VoiceXML application.

In the next lesson, Lesson 8, we will cover events and links. The versions of app-root.vxml that we have developed so far have included this event-handling code:

<catch event="noinput nomatch">
            Sorry. Didn't get that. Please try again.
            <reprompt/>
         </catch>

This code has been included without any explanation—other than that it will keep the application from hanging up if the speech recognition engine doesn't hear any input that matches the grammar.

Lesson 8 will explain what this <catch> element is and how it works, along with several related subjects.