SCXML:状态机批注和语音应用程序开发

ZDNet软件频道 时间:2006-04-14 作者:Peter V. Mikhalenko |  我要评论(7)
本文关键词:xml webtrend
数字电话正在迅速普及,这为语音通信提供了新的技术。在本文里,我将探讨一种用于电信行业的新XML语言。

数字电话正在迅速普及,这为语音通信提供了新的技术。在本文里,我将探讨一种用于电信行业的新xml语言。

State Chart xmlSCXML)是(W3C语音浏览器工作组目前正在开发的)VoiceXML 3.0里的控制语言的一个候选对象。Voicexml 3.0包括CCxml 2.0(预计将由语音浏览器工作组在2006年进行开发)和多模编辑语言(正在由多模交互工作组开发)。

它是一种通用状态机语言,能够用在多种环境下,包括Voicexml 3.0、CCxml 2.0和多模交互框架(MultiModal Interaction framework)。

首先,我们将简要介绍这个开发项目的目的,然后再仔细看看SCxml批注,最后我们将探讨Harel State Table批注逻辑及其在SCxml中的体现。

项目目的

新语言所提供的状态机批注结合了CCxml和Harel State Table的概念。

CCXML是一门基于事件的状态机语言,它设计用来支持语音应用程序(尤其包括但不仅限于Voicexml)的呼叫控制功能。CCxml 1.0规范同时定义了状态机和事件处理句法,以及呼叫控制元素的标准化集合。CCxml语言不是本文讨论的范围,我将在另外的文章里专门讨论这门语言。

Harel State Table就是状态机批注,它们也是统一建模语言(UML)的一部分。它们为复杂的构建,比如并行状态,提供了一个清晰、成熟的语义。但是,它们被定义为一门图形规范语言,因此没有xml表示。事件处理模型以及状态和转换的语义都在UML规范有具体的定义。虽然UML也不是本文讨论的范围;但是我们还是要回顾一下UML最基本的一些概念以及SCxml中与之相对应的概念。

SCxml规范的目标是将Harel语义与一种xml句法结合在一起,这种句法是CCxml的状态和事件批注的一个逻辑扩展。SCxml的使用方法有很多种,包括但不仅限于下面几种:

  • 作为CCxml未来版本的一个状态机框架;
  • 作为一门高级对话语言,控制Voicexml 3.0的封装语音模块(voice form、voice picklist等);
  • 作为语音应用程序元语言,它除了提供Voicexml 3.0功能外,还能控制数据库访问和业务逻辑模块等;
  • 作为多模交互框架里的多模控制语言,将Voicexml 3.0对话与其它模式(包括键盘、鼠标、墨水、视觉、触觉等)的对话结合在一起。它还可以控制经过组合的模式,例如唇语(将语音识别和视觉相结合)输入,并将键盘输入作为后备,以及用多个键盘进行多用户编辑。
  • 作为对话控制语言,调用语音识别、双音多频(DTMF)识别、语音合成、音频录制、以及音频回放服务等;
  • 作为扩展呼叫中心管理语言,将CCxml的呼叫控制功能与程控电话集成相结合,这样呼叫中心就可以将电话呼叫与计算机屏幕显示,以及如聊天、即时消息等其他类型的信息交换相结合;
  • 作为其他不涉及语音处理环境下的通用处理控制语言。

Harel State Table批注和语义

为了简化说明过程,让我们来看看UML定义的状态机的最重要特性,以及它在SCxml中的体现。下面所有的示例都取自SCxml规范。

注:xml代码示例都可以从本zip文件里下载获得。

A显示的是一个相当简单的状态机,它有三个状态S1、S2和S3。它对应的SCxml也很直观简单,相当容易理解(example1.txt)。这些状态由转换来连接,由事件来触发。

A

简单的状态机

示例1

<?xml version="1.0" encoding="us-ascii"?>
<scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initialstate="S1">
  <state id="S1">
    <transition event="Event1" target="S2"/>
  </state>
 
  <state id="S2">
    <transition event="Event2" cond="X>0" target="S1"/>
    <transition event="Event2" cond ="X<0" target next="S3"/>
  </state>
 
  <state id="S3">
  </state>
 
</scxml>

在这个例子里,状态会在Event1发生的时候从S1转换到S2。这是系统从S1转换到S2的唯一途径,因为它是这两个状态间唯一的转换。当系统处于S1状态时,其它所有事件会被忽略。

S2状态里的逻辑稍微复杂一点。它有两个转换,都是由事件Event2触发。两个转换都有检查变量X的值的警戒条件。如果X < 0,那么当Event2发生的时候,状态S2就会转换为S3。如果X > 0,状态就会转换回S2。要注意的是,没有条件来考虑X = 0的情况。因此如果当Event2发生的时候X = 0,那么系统仍然会保持在S2状态。就在状态S1里一样,所有在转换过程中没有涉及到的事件都会被忽略。在上面的例子里,只用到了<state>和<transition>这两个元素。

Harel State Table可以嵌入代码,用于执行进入或者退出状态。在B里,我们看到了与图1相同的三个状态,但是S1有一个用来减少X的OnEntry处理程序,而S2也有一个用来减少X的OnExit处理程序。S3同时拥有OnEntryOnExit处理程序,两个都用来增加X。

B

新添加的OnEntryOnExit

现在假设X当前的值是2,系统进入S1状态。当Event1发生的时候,系统会转换到S2状态,这就和前面一个例子一样。现在,当Event2发生的时候,X等于1,所以系统将转换回S1状态。当系统退出S2状态的时候,OnExit处理程序就把X的值减为0。要注意的是,这发生在转换被选择、警戒条件被计算之后。示例2里是相应的SCxml代码(example2.txt)。我们可以看到<onexit><onentry>这两个新元素提供了状态转换处理程序,而<datamodel>元素提供了用在图表里的数据模型。这些数据模型将在下面讨论。

示例2

<?xml version="1.0" encoding="us-ascii"?>
<scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initialstate="S1">
  <datamodel>
    <data name="X" expr="2"/>
  </datamodel>
 
  <state id="S1">
    <onentry>
      <assign name="X" expr="X--"/>
    </onentry>
    <transition event="Event1" target="S2"/>
   </state>
 
  <state id="S2">
    <transition event="Event2" cond= "X>0" target="S1"/>
    <transition event="Event2" cond ="X><0" target="S3"/>
    <onexit>
      <assign name="X" expr="X--"/>
    </onexit>   
  </state>
 
  <state id="S3">
    <onentry>
      <assign name="X" expr="X++"/>
    </onentry>
    <onexit>
      <assign name="Y" expr="0"/>
    </onexit>      
  </state>
 
</scxml>

Harel State Table还包括复合状态的概念,也就是有亚状态(example3.txt里的substate)。在这个例子里,S1有连续的亚状态。当状态机处于带有亚状态的状态时,它必须也只能处于其中的一种亚状态。亚状态有一种“Or”语义,可以被看作代表父状态的分解。将系统变到S1状态的转换可以直接将S11或者S12指定为其“目标(target)”。然而,为了处理它无法处理的情况,S1带有一个<initial>元素,用来定义默认的亚状态,当转换将S1指定为其目标时,它就会开始起作用。

示例3

<?xml version="1.0" encoding="us-ascii"?>
<scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initialstate="S1">

  <state id="S1">
    <state id="S11">
    </state>
    <state id="s12">
    </state>
    <initial>
      <transition target next="S11"/>
    </initial>   
  </state>
</scxml>

除了连续的亚状态,Harel State Chart还提供了并发亚状态(concurrent substate),代表一种“And”逻辑。当状态机处于一种带有并发亚状态的状态时,它必须同时处于每一种并发子状态。

根据基本的Harel语义,S1和S2会独立运行,所以S1会从S11转到S12再到S13而不管S2在做什么,反之亦然。但是现在假设我们想要确保S2不会从S22转到S23,除非S1离开S11。C显示了我们可以如何使用<join>状态达到这个目的。相应的SCxml代码见example4.txt

C

添加<join>状态

示例4

<?xml version="1.0" encoding="us-ascii"?>
<scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initialstate="S1">

  <state>
    <parallel>
     
      <state id="S1">
        <state id="S11">
          <transition target next ="S12 synch1"/>
        </state>
        <state id="S12">
          <transition target next="S13"/>
        </state>
        <state id="S13"/>
        </state>
     
      <state id="S2">
        <state id="S21">
          <transition target="S12"/>
        </state>
        <state id="S22>
          <transition target="j1"/>
         </state>
        <state id="S23"/>
        <join id="j1">
        <transition target="S23"/>
        </join>
      </state>
   
    </parallel>
  </state>
</scxml>

我们在S22和S23之间插入一个<join>伪状态,同时还加入了一个从S22的无条件向内转换(incoming transition)和一个向S23的无条件向外转换(outgoing transition)。(<join>伪状态用一个带有多个向内转换和一个向外转换的竖线来表示。)然后我们用转换离开S11,向它加入分支,以便让<join>状态成为另外一个目标。(在图表里,这用一个‘带分叉’的竖线来表示,用来表示一个向内转换和多个向外转换。在我们的SCxml批注里,我们在“目标”属性里用了多个值。)

现在当状态机达到S22状态时,它会等待,直到<join>状态被激活(这样就准备好进行转换),然后进入<join>状态并转换到S23。类似的,当S1准备离开S11状态时,它会等待,直到S2达到S22状态,然后才进入<join>状态。在上面两种情况里,<join>状态的结果导致S1和S2相互等待,然后才同时进入S12和S13状态。


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134