铁观音

C++编程宝典

   ::  ::  ::  ::  :: 管理 ::
  1 随笔 :: 19 文章 :: 0 评论 :: 0 Trackbacks
VoiceXML2.0规范
 
第一章  概述

 

 
    这篇文档详细描述了VoiceXML,即语音扩展标记语言。第一章介绍它的背景、基本概念和用途;第二章介绍form的对话框结构(dialog constructs)、menu、link和它们的解释机制FIA(Form Interpretation Algorithm);第三章介绍用户的DTMF(Dual Tone Multi-Frequency)和语音输入用到的语法;第四章介绍系统输出用到的语音合成和预先录制的音频;第五章介绍对话框(Dialog)流程的控制,包括变量、事件和可执行元素;第六章介绍各种环境特性,例如参数(Parameter)、属性(Property)和资源处理;附录提供了包括VoiceXML计划、FIA(Form Interpretation Algorithm)、音频文件格式等附加信息。
    VoiceXML最早出现于1995年,作为一种基于XML对话的设计语言,它的出现是为了简化AT&T一个名为PML(Phone Markup Language)项目中语音识别程序的开发过程。经过AT&T的重新组织,AT&T,Lucent and Motorola的开发团队继续致力于开发他们的类PML语言。
    1998年,W3C主办了一次关于语音浏览器的会议。此时,AT&T and Lucent对于最开始的PML都有各自不同的发展,Motorola开发了VoXML,IBM正在开发它自己的SpeechML。此次会议的其他与会者也正在开发类似的语言,例如HP的TalkML和PipeBeach的VoiceHTML。
    于是AT&T、IBM、Lucent和Motorola共同组织了VoiceXML论坛,它的任务是定义一种标准的对话设计语言,使开发者可以用它来创建会话式的应用程序。他们选择XML作为他们工作的基础,因为他们很清楚,XML是技术发展的趋势。
    在2000年,VoiceXML论坛发布了VoiceXML 1.0。此后不久,VoiceXML 1.0被提交给W3C(World Wide Web Consortium)作为一种新的国际标准。VoiceXML 2.0就是W3C的成员单位、其他的W3C工作组和公众的共同努力的结果。
    熟悉VoiceXML1.0的开发者可直接到附录,那里总结了VoiceXML2.0和VoiceXML1.0的差别。
 
第一节 介绍  
 
    VoiceXML是用来创建音频对话的,主要包括语音合成、数字化音频、语音识别、DTMF按键输入识别、录音、通话、混合主动式会话。它的主要作用是把基于网络的开发和信息这两者的优势引入语音应答系统。
    这里有两个简短的例子,第一个例子是“Hello World”:
      <?xml version="1.0" encoding="UTF-8"?>
      <vxml xmlns="http://www.w3.org/2001/vxml"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.w3.org/2001/vxml
               http://www.w3.org/TR/voicexml20/vxml.xsd"
                version="2.0">
        <form>
          <block>Hello World!</block>
        </form>
      </vxml>
    最上层的元素是<vxml>,它主要是作为dialog的容器。在VoiceXML里有两种dialog:form和menu 。form用来输出提示信息和收集输入信息,menu提供一些choice,以决定下一步要做什么。这个例子里有一个form,它包含了一个block,这个block把“Hello World!”合成语音,并输出给用户。由于这个form没有指定下一个dialog,因此,这次会话结束。
    第二个例子要求用户选择一种饮料,然后把它提交给服务器端的一个脚本。
      <?xml version="1.0" encoding="UTF-8"?>
      <vxml xmlns="http://www.w3.org/2001/vxml"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.w3.org/2001/vxml
               http://www.w3.org/TR/voicexml20/vxml.xsd"
                version="2.0">
        <form>
         <field name="drink">
           <prompt>Would you like coffee, tea, milk, or nothing?</prompt>
           <grammar src="drink.grxml" type="application/srgs+xml"/>
         <block>
           <submit next="http://www.drink.example.com/drink2.asp"/>
         </block>
         </field>
        </form>
      </vxml>
    field是一个输入域,用户必须给field提供一个值,否则就不可能进行到form中的下一个元素。下面是这个例子的一个简单的人机交互:
      C (computer): Would you like coffee, tea, milk, or nothing?
      H (human): Orange juice.
      C: I did not understand what you said. (a platform-specific default message.) 
      C: Would you like coffee, tea, milk, or nothing?
      H: Tea
      C: (continues in document drink2.asp) 

第二节 背景  
 
    这一节包含了一个高级的结构模型,它的一些术语将用来说明VoiceXML的目标,范围、设计法则对支持VoiceXML的系统的要求。
一、结构模型
    这篇文档采用的结构模型由以下几部分组成:
图1: 结构模型
    文档服务器(例如web服务器)通过VoiceXML解释器环境(context)处理来自客户端应用程序,即VoiceXML解释器的请求。服务器端则产生一些文档由VoiceXML解释器处理。VoiceXML解释器环境和VoiceXML解释器会同时监听用户的输入。例如,VoiceXML解释器可能会一直监听一段特别的提示输出,以便更好的引导用户,同时另一个则监听用户参数选择的改变,如音量或者语音合成的特性。
    执行平台由VoiceXML解释器环境和VoiceXML解释器控制。例如,在交互式语音应答系统中,VoiceXML解释器环境负责检测电话呼入,若有则把电话接起来并把这次呼叫引导到程序的第一个文档;而VoiceXML解释器在电话接起来后负责控制对话框。执行平台则产生一些事件来响应用户相应的操作(如接收到的语音或字符输入,或者挂机)和相应的系统事件(如定时器到期)。其中,有一些事件是由VoiceXML解释器执行,像VoiceXML文档中指定的一些事件;另外一些则由VoiceXML解释器环境执行。
 
二、VoiceXML的目标
    VoiceXML的主要目标有三个:1、最大限度地将web开发和web内容传输的能力带入到语音应答系统中;2、将该领域的程序员从底层编码解脱出来;3、资源管理。它使得语音服务和数据服务可以通过我们熟悉的客户服务器模式结合起来。通过和执行平台之间一系列的交互对话,用户就可以浏览语音服务了。这些对话由文档服务器提供,文档服务器和执行平台可能不在同一台机器上。文档服务器负责提供全部的服务逻辑、执行数据库、执行传下来的系统操作、产生对话框。VoiceXML文档会指定每一个交互式对话,以便于VoiceXML解释器控制。用户的输入会影响到对话框的解释,并且这些输入也会被提交给文档服务器。文档服务器提供另一个VoiceXML文档以继续用户和其他dialog之间的会话。
    VoiceXML是一种标记语言,它有以下优点:
      1、通过在每个文档中指定多个交互式对话,最大限度地减少客户机和服务器之间的交互;
      2、使得程序员不用理会底层的和平台特有的细节;
      3、使得用户交互的代码(在VoiceXML中)和业务逻辑(例如CGI脚本)分离;
      4、提高业务在不同平台的可移植性。VoiceXML对内容提供商、工具提供商和平台提供商来说是一种通用的语言;
      5、它可以很容易地应用到简单的交互中,也可以通过提供一些语言特性来支持复杂的对话。
    虽然VoiceXML力争满足大多数语音应答服务的需求,但对于一些有特殊要求的服务,最好还是由专门的应用程序来完成,因为他们有更出色的控制水平。
 
三、VoiceXML的范围
    VoiceXML描述的是由语音应答系统提供的人机交互,它包括以下几个方面:
      1、语音合成(text-to-speech);
      2、声音文件的输出;
      3、语音输入的识别;
      4、DTMF输入的识别;
      5、对话流的控制;
      6、电话的一些特性,如呼叫转移和挂机。
    VoiceXML提供了多种方式来收集字符和(或)语音输入,给文档定义的相应的变量赋值,也提供了多种方式来决定文档的解释顺序。一个文档可以通过URI(Universal Resource Identifier)链接到其他的文档。
 
四、设计法则
    VoiceXML程序也是一种XML程序。
      1、VoiceXML通过抽象化平台资源以提高服务的可移植性;
      2、VoiceXML在支持的声音文件格式、语音语法格式和URI方案上可以适应平台的多样性。虽然提供商的平台可能支持多种语法格式,但是VoiceXML要求平台必须支持一种通用的格式,即W3C的SRGS(Speech Recognition Grammar Specification)的XML格式,以提高协同工作的能力。同样的,对回放和录音的声音文件,虽然平台可能支持多种格式,但是附录E上所提到的几种声音格式是必须要支持的;
      3、对于普通类型的交互的编写,VoiceXML完全可以支持;
      4、VoiceXML有定义明确的语义,它保存了作者希望的人机交互行为。客户端是启发式的,它不需要理会文档元素的解释;
      5、VoiceXML通过语法来识别语义解释,使得程序可以运作;
      6、VoiceXML有一套流程控制机制;
      7、VoiceXML通过交互行为使各自分离的服务逻辑能够运作;
      8、VoiceXML并不是用来进行精确计算、数据库操作或传统的系统操作的,这些操作由文档解释器以外的外部资源处理(例如文档服务器);
      9、一般的服务逻辑、状态管理、对话框的产生和对话框的先后顺序都不属于文档解释器处理;
      10、通过URI,VoiceXML提供了多种方式链接到其他的文档,也有多种方式提交数据到服务器脚本;
      11、VoiceXML提供了多种方式正确地识别哪一些数据要提交到服务器,在某一次提交会用到哪个HTTP方法(GET or POST);
      12、VoiceXML不要求文档作者明确的分配和释放对话资源,或处理并发执行。资源分配和控制线程的并发执行由执行平台处理。
 
五、对执行平台的要求
    这一小节简要地描述对支持VoiceXML解释器的硬件/软件平台的要求。
    文档获得。解释器环境要能够获得文档给VoiceXML解释器解释,因此,必须支持“HTTP”URI协议。在某些情况下,文档的请求(request)是在VoiceXML文档解释的时候产生的,而其他的请求是解释器环境为了响应VoiceXML范围之外的事件产生的,例如电话呼入。当通过HTTP发送文档请求时,解释器环境用“User-Agent”头变量来标识自己,它的形式为“<name>/<version>”,例如,“acme-browser/1.2”。
    音频输出。执行平台必须支持声音文件和文本语音转换(TTS)的音频输出,并且能够自由地序列化它们。如果某个音频输出资源不可用,要抛出事件error.noresource。声音文件是通过URI引用的。VoiceXML指定了一系列必须支持的声音文件格式(详见附录E),除了这些必须支持的格式以外,执行平台也可以支持其他格式的声音文件。
    音频输入。执行平台要能够检测,同时报告字符和(或)语音输入;控制检测输入的间隔时间,间隔时间的长短由VoiceXML文档指定。如果音频输入资源不可用,要抛出事件error.noresource。
      1、执行平台必须能够报告用户输入的字符(如DTMF)。它必须支持W3C的SRGS所描述的XML格式的DTMF语法。也应该支持SRGS所描述的ABNF(Augmented Backus-Naur Form)格式的DTMF语法;
      2、执行平台必须能够动态地接收语音识别语法数据。它必须能用 W3C SRGS的XML格式的语音语法数据。也应该能够接收W3C SRGS的ABNF格式的语音识别语法数据,它也可以支持其他格式的语法,如JSGF(JSpeech Grammar Format),或者一些专有的格式。有些VoiceXML元素包含了语法数据,其他的则通过URI来指向语法数据。语音识别器必须能够跟着语音输入的动态更新而更新,通过语音语法数据指定的方法来监听语音输入;
      3、执行平台必须要能够把用户的音频输入录下来,且录音对相应请求的变量是可用的。VoiceXML指定了一系列必须支持的录音文件的格式(详见附录E),也可以支持其他的格式。
    转接。平台应该能够支持通过通信网络(如电话)连接第三方。

第三节 概念  
 
    一个VoiceXML文档(或一系列相关的文档叫做一个应用(application))构成了一个有限的会话状态。用户一次只能在一个会话状态或dialog中。每个dialog都会确定要跳转的下一个dialog。跳转通过URI指定,URI规定了下一个要用到的文档和dialog。如果URI没有指向一个文档,则认为它指向当前文档。如果URI没有指向一个dialog,则认为它指向那个文档的第一个dialog。如果一个dialog没有指定它的下一个dialog,或者它有一个明确地退出会话的元素,则执行中断。
一、Dialogs and Subdialogs
    VoiceXML有两种dialog:form和menu。Form 定义了一个收集用户输入,并给相应的field变量赋值的交互。每个field可以指定一个语法,这个语法规定了field允许的输入。如果有form级的语法存在,一个utterance可以填充几个field。Menu给用户提供了一些可选的选项,并根据用户的选择跳转到另外一个dialog。
    Subdialog就像函数调用一样,它提供了一种机制来调用一个新的交互,并返回到调用它的form。变量实例、语法和状态信息都被保存起来,在返回到调用的文档后仍然可用。例如,subdialog可以用在创建一个由数据库查询得到的确定序列;或者创建在单个应用的文档中共享的组件;或者在多个应用中可重用的dialog库。
 
二、会话
    会话始于用户开始和VoiceXML解释器环境交互的时候,随着用户或文档或解释器环境请求结束而结束,包括了加载和执行文档的过程。
 
三、应用
    应用(application)是由共享同一应用根文档(application root document)的一系列文档组成的。无论如何,只要用户在跟应用里的文档交互,它的根文档都会被加载。当用户在同一应用的其他文档中跳转时,应用根文档一直都被加载,直到用户跳转到一个不在这个应用里的文档。当应用根文档被加载的时候,它的变量就像这个应用的变量一样,对这个应用里所有的文档都是可用的,它的语法在这个应用的生命期内都是激活的。关于语法激活的规则在第3.1.4节讨论。
    图2展示了在一个应用中,共享同一个应用根文档(root)的几个文档(D)之间的跳转。
图2: 在一个应用中的几个文档之间的跳转
 
四、语法
    每个dialog都有一个或多个语音和(或)DTMF语法。在机器主导的应用中,每个dialog的语法只有当用户在那个dialog中的时候才激活。而在混合主动式(mixed initiative)的应用中,相关的几个dialog的语法同时都是激活的(也就是正在监听),即使用户在同一个文档的另外一个dialog,或者在同一个应用的另一个加载的文档。混合主动式是指,用户和机器交替地决定下一步要做的。在这种情况下,如果用户说的话匹配了另一个dialog中激活的语法,执行平台会跳转到那个dialog,用户刚才所说的话就像是它在那个dialog中说的一样。混合主动式增强了语音应用程序的灵活性和性能。
 
五、事件
    VoiceXML提供了填充form的机制来处理“正常”的用户输入。另外,VoiceXML定义了一种机制来处理那些form机制没有包含进去的事件。
    平台能在多种环境下抛出事件,例如当用户没有响应的时候,或者没有清楚地响应的时候,或者要求帮助的时候等。如果发现VoiceXML文档有语义错误的时候,也会抛出事件。事件由catch元素或他们的简写元素捕捉。可能出现事件的元素都可以指定catch元素。catch也可以在封装的元素里像拷贝一样地继承。这样,可在某一级别指定对相同事件的处理,这些处理对更低级别的元素同样有效。
 
六、链接
    link支持混合主动式。它可以指定一个语法,无论何时,只要用户在这个link的作用域内,这个语法都是激活的。如果用户的输入匹配了这个link的语法,控制就跳转到该link指定的URI。

第四节 VoiceXML元素  
 
元素 作用 章节
<assign> 给变量赋值。 5.3.2
<audio> 在prompt中播放一段音频。 4.1.3
<block> 没有人机交互的可执行代码的容器。 2.3.2
<catch> 捕获事件。 5.2.2
<choice> 定义一个menu item。 2.2.2
<clear> 清除一个或多个form item变量。 5.3.3
<disconnect> 断开一个会话。 5.3.11
<else> 用于<if>元素中的else。 5.3.4
<elseif> 用于<if>元素中的elseif。 5.3.4
<enumerate> 列举menu中的choice的信息。 2.2.4
<error> 捕获<error>事件。 5.2.3
<exit> 退出会话。 5.3.9
<field> 在form中声明一个输入域。 2.3.1
<filled> 在输入域被填充后执行一些操作。 2.4
<form> 用于给出信息和收集数据的dialog。 2.1
<goto> 在同一或不同文档中跳转。 5.3.7
<grammar> 指定语音识别或DTMF语法。 3.1
<help> 捕获<help>事件。 5.2.3
<if> 简单的条件逻辑。 5.3.4
<initial> 在进入一个混合主动式的form时声明初始的逻辑。 2.3.3
<link> 对所有在link的作用域内的会话指定一个跳转。 2.5
<log> 生成调试信息。 5.3.13
<menu> 提供可供选择的跳转。 2.2.1
<meta> 以name/value对的形式定义一个元数据项。 6.2.1
<metadata> 使用元数据方案定义元数据信息。 6.2.2
<noinput> 捕获<noinput>事件。 5.2.3
<nomatch> 捕获<nomatch>事件。 5.2.3
<object> 跟自定义的扩展功能进行交互。 2.3.5
<option> 在<field>中指定一个可选项。 2.3.1.3
<param> <object>或<subdialog>的参数。 6.4
<prompt> 产生一个输出给用户的语音合成和音频的队列。 4.1
<property> 控制平台的设置。 6.3
<record> 录音。 2.3.6
<reprompt> 在某个事件被捕获后重新访问field时,再次播放这个field的prompt。 5.3.6
<return> 从subdialog返回。 5.3.10
<script> 指定一段客户端的ECMAScript脚本逻辑。 5.3.12
<subdialog> 在当前的dialog中调用另外一个dialog作为subdialog。 2.3.4
<submit> 提交一些值到文档服务器。 5.3.8
<throw> 抛出事件。 5.2.1
<transfer> 呼叫转移。 2.3.7
<value> 在prompt中插入一个表达式的值。 4.1.4
<var> 声明一个变量。 5.3.1
<vxml> 在每个VoiceXML文档中最上层的元素。 1.5.1
表1:VoiceXML元素
 
第五节 文档的结构和执行  
 
    VoiceXML文档主要由一些叫做dialog的上层元素组成。VoiceXML有两种对话:form和menu。文档里还可以有<meta>、<metadata>、<var>、<script>、<property>、<catch>和<link>元素。
一、在一个文档中执行
    文档的执行由默认的第一个对话开始。每个对话在执行的时候,都会指定下一个对话,否则执行中止。
    下面举个“Hello World”的例子来说明它。这个例子里由有一个文档级的变量――hi,它的值为字符串“Hello World!”,是第一个form的提示信息。一旦第一个form播放了“Hello World”,控制会跳转到下一个叫做“say_goodbye”的form,然后播放“Goodbye!”由于第二个form没有跳转到其他的对话,文档退出,执行结束。
      <?xml version="1.0" encoding="UTF-8"?>
      <vxml xmlns="http://www.w3.org/2001/vxml"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.w3.org/2001/vxml
               http://www.w3.org/TR/voicexml20/vxml.xsd"
                version="2.0">
        <meta name="author" content="John Doe"/>
        <meta name="maintainer" content="hello-support@hi.example.com"/>
        <var name="hi" expr="'Hello World!'"/>
        <form>
         <block>
            <value expr="hi"/>
            <goto next="#say_goodbye"/>
         </block>
        </form>
        <form id="say_goodbye">
         <block>
            Goodbye!
         </block>
        </form>
      </vxml>
    上面的两个form也可以合起来:
      <?xml version="1.0" encoding="UTF-8"?>
      <vxml xmlns="http://www.w3.org/2001/vxml"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.w3.org/2001/vxml
               http://www.w3.org/TR/voicexml20/vxml.xsd"
                version="2.0">
        <meta name="author" content="John Doe"/>
        <meta name="maintainer" content="hello-support@hi.example.com"/>
        <var name="hi" expr="'Hello World!'"/>
        <form>
         <block>
            <value expr="hi"/> Goodbye!
         </block>
        </form>
      </vxml>
    元素<vxml>有如下属性:
version 表示该文档的VoiceXML的版本号(必须的),当前的版本号是2.0。
xmlns 表示给VoiceXML指定的域名空间(必须的)VoiceXML的域名空间是http://www.w3.org/2001/vxml。
xml:base 该文档的基础URI,文档中所有的相对的URI引用都是相对于这个基础URI的。
xml:lang 表示该文档的语言标识符,如果省略,默认的语言为平台特定的语言。
application 表示该文档的应用根文档的URI。
表2:<vxml>元素的属性
    在文档级,语言信息可以通过继承得到:那些有“xml:lang”属性的元素可以继承“xml:lang”的值,例如<grammar>和<prompt>元素,除非这些元素也指定了一个值。
 
二、多文档应用的执行
    通常,每个文档都是作为一个孤立的应用运行的。在某些情况下,你想要多个文档作为一个应用一起运行,你可以选择一个文档作为应用根文档(application root document),其他的作为应用叶文档(application leaf document),每个叶文档在它的<vxml>元素里指定根文档。
    这样的话,每次解释器要加载执行该应用的一个叶文档时,如果应用根文档还没有加载,它会先加载应用根文档。应用根文档会一直被加载,直到解释器加载另外一个应用的文档。因此,解释器在解释的时候,下面两个条件,必须满足一个:
      1、应用根文档已经加载,且用户正在根文档里执行,没有叶文档被加载。
      2、应用根文档和一个叶文档都被加载,且用户在叶文档里执行。如果各个文档里有定义了一些subdialog,此时可能不止加载一个叶文档,但是只能在其中的一个文档中执行。
    当加载一个叶文档时,虽然根文档也被加载,但是根文档中的对话不会被执行,而是在叶文档中执行。
    多文档应用有几个好处:
      1、叶文档可以使用根文档的变量,因此一些信息能够共享,并保留下来;
      2、根文档的<property>元素可以给叶文档要用的一些property指定默认值;
      3、公有的ECMAScript代码可以放在根文档的<script>元素中,然后在叶文档中使用;
      4、根文档中的<catch>元素可以为叶文档指定默认的事件处理;
      5、根文档中作用域为document的语法在叶文档中也是激活的,这样用户就可以和根文档中的form、link和menu进行交互。
    下面是一个有两个文档的应用:
    应用根文档(app-root.vxml):
      <?xml version="1.0" encoding="UTF-8"?>
      <vxml xmlns="http://www.w3.org/2001/vxml"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.w3.org/2001/vxml
               http://www.w3.org/TR/voicexml20/vxml.xsd"
                version="2.0">
        <var name="bye" expr="'Ciao'"/>
        <link next="operator_xfer.vxml">
          <grammar type="application/srgs+xml" root="root" version="1.0">
            <rule id="root" scope="public">operator</rule>
          </grammar>
        </link>
      </vxml>
    叶文档(leaf.vxml):
      <?xml version="1.0" encoding="UTF-8"?>
      <vxml xmlns="http://www.w3.org/2001/vxml"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.w3.org/2001/vxml
               http://www.w3.org/TR/voicexml20/vxml.xsd"
                version="2.0"  application="app-root.vxml">
        <form id="say_goodbye">
          <field name="answer">
           <grammar type="application/srgs+xml" src="/grammars/boolean.grxml"/>
            <prompt>Shall we say<value expr="application.bye"/>?</prompt>
           <filled>
            <if cond="answer">
             <exit/>
            </if>
             <clear namelist="answer"/>
           </filled>
          </field>
        </form>
      </vxml>
    在这个例子中,该应用的入口文件是leaf.vxml,因此leaf.vxml先被加载,它的application属性指定app-root.vxml为它的应用根文档,因此接着会加载app-root.vxml。在app-root.vxml中定义了一个变量――bye和一个link,只要用户说“operator”,那么控制就会跳转到operator-xfer.vxml。用户由名为say_goodbye的form开始人机交互。
      C: Shall we say Ciao?
      H: Si.
      C: I did not understand what you said. (a platform-specific default message.) 
      C: Shall we say Ciao?
      H: Ciao
      C: I did not understand what you said. 
      H: Operator.
      C: (Goes to operator_xfer.vxml, which transfers the caller to a human operator.) 
    注意,当用户在多文档的应用里,一次最多只有两个文档同时加载:应用根文档和一个应用叶文档,除非用户正在和应用根文档交互(此时只有一个文档加载,即应用根文档)。根文档的元素不能再指定application属性,而叶文档一定要指定application属性。在多文档的情况下,应用根文档总是被加载的,而应用叶文档则不一定。
    应用根文档的绝对URI就是解释器当前的应用名(name of application)。如果有的话,该绝对URI可以包含一个查询字符串,但是它不可以包含段标识符。只要应用名没有变,解释器就一直在同一个应用里。一旦应用名改变,解释器就进入到一个新的应用里,并初始化新应用的根环境。应用根环境包括作用域为application的变量、语法、catch元素、script和property。
    在用户会话期间,解释器从一个文档到另一个文档的跳转可以用<choice>、<goto>、<link>、<subdialog>和<submit>元素。有的跳转是在某个应用内,有的是在两个应用之间。根环境能否保存取决于跳转的类型:
      1、同一应用中根到叶的跳转
      当当前文档为根文档,且目标文档的applocation属性值和当前应用的绝对URI一样,此时的跳转即为同一应用中根到叶的跳转。该应用根文档和它的环境都在跳转中保留下来。
      2、同一应用中叶到叶的跳转
      当当前文档为叶文档,且目标文档的application属性值和当前应用的绝对URI一样,此时的跳转即为同一应用中叶到叶的跳转,该应用根文档和它的环境都在跳转中保留下来。
      3、同一应用中叶到根的跳转
      当当前文档为叶文档,且目标文档的绝对URI和当前应用名一样,此时的跳转即为同一应用中叶到根的跳转。如果是通过<choice>或<goto>或<link>跳转的,该应用根文档和它的环境都在跳转中保留下来。如果是通过<submit>跳转的,根环境会被重新初始化,因为使用<submit>元素总是会导致URI的获取。
      4、根到根的跳转
      当当前文档为根文档,且目标文档也是根文档,即目标文档没有指定application属性,此时的跳转就是根到根的跳转。根环境和由缓存策略(caching policy)返回的应用根文档一起被初始化。 即使目标应用名和当前应用名一样,也可能会使用缓存策略。
      5、子对话
      当根文档或叶文档执行<subdialog>元素,此时即为subdialog调用。正如2.3.4节所讲的,subdialog调用时,创建了一个新的执行环境。在subdialog执行期间,应用根文档和它的环境都被保存起来,但是它们在被调用文档的执行环境里是不可用的。Subdialog新的执行环境有它自己的根环境,也许还有叶环境(leaf context)。当subdialog调用为一个非空的URI时,就可以用缓存策略来获得根和叶文档,以初始化新的根和叶环境。如果subdialog调用为一个空的URI,且为段标识符(例如“#sub1”),则根和叶文档保持不变,因此当前的根和叶文档会用来初始化新的根和叶环境。
      6、应用之间的跳转
      两个应用间的跳转使得应用根环境和下一个应用的根文档一起被初始化。
    如果某个文档引用了一个不存在的应用根文档,则抛出一个error.badfetch事件。如果某个文档的application属性引用的文档也指定了application属性,则抛出一个error.semantic事件。
    下面的图表说明了根和叶文档在应用根环境中跳转的结果。在这个图表中,方框表示文档,方框内纹理的变化表示根环境的初始化,实心箭头表示跳转到箭头所指向的URI,竖向的虚线箭头所指向的表示application属性指定的URI。
图3: 保存根环境的的跳转
    在这个图中,所有的文档都属于同一应用。1、2、3、4表示跳转的步骤:
      1、跳转经由URI A到文档1,应用环境被初始化。假设文档1是这个会话的入口文件。当前的应用名为A。
      2、文档1指定了一个跳转经由URI B到文档2。文档2的application属性值等于A。根文档为文档1,和它的环境一起被保存下来。这是在同一应用中,根到叶的跳转。
      3、文档2指定了一个跳转经由URI C到另外一个叶文档,即文档3。文档3的application属性值也等于A。根文档和它的环境一起被保存下来。这是在同一应用中,叶到叶的跳转。
      4、文档3指定了一个跳转经由URI A到文档1,它是通过来跳转的。文档1的根环境原封不动。这是在同一应用中。叶到根的跳转。
    下面的图说明了初始化根环境的跳转。
图4: 初始化根环境的跳转
      5、文档1指定了一个跳转经由URI A到文档4。文档4没有指定它的application属性,它自己就是根文档,它的根环境被初始化。这是一个根到根的跳转。
      6、文档4指定了一个跳转经由URI D到文档5。文档5的application属性值为URI E和当前的应用名不一样。解释器进入到一个新的应用。URI E指向了文档6。根环境根据文档6的内容来初始化。这就是应用之间的跳转。
      7、文档5指定了一个跳转经由URI A。
 
三、子对话
    subdialog是一种用来分解复杂的对话序列并改善他们的结构,或创建可重用组件的一种机制。例如帐户信息请求可能包含了几部分信息的收集,像帐户号和家庭电话号码。这样的客户管理服务可以由几个应用组成 这些应用能够共享基本的组件,因此用subdialog来构造这个服务就很合理。下面的例子说明了这一点。第一个文档(app.vxml)用来调整用户的帐号,因此,它必须得到帐户的信息和要调整的级别。通过subdialog元素调用另一个VoiceXML文档让用户输入以获得帐户信息。当第二个文档执行的时候,第一个文档的dialog被挂起,等待信息的返回。第二个文档通过<return>元素返回用户交互的结果,返回值可以通过<subdialog>元素的name属性定义的变量获得。
    用户服务程序(app.vxml):
      <?xml version="1.0" encoding="UTF-8"?>
      <vxml xmlns="http://www.w3.org/2001/vxml"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.w3.org/2001/vxml
               http://www.w3.org/TR/voicexml20/vxml.xsd"
                version="2.0">
        <form id="billing_adjustment">
          <var name="account_number"/>
          <var name="home_phone"/>
          <subdialog name="accountinfo" src="acct_info.vxml#basic">
           <filled>
             <!-- Note the variable defined by "accountinfo" is
              returned as an ECMAScript object and it contain
                two properties defined by the variables specified in the
                  "return" element of the subdialog. -->
             <assign name="account_number" expr="accountinfo.acctnum"/>
             <assign name="home_phone" expr="accountinfo.acctphone"/>
           </filled>
          </subdialog>
         <field name="adjustment_amount">
           <grammar type="application/srgs+xml" src="/grammars/currency.grxml"/>
            <prompt>
              What is the value of your account adjustment?
            </prompt>
            <filled>
              <submit next="/cgi-bin/updateaccount"/>
            </filled>
           <field>
         <form>
      </vxml>
    包含帐户信息的subdialog文档(acct_info.vxml):
      <?xml version="1.0" encoding="UTF-8"?>
      <vxml xmlns="http://www.w3.org/2001/vxml"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.w3.org/2001/vxml
               http://www.w3.org/TR/voicexml20/vxml.xsd"
                version="2.0">
        <form id="basic">
          <field name="acctnum">
           <grammar type="application/srgs+xml" src="/grammars/digits.grxml"/>
            <prompt>What is your account number?</prompt>
           <filled>
           <field name="acctphone">
             <grammar type="application/srgs+xml" src="/grammars/phone_numbers.grxml"/>
            <prompt>What is your home telephone number?</prompt>
             <filled>
               <!-- The values obtained by the two fields are supplied
               to the calling dialog by the "return" element. -->
             <return namelist="acctnum acctphone"/>
            </filled>
          </field>
        </form>
      </vxml>
    subdialog被调用的时候产生了一个新的执行环境,subdialog既可以是现有文档的一个新dialog,也可以是新文档的一个新dialog。
    Subdialog可以由几个文档组成。图5展示了一系列文档(D)跳转到subdialog(SD),并返回的执行流程。
图5: subdialog由几个文档组成,并由最后一个subdialog返回
    当dialog D2调用文档sd2.vxml中的subdialog SD1时,dialog D2的执行环境被挂起,sd1指定执行跳转到sd2.vxml中的dialog(使用<goto>元素)。因此,当sd2.vxml中的dialog返回时,控制直接返回到dialog D2。
    图6展示了一个多文档的subdialog调用的例子,在这个例子中,控制由一个subdialog跳转到另一个subdialog。
图6: 由几个文档组成的subdialog,并由第一个subdialog返回
    在sd1.vxml中的subdialog指定将控制跳转到sd2.vxml的另一个subdialog,SD2。当执行SD2时,总共有两个环境被挂起:D2的dialog环境因等待SD1返回而挂起,SD1的dialog因等待SD2返回而挂起。当SD2返回时,控制也返回到SD1,SD1又把控制返回到dialog D2。
 
四、后期处理
    在某些情况下(特别是当VoiceXML解释器处理挂机事件时),解释器可以继续执行,进入后期处理状态,即使解释器和终端用户之间的连接已经中断。后期处理的目的是让VoiceXML应用去完成一些必要的后期的清理。例如提交信息到应用服务器。举个例子来说,下面的<catch>元素将捕获connection.disconnect.hangup事件,并进入后期处理状态执行。
      <catch event="connection.disconnect.hangup">
        <submit namelist="myExit" next="http://mysite/exit.jsp"/>
      </catch>
    然而,在后期处理状态,应用必须保持跳转状态,且不可以进入等待状态(详见4.1.8节),因此,在后期处理状态,应用不应该进入<field>或<record>或<transfer>。如果此时VoiceXML应用试图进入等待状态,VoiceXML解释器必须退出。
    除了上面的限制,VoiceXML应用的执行可以在后期处理状态正常继续。例如,应用在后期处理状态可在文档之间跳转,如果没有任何符合条件的form item被选定的话(详见2.1.1节),解释器必须退出。

(未完待续)
posted on 2006-09-16 15:58 铁观音 阅读(1988) 评论(0)  编辑 收藏 引用 所属分类: VoiceXML2.0规范