VoiceXML

 

Sub Dialog Page 6 of 6

A <subdialog> element invokes a “called” dialog (known as the subdialog) identified by its src attribute. The subdialog executes in a new execution context. The subdialog proceeds until the execution of a <return> element which causes the subdialog to return. When the subdialog returns, its execution context is deleted, and execution resumes in the calling dialog with any appropriate <filled> elements. An execution context includes all declarations and state information for the dialog, the dialog’s document, and the application root (if present). Subdialogs can permit the reuse of a common dialog such as this example of prompting a user for credit card information, or build libraries of reusable applications.

The attributes are:

name The result returned from the subdialog, an ECMAScript object whose properties are the ones defined in the namelistattribute of the <return> element.
expr The initial value of the form item variable; default is ECMAScript undefined. If initialized to a value, then the form item will not be visited unless the form item variable is cleared.
cond A boolean condition that must also evaluate to true in order for the form item to be visited.
modal Controls which grammars are active during the subdialog. If true (the default) all grammars active in the calling dialog are disabled. If false, they remain active.
namelist Same as namelist in <submit>, except that the default is to submit nothing. Only valid when fetching another document.
src The URI of the <subdialog>.

 

The <subdialog> element may contain elements common to all form items, and may also contain <param> elements. The <param> elements of a <subdialog> specify the parameters to pass to the subdialog. These parameters must be declared in the subdialog using <var> elements; it is a semantic error to attempt to set a form item variable or an undeclared variable using <param>. When a subdialog initializes, its variables are initialized in document order to the corresponding <param> value, if they don't have an expr attribute. Thus <param> elements can only initialize <var> elements without expr attributes.

In the example below, the birthday of an individual is used to validate their driver's license. The src attribute of the subdialog refers to a form that is within the same document. The <param> element is used to pass the birthday value to the subdialog.

<!-- form dialog that calls a subdialog --> 
<form> 
  <subdialog name="result" src="#getdriverslicense"> 
   <param name="birthday" expr="'2000-02-10'"/> 
   <filled> 
     <submit next="http://myservice.example/cgi-bin/process"/> 
   </filled> 
  </subdialog> 
</form> 

<!-- subdialog to get drivers license --> 
<form id="getdriverslicense"> 
  <var name="birthday"/> 
  <field name="drivelicense"> 
   <grammar src="http://grammarlib/drivegrammar.gram"
      type="application/x-jsgf"/> 
   <prompt> Please say your driver's license. </prompt> 
   <filled> 
     <if cond="validdrivelicense(drivelicense,birthday)"> 
       <var name="status" expr="true"/> 
     <else/> 
       <var name="status" expr="false"/> 
     </if> 
     <return namelist="drivelicense status"/> 
   </filled> 
  </field> 
</form> 

The driver’s license value is returned to calling dialog, along with a status variable in order to indicate whether the license is valid or not.

This example also illustrates the convenience of using <param> as a means for forwarding data to the subdialog as a means of instantiating values in the subdialog without using server side scripting. An alternate solution that uses scripting, is shown below.

Document with form that calls a subdialog

<?xml version="1.0"?> 
<vxml version="1.0"> 

  <form> 
   <field name="birthday" type="date"> 
     What is your birthday? 
   </field> 
   <subdialog name="result" 
          src="/cgi-bin/getlib#getdriverslicense" 
          namelist="birthday"> 
     <filled> 
       <submit next="http://myservice.example/cgi-bin/process"/> 
     </filled> 
   </subdialog> 
  </form> 
</vxml> 

Document containing the subdialog (generated by /cgi-bin/getlib)

<?xml version="1.0"?> 
<vxml version="1.0"> 

  <form id="getdriverlicense"> 
    <var name="birthday" expr="'1980-02-10'"/> 
    <!-- Generated by server script -->    
   <field name="drivelicense"> 
     <grammar src="http://grammarlib/drivegrammar.gram"
        type="application/x-jsgf"/> 
     <prompt>
       Please say your driver’s license number.
     </prompt> 
     <filled> 
       <if cond="validdrivelicense(drivelicense,birthday)"> 
         <var name="status" expr="true"/> 
       <else/> 
         <var name="status" expr="false"/> 
       </if> 
       <return namelist="drivelicense status"/> 
     </filled> 
   </field> 
  </form> 
</vxml> 

In the above example, a server side script had to generate the document and embed the birthday value.

When a subdialog is interpreted, the only active grammars are those in dialog-scope of the subdialog and the default grammars defined by the interpreter context (e.g. help, cancel). The set of active grammars remains limited for all subsequent dialogs until a <return> is executed. For example, if subdialog A transitions to dialog B, then the interpretation of B considers only active grammars in its dialog scope and the default grammars.

One last example is shown below that illustrates a subdialog to capture general credit card information. First the subdialog is defined in a separate document; it is intended to be reusable across different applications. It returns a status, the credit card number, and the expiry date; if a result cannot be obtained, the status is returned with value "no_result".

<?xml version="1.0"?> 
<vxml version="1.0"> 
   <!-- Example of subdialog to collect credit card information. --> 
   <!-- file is at http://www.somedomain.example/ccn.vxml --> 
   <form id="getcredit"> 
     <var name="status" expr="'no_result'"/> 
     <var name="username"/>
 
     <field name="creditcardnum"> 
       <prompt>
         What is your credit card number?
       </prompt> 
       <help> 
         I am trying to collect your credit card information. 
         <reprompt/> 
       </help> 
       <nomatch>
         <return namelist="status"/>
       </nomatch> 
       <grammar .../> 
     </field> 

     <field name="expirydate" type="date"> 
       <prompt> 
         What is the expiry date of this card? 
       </prompt> 
       <help> 
         I am trying to collect the expiry date of the credit 
         card number you provided. 
         <reprompt/> 
       </help> 
       <nomatch> 
         <return namelist="status"/> 
       </nomatch> 
     </field>

     <block> 
       <assign name="status" expr="'result'"/> 
       <return namelist="status creditcardnum expirydate"/> 
     </block> 
   </form> 
</vxml> 

An application that includes a calling dialog is shown below. It obtains the name of a software product and operating system using a mixed initiative dialog, and then solicits credit card information using the subdialog.

<?xml version="1.0"?> 
<vxml version="1.0"> 
  <!-- Example main program --> 
  <!-- http://www.somedomain.example/main.vxml --> 
  <!-- calls subdialog ccn.vxml --> 

  <!-- assume this gets defined by some dialog --> 
  <var name="username"/>

  <form id="buysoftware"> 
    <var name="ccn"/> 
    <var name="exp"/> 
    <grammar ..../> 
    <initial name="start"> 
      <prompt> 
        Please tell us the software product you wish to buy
        and the operating system on which it must run. 
      </prompt> 
      <noinput> 
        <assign name="start" expr="true"/> 
      </noinput> 
    </initial> 

    <field name="product"> 
      <prompt>
        Which software product would you like to buy?
      </prompt> 
    </field> 

    <field mname="operatingsystem"> 
      <prompt>
        Which operating system does this software need to run on? 
      </prompt> 
    </field> 

    <subdialog name="cc_results"
        src="http://somedomain.example/ccn.vxml"> 
      <filled> 
        <if cond="cc_results.status=='no_result'"> 
          Sorry, your credit card information could not be 
          Obtained. This order is cancelled. 
          <exit/> 
        <else/> 
          <assign name="ccn" expr="cc_results.creditcardnum"/> 
          <asssign name="exp" expr="cc_results.expirydate"/> 
        </if> 
      </filled> 
    </subdialog> 

    <block> 
      We will now process your order. Please hold. 
      <submit namelist="username product operatingsystem ccn exp"/> 
    </block> 
  </form>
</vxml> 
            
Remarks
The subdialog element allows you to call a self-contained VoiceXML dialog. In addition to passing parameters to the called dialog via param elements, the called dialog can return values to the caller via the return element. Whether or not you return data from a subdialog, you should always include the return element in the dialog called by the subdialog element to properly return to the execution context of the caller.
Just before the subdialog is executed the VoiceXML interpreter suspends the execution context of the caller including all event handlers, grammars, links, scripts, and variables in any scope (dialog, document, application). The VoiceXML interpreter creates a new execution context for the subdialog while it executes. This context is destroyed when the subdialog returns. To share data between the caller and the subdialog, use the param and return elements.
The namelist, method, and enctype attributes are only relevant if the subdialog element navigates to a server-side script (e.g. CGI).
You typically place a subdialog in a separate VoiceXML document that does not reference the application root document of the application containing the calling dialog. If you were to reference the application root from the document containing the subdialog, all variables in the application root are reinitialized each time the subdialog is called.
The src and srcexpr attributes are mutually exclusive.
Examples

The following example jumps to a local subdialog, fruit_picker, that asks the user to pick a piece of fruit. Once the user selects a fruit, the value is returned to the calling dialog via the namelist attribute. The calling dialog accesses the value as a property of the object named by the name attribute of the subdialog element. To see that the subdialog and its caller do not share execution contexts, run the example, check the debug log, and observe that the calling_dialog variable is reinitialized to the value "none" within the context of the subdialog even though it is set to "main" in the calling dialog before the subdialog is executed.

<?xml version="1.0"?>
<vxml version="2.0">

   <var name="calling_dialog" expr="'none'" />
   <var name="user" expr="'unknown'" />

   <form id="main">
   <block>
      <assign name="calling_dialog" expr="'main'"/>
      <assign name="user" expr="'noah'"/>
   </block>
   <subdialog src="#fruit_picker" name="oResult">
      <param name="customer" expr="document.user"/>
      <catch event="event.failed">
         <audio>fruit picker failed</audio>
      </catch>
      <filled>
        <audio>fruit picker returned <value expr="oResult.fruit"/></audio>
        <log>back in <value expr="calling_dialog"/></log>
        <exit />
      </filled>
   </subdialog>
   </form>

   <form id="fruit_picker">
      <var name="customer"/>

      <var name="aFruits" expr="new Array('apples', 'oranges', 'bananas', 'pears')"/>

      <block>
         <!-- 
         calling_dialog will evaluate to 'none' because the subdialog 
         doesn't share the execution context of the calling dialog
         -->
         <log>calling dialog is <value expr="calling_dialog"/></log>
      </block>

      <field name="fruit">
         
         <prompt>
         <audio>What kind of fruit would you like, <value expr="customer"/></audio>
         </prompt>
   
         <grammar type="application/x-gsl" mode="voice">
         <![CDATA[
         [
            [apple apples] {<fruit "apple">}
            [orange oranges] {<fruit "orange">}
            [banana bananas] {<fruit "banana">}
            [pear pears] {<fruit "pear">}
         ]
         ]]>
         </grammar>
   
         <catch event="noinput nomatch">
            <audio>Sorry <value expr="customer"/>.</audio>
            <audio>I don't think we have any of those available.</audio>
            <audio>Our limited selection includes the following:</audio>
            <foreach item="f" array="aFruits">
               <audio><value expr="f"/></audio>
            </foreach>
            <audio>Please pick one.</audio>
         </catch>
   
         <catch event="noinput">
            <audio>Sorry <value expr="customer"/>. I didn't hear you.</audio>
            <reprompt/>
         </catch>
   
         <catch event="noinput nomatch" count="2">
            <audio>Bailing.</audio>
            <return event="event.failed" />
         </catch>
   
         <filled>
            <log>Recognized <value expr="fruit"/></log>
            <return namelist="fruit"/>
         </filled>

      </field>
   </form>

</vxml>