##SCXML 有限状态机规范概述
State Chart XML(SCXML) 是 W3C 组织制定的一种有限状态机的规范,它提供了一个在 CCXML 和 Harel State Tables 基础之上演化而来的状态机执行环境。但此规范目前还处于 Working Draft,即修订当中,目前最新的修订版本是 W3C Working Draft 16 December 2010,相信随着时间的推移,此规范很快将会发布正式版。
SCXML 的概念源于 CCXML 和 Harel State Tables 的结合。CCXML 是一种用来支持具有呼叫中心功能特点的语音应用程序(例如 VoiceXML 但不仅限于此)基于事件驱动的状态机语言。CCXML 1.0 的说明书定义了状态机和事件处理的两种语法,以及标准化的一些呼叫控制基本单元。CCXML 和 Harel State Tables 的结合搭建起了一套表达了富有规则的、很有想法的语义,并具有精密的构架逻辑,例如:平行状态。它们定义了图形化的规范语言,然而却不再使用基本 XML 的呈现方式。
SCXML 是一种多元化、基于事件状态的机器语言,其用法主要有几个方面 :
它是在 VoiceXML 3.0 的基础之上发展而来的高级对话语言,可封装为不同的语言模块。
作为语言分析的应用开发程序,它在 VoiceXML 3.0 的基础功能之上,还具备了控制数据库连接的功能和商业业务逻辑模块。
作为一种多态的控制语言,在这种多形式的交互式构架中,SCXML 集成了 VoiceXML 3.0 的所有对话形式,这其中包括键盘鼠标,文字,视觉感官,触觉感受等多种交互形态。其可能包括一些综合技术如对口型的阅读(语音识别技术与视觉的结合表现)。语音的输入以键盘作为载体,并且引入多个键盘和多个用户同步编写的功能。
SCXML 还是 CCXML 未来版本的基础构架。
作为一种高级的、可扩展的呼叫中心管理语言,CCXML 又称为被呼叫中心使用的具有控制功能的计算机电话集成系统。这种集成系统应用计算机屏幕弹出窗口,并提供其他方式的信息交互,例如,在线聊天,发送即时信息等。
##有限状态机 SCXML 简单实例
每个 SCXML 状态机文件主要是由多个状态元素以及状态变迁元素以及事件组成。 清单 1. 基于 SCXML 的计时器实例
<scxml xmlns="http://www.w3.org/2005/07/scxml"
version="1.0"
initialstate="reset">
<state id="reset">
<transition event="watch.start" target="running"/>
</state>
<state id="running">
<transition event="watch.split" target="paused"/>
<transition event="watch.stop" target="stopped"/>
</state>
<state id="paused">
<transition event="watch.unsplit" target="running"/>
<transition event="watch.stop" target="stopped"/>
</state>
<state id="stopped">
<transition event="watch.reset" target="reset"/>
</state>
</scxml>
这是一个基于 SCXML 有限状态机规范的计时器实例,在此状态描述文件中,一共有四个状态:rest,running,paused 和 stopped 状态。此状态机的初始状态是 reset 态,是通过 scxml 元素的 initialstate 元素来指定的。这意味当状态机启动时, 最先进入的将会是这个状态。当状态机处于 reset 态的同时有 watch.start 事件发生时,将会触发状态机进行状态迁移,进入 running 态,即计时器运行态。
每个 state 元素可以具有多个状态变迁 transition 子元素,从上例中可以看出,当状态机处于 running 态时,若有 watch.split 事件发生时,将会触发状态迁移事件
<transition event="watch.split" target="paused"/>
使状态机进入 paused 态。而如果是有 watch.sop 事件发生时,将会触发状态迁移事件
<transition event="watch.stop" target="stopped"/>
使状态机进入 stopped 态。
当然,这只是 SCXML 有限状态机最简单的一个示例,仅凭示例中这几个简单的元素,是无法有效的组织起一个成熟的商业应用的。本文后续将会对 SCXML 规范中的元素进行一个详尽的介绍讲解。
##SCXML 规范组成及元素详解 ###核心模型元素
SCXML 元素
该元素是 SCXML 文档的最顶层元素,携带了文档版本等相关信息,当前状态机构成以及子元素等。此元素通过 initialState 属性来指定状态机的进入初始态,可包含 State、Parallel、Final、DataModel 和 Script 子元素。
如果该元素的执行模式处于宽松态,SCXML 引挚一般会忽略该元素所带的不符合规范的属性、子元素以及命名空间信息等。如果该元素的执行模式为严格态,SCXML 引挚将会要求该元素所带的所有属性、子元素和命名空间符合 W3C SCXML 的规范,否则则会认为该 SCXML 文档为不符合规范的文档而拒绝执行。
State 元素
此元素用以表示有限状态机中的一个基本状态,它具有可选的属性 id 和 initial。具有 State 或是 Parallel 子元素的复杂态必须为其指定 initial 属性,用于表示进入此复杂态所应该进入的第一个子状态。
此元素的子元素可以为 OnEntry 元素、OnExit 元素、Transition 元素、State 元素、Parallel 元素、DataModel 元素和 Invoke 元素。
Transition 元素
此元素用以表示状态间的变迁,状态变迁是以事件以驱动的,并会进行变迁条件的判断操作。并且在进行状态迁移时,子元素可以包含执行模块,用以表示在状态迁移时进行的操作。其主要属性包括:
Event 属性,用以表示触发此状态迁移的事件。
Cond 属性,用以表示此状态迁移进行的限制条件。
Target 属性,用以表示此状态迁移的目标态。
此元素可以包括执行模块子元素,例如 Log 元素,下面通过举例进行讲解。 清单 2.Transition 元素实例
<state id=s">
<transition event="e1" cond="x==1" target="s1"/>
<transition event="e2" target="s2">
<log expr="'executing transition'"/>
</transition>
</state>
此代码清单中的 State 元素具有两个 Transition 子元素。第一个 Transition 元素的触发事件是 s1,当 s1 事件发生时,将会进行迁移条件的判断,如果 x==1,状态机将会迁移至 s1 态。第二个 Transition 元素的触发事件是 s2,当 s2 事件发生时,状态机将会直接迁移至 s2 态,但在状态迁移的过程当中,会执行 Log 操作,输出一行日志内容。
Parallel 元素
此元素表示具有并行执行子元素的状态,与 State 元素类似,此元素可以包含 OnEntry 元素、OnExit 元素、Transition 元素、State 元素、Parallel 元素、DataModel 元素和 Invoke 元素为子元素。
但是 Paralle 元素与 State 元素有着不同的语义,当某个 State 元素处于 active 态,其有且只有一个子元素处于 active 态,但是当某个 Parallel 元素处于 active 态时,其所有子元素均处于 active 态。特别的是,当状态机进入某个 Parallel 元素时,将会同时进入其所有的子元素。Parallel 元素和其所有子元素的 Transition 独立的进行,但这些 Transition 中有一个触发,并且其目标态位于 Parallel 之外,状态机将会退出 Parallel 元素与其所有子元素,转而进入目标态。
OnEntry 元素
此元素是一个容器元素,用以包含状态机进入某个状态时所进行的全部操作,其子元素均为可执行模块内容。
OnExit 元素
类似于 OnEntry 元素,此元素也是一个容器元素,用以包含状态机退出某个状态之前所进行的全部操作,其子元素均为可执行模块内容。 可执行内容元素
可执行模块允许状态在运行过程当中做一些实际的事件,它允许某个状态机对话修改自身的数据模型,或是与外部实例进行交互操作。如上文所述,由事件组成的可执行模块可以是 Transition 元素的子无素。特别的是,位于 OnEntry 和 OnExit 元素内的可执行元素模块往往和 Transtion 元素里的可执行元素具有等同的作用效果。当状态机执行 Transition 元素时,它将会执行它离开的那个 State 元素的 OnExit 包含的可执行内容模块,当它进入目标 State 元素时,会执行目标态 OnEntry 元素所包含的可执行内容模块。
此模块主要包含如下几个元素:
Raise 元素,此元素用于在当前状态机会话当中产生一个内部事件,SCXML 引挚必须将此事件放置在当前会话的内部事件序列的尾部。
If 元素,此元素是有条件执行元素的容器,ElseIf 元素和 Else 元素是此元素的可选子元素。If 元素具有 cond 属性,当此属性值为 true 时,状态机将会执行该 If 后的事件子元素,读者可以在后续的代码清单 3 中看到 If 元素的使用示例。
ElseIf 元素,此元素是 If 元素的子元素,当其前续的 If 元素或是 ElseIf 元素条件判断值为 false 时,状态机将会进行当前 ElseIf 元素 cond 值的判断,如果值为 true, 将会执行此 ElseIf 元素后续的事件元素。
Else 元素,此元素是 If 元素的子元素,当其前续的 If 元素或是 ElseIf 元素条件判断值均为 false 时,状态机将会执行此元素后续的事件元素。
Log 元素,此元素为应用提供日志或是调试信息输出的功能,输出的日志信息风格是依赖平台而定的。它具有可选的 label 属性和必选的 expr 属性。
其它元素,SCXML 规范还定义了其它的可执行元素,例如 assign、validate 和 script 等,在这里就不赘述,请读者自行查看。
清单 3. If、ElseIf 和 Else 元素使用示例
<if cond="cond1">
<!-- selected when "cond1" is true -->
<elseif cond="cond2"/>
<!-- selected when "cond1" is false and "cond2" is true -->
<elseif cond="cond3"/>
<!-- selected when "cond1" and "cond2" are false and "cond3" is true -->
<else/>
<!-- selected when "cond1", "cond2", and "cond3" are false -->
</if>
读者可以查看 SCXML 规范的 Executable Content内容模块来查看更多可执行内容元素的信息。 数据模型与数据操作元素
数据模型模块为 SCXML 有限状态机提供了内置的数据存储、读写、修改数据集的能力。SCXML 规范中数据模型用 DataModel 元素来表示,其可以包含一个或是多个 Data 元素,每个 Data 元素表示一个数据项,并可以此数据项指定初始值。可以通过 Assign 元素来修改 Data 数据项的值,通过 Validate 元素来验证 Data 数据值的合法性,并且可以通过 Donedata、Param 等这些元素来完成 Data 元素与外部实例的交互。下面对数据模型模块的 SCXML 元素进行基础的介绍。
Datamodel 元素,此元素为容器元素,可以包含一个或是多个 Data 元素,SCXML 通过 Data 元素来完成基本数据项的定义与使用。
Data 元素,该元素用来声明和组成 Datamodel 元素,具有必选的 id 属性和可选的 src 和 expr 属性。Data 的 id 属性用来唯一标识某一数据项,通过 src 或是 expr 属性来指定属性值。
Assign 元素,此元素用于修改 Data 元素的数据值。具有必选的属性 location,该属性与 Data 元素的 id 属性对应,用于标识某一数据项。通过可选的 expr 为 Data 元素指定新的数据值。
Validate 元素,此元素用于验证 Data 数据值的合法性。当通过 src 为 data 指定外部数据源时,例如 XML 数据源,则可利用此元素和 XML Schema 来验证 Data 数据值的合法性。
Donedata 元素,此元素为容器元素,用以装载 SCXML 状态机进入 Final 态时所返回的数据。当 SCXML 引挚进入 Final 态时,会产生一个 done 事件,引挚必须将 Donedata 元素的数据值指定为 _event.data 全局数据值。此元素的子元素可以为 Content 元素或是 Param 元素。
Content 元素,此元素为将内嵌数据传送至外部服务的容器元素。
Param 元素,此元素提供了一个一般性的用来标识 name/key 或是动态计算的值的方法,该值可传送至外部服务或是被包含在一个事件中。
Script 元素,该模块为有限状态机添加了内置脚本的支持。
清单 4. 数据模型实例
<scxml version="1.0" datamodel="ecmascript">
<datamodel>
<data id="employees" src="//example.com/employees.json"/>
<data id="year" expr="2008"/>
<data id="CEO" expr="\"Mr Big\""/>
<data id="profitable" expr="true"/>
</datamodel>
</scxml>
通过 Data 元素实现数据定义,可以是内置的数据值或是外部数据源。 外部交互元素
外部交互能力允许 SCXML 会话与外部节点间进行事件的发送或是接收,并且同时提供调用外部服务的能力。
Send 元素提供“触发就忘记”的数据传输能力,可以将事件传送至外部环境或是其它的 SCXML 会话。事件传输的细节以及数据格式是 SCXML 引挚所选择的 Event I/O Processor 所决定的,每个 SCXML 引挚都会实现一个或是多个 Event I/O Processor,SCXML 的使用者可以根据需要选择一个他理想的事件 IO 处理器。
Invoke 元素提供一种紧藕合的与外部系统进行交互的方式,特别的是提供触发外部平台定义的服务并传送数据的能力,该服务在完成的时候将会产生一个 done 事件。