Version: Feb 16, 2007
Editors:
Copyright ©2007 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark, document use and software licensing rules apply.
The VoiceXML 2.1 Specification entered the Candidate Recommendation period on 13 June 2005. In order to clarify some issues regarding the content model of the <foreach> element, VoiceXML 2.1 was re-published as a Working Draft on 15 September 2006.
The planned date for entering Proposed Recommendation is 25 April 2007. Preparation of an Implementation Report is a key criteria for moving beyond the Candidate Recommendation. This document describes the requirements for the Implementation Report and the process that the Voice Browser Working Group will follow in preparing the report.
During the CR period, the Working Group will carry out the following activities:
You are invited to contribute to the assessment of the W3C VoiceXML 2.1 Specification by participating in the Implementation Report process.
The VBWG established the following entrance criteria to Proposed Recommendation in the Request for CR:
Require implementations and testimonial statements for at least two VoiceXML User Agents supporting both ASR and DTMF.
The following table lists the assertions that were gleaned from the VoiceXML 2.1 Specification. The ID column uniquely identifies the assertion and links to a corresponding test. The Spec column identifies the section of the specification from which the assertion was derived. The Req column indicates whether or not the spec requires the platform to implement the feature described by the assertion. The Auto column indicates whether or not the associated test can be automated or requires manual execution. The Abstract column describes the assertion. The Results column tabulates the results submitted by the VoiceXML platform contributors enumerated in Section 6, Systems.
ID | Spec | Req | Auto | Abstract | Results | ||
---|---|---|---|---|---|---|---|
Pass | Fail | N/I | |||||
1 | [sec-grammar_expr] | Yes. | Yes. | Grammar element may include a srcexpr attribute to dynamically generate grammar URL | 7 | 0 | 0 |
2 | [sec-grammar_expr] | Yes. | Yes. | If both src and srcexpr are included, error.badfetch is thrown | 7 | 0 | 0 |
3 | [sec-grammar_expr] | Yes. | Yes. | If both srcexpr and inline grammar are included, error.badfetch is thrown | 7 | 0 | 0 |
4 | [sec-grammar_expr] | Yes. | Yes. | If none of src, srcexpr nor inline grammar are included, error.badfetch is thrown | 7 | 0 | 0 |
5 | [sec-grammar_expr] | Yes. | Yes. | srcexpr must be evaluated every time the grammar element needs to be executed | 7 | 0 | 0 |
7 | [sec-grammar_expr] | Yes. | Yes. | If srcexpr cannot be evaluated, an error.semantic is thrown | 7 | 0 | 0 |
9 | [sec-script_expr] | Yes. | Yes. | Script element may include an srcexpr attribute to dynamically generate script URL | 7 | 0 | 0 |
10 | [sec-script_expr] | Yes. | Yes. | If both src and srcexpr are included, error.badfetch is thrown | 7 | 0 | 0 |
11 | [sec-script_expr] | Yes. | Yes. | If none of src, srcexpr nor inline script are included, error.badfetch is thrown | 7 | 0 | 0 |
12 | [sec-script_expr] | Yes. | Yes. | srcexpr must be evaluated every time the script element needs to be executed | 7 | 0 | 0 |
13 | [sec-script_expr] | Yes. | Yes. | If both srcexpr and inline script are included, error.badfetch is thrown | 7 | 0 | 0 |
14 | [sec-script_expr] | Yes. | Yes. | If both src and inline script are included, error.badfetch is thrown | 7 | 0 | 0 |
15 | [sec-script_expr] | Yes. | Yes. | If srcexpr cannot be evaluated, an error.semantic is thrown | 7 | 0 | 0 |
16 | [sec-mark] | Yes. | Yes. | When a <mark> is executed during the processing of a form item, the interpreter sets shadow variables, the names of which correspond to the properties of the application.lastresult$ object. The value of each shadow variable must be identical to the value of the corresponding application.lastresult$ property. | 6 | 1 | 0 |
17 | [sec-mark] | Yes. | Yes. | VoiceXML 2.1 extends the <mark> element to support the nameexpr attribute, which is an ECMAScript expression that evaluates to the name of the <mark>. | 6 | 1 | 0 |
18 | [sec-mark] | Yes. | Yes. | Exactly one of "name" and "nameexpr" must be specified; otherwise, an error.badfetch event is thrown. | 7 | 0 | 0 |
19 | [sec-mark] | Yes. | Yes. | The markname and marktime properties of the application.lastresult$ object must be set whenever the application.lastresult$ object is assigned and a <mark> has been executed. | 6 | 1 | 0 |
20 | [sec-mark] | Yes. | Yes. | If no <mark> was executed, the markname and marktime properties of application.lastresult$ are undefined. | 6 | 1 | 0 |
21 | [sec-data] | Yes. | Yes. | If content is not returned within the specified fetchtimeout, an error.badfetch event is thrown. | 7 | 0 | 0 |
22 | [sec-data] | Yes. | Yes. | The interpreter fetches the URI specified by the src attribute. | 7 | 0 | 0 |
23 | [sec-data] | No. | Yes. | If the name attribute is specified, the interpreter exposes the DOM through the ECMAScript variable corresponding to the value of the name attribute. | 7 | 0 | 0 |
24 | [sec-data] | Yes. | Yes. | If the name attribute is present, and the interpreter doesn't support DOM, the interpreter must throw error.unsupported.data.name. | 4 | 0 | 3 |
25 | [sec-data] | Yes. | Yes. | The interpreter evaluates the srcexpr attribute as an ECMAScript expression when the <data> element needs to be executed. The result of evaluating the srcexpr attribute is the URI to be fetched. | 7 | 0 | 0 |
26 | [sec-data] | Yes. | Yes. | If srcexpr cannot be evaluated, error.semantic is thrown. | 7 | 0 | 0 |
27 | [sec-data] | Yes. | Yes. | Exactly one of "src" or "srcexpr" must be specified; otherwise, an error.badfetch event is thrown. | 7 | 0 | 0 |
28 | [sec-data] | Yes. | Yes. | Interpreters must support the methods GET and POST when submitting an HTTP request. GET is the default method. | 7 | 0 | 0 |
29 | [sec-data] | Yes. | Yes. | Specifying a URL that points to a non-existent resources causes the interpreter to throw a catchable error.badfetch event. | 7 | 0 | 0 |
30 | [sec-data] | Yes. | Yes. | If the name attribute is specified, the interpreter supports the DOM, and the interpreter retrieves an XML document that is not well-formed, the interpreter must throw a catchable error.badfetch. | 7 | 0 | 0 |
31 | [sec-data] | Yes. | Yes. | The <data> element can occur in executable content or as a child of <form> or <vxml>. | 7 | 0 | 0 |
32 | [sec-data] | Yes. | Yes. | The <data> element shares the same scoping rules as the <var> element. | 7 | 0 | 0 |
33 | [sec-data] | Yes. | Yes. | If a <data> element has the same name as a variable already declared in the same scope, the variable is assigned a reference to the DOM exposed by the <data> element. | 7 | 0 | 0 |
34 | [sec-data] | Yes. | Yes. | If use of the DOM causes a DOMException to be thrown, but the DOMException is not caught by an ECMAScript catch handler, the VoiceXML interpreter throws error.semantic. | 7 | 0 | 0 |
35 | [sec-data] | Yes. | Yes. | When an ECMAScript variable is submitted to the server its value is first converted into a string before being submitted. | 7 | 0 | 0 |
36 | [sec-data] | Yes. | Yes. | The default encoding type of the submitted document is "application/x-www-form-urlencoded". | 7 | 0 | 0 |
37 | [sec-data] | Yes. | Yes. | If the enctype attribute is set to "multipart/form-data", the interpreters must submit the document using that encoding type. | 7 | 0 | 0 |
38 | [sec-data] | Yes. | Yes. | If the namelist is not specified, no variables are submitted. | 6 | 1 | 0 |
39 | [sec-data] | Yes. | Yes. | If <data> has a namelist attribute, all and only those variables are submitted. | 7 | 0 | 0 |
40 | [sec-data] | Yes. | Yes. | If a namelist is supplied, it may contain individual variable references which are submitted with the same qualification used in the namelist. | 7 | 0 | 0 |
41 | [sec-data] | Yes. | No. | If specified, fetchaudio plays during a long fetch. | 7 | 0 | 0 |
42 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the code property of the DOMException object as specified in DOM Level 2 . | 6 | 1 | 0 |
43 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the documentElement property of the Document object as specified in DOM Level 2 . | 7 | 0 | 0 |
44 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getElementsByTagName method of the Document object as specified in DOM Level 2 . | 7 | 0 | 0 |
45 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getElementsByTagNameNS method of the Document object as specified in DOM Level 2 . | 7 | 0 | 0 |
46 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getElementById method of the Document object as specified in DOM Level 2 . | 7 | 0 | 0 |
47 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the nodeName property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
48 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the nodeValue property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
49 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the nodeType property of the Node object as specified in DOM Level 2 . | 6 | 0 | 1 |
50 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the parentNode property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
51 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the childNodes property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
52 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the firstChild property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
53 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the lastChild property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
54 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the previousSibling property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
55 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the nextSibling property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
56 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the attributes property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
57 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the ownerDocument property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
58 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the namespaceURI property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
59 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the prefix property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
60 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the localName property of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
61 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the hasChildNodes method of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
63 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the hasAttributes method of the Node object as specified in DOM Level 2 . | 7 | 0 | 0 |
64 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the length property of the NodeList object as specified in DOM Level 2 . | 7 | 0 | 0 |
65 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the item method of the NodeList object as specified in DOM Level 2 . | 7 | 0 | 0 |
66 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the length property of the NamedNodeMap object as specified in DOM Level 2 . | 7 | 0 | 0 |
67 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getNamedItem method of the NamedNodeMap object as specified in DOM Level 2 . | 7 | 0 | 0 |
68 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the item method of the NamedNodeMap object as specified in DOM Level 2 . | 7 | 0 | 0 |
69 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getNamedItemNS method of the NamedNodeMap object as specified in DOM Level 2 . | 7 | 0 | 0 |
70 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the data property of the CharacterData object as specified in DOM Level 2 . | 7 | 0 | 0 |
71 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the length property of the CharacterData object as specified in DOM Level 2 . | 7 | 0 | 0 |
72 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the substringData method of the CharacterData object as specified in DOM Level 2 . | 7 | 0 | 0 |
73 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the name property of the Attr object as specified in DOM Level 2 . | 7 | 0 | 0 |
74 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the specified property of the Attr object as specified in DOM Level 2 . | 7 | 0 | 0 |
75 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the value property of the Attr object as specified in DOM Level 2 . | 7 | 0 | 0 |
76 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the ownerElement property of the Attr object as specified in DOM Level 2 . | 7 | 0 | 0 |
77 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the tagName property of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
78 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getAttribute method of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
79 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getAttributeNode method of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
80 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getElementsByTagName method of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
81 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getAttributeNS method of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
82 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getAttributeNodeNS method of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
83 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the getElementsByTagNameNS method of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
84 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the hasAttribute method of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
85 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the hasAttributeNS method of the Element object as specified in DOM Level 2 . | 7 | 0 | 0 |
86 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the target property of the ProcessingInstruction object as specified in DOM Level 2 . | 7 | 0 | 0 |
87 | [sec-data-dom] | No. | Yes. | The DOM exposed by the <data> tag must support the data property of the ProcessingInstruction object as specified in DOM Level 2 . | 7 | 0 | 0 |
88 | [sec-foreach] | Yes. | Yes. | The <foreach> element can occur as a child of a <prompt> element. | 7 | 0 | 0 |
89 | [sec-foreach] | Yes. | Yes. | The array attribute must be an ECMAScript expression that evaluates to an array; otherwise an error.semantic is thrown. | 7 | 0 | 0 |
90 | [sec-foreach] | Yes. | Yes. | The item variable stores each array item upon iteration of the loop. A new variable will be declared if it is not already defined within the parent's scope. | 7 | 0 | 0 |
92 | [sec-reco_reco] | Yes. | No. | When the "recordutterance" property is set to true, the "recording" shadow variable of an input item (e.g. field) stores a reference to the recording when audio is collected from the user. Utterance recordings can be played back using the expr attribute of the audio element. | 7 | 0 | 0 |
94 | [sec-reco_reco] | Yes. | Yes. | when property "recordutterance" is set to true, an input item has been filled and has its shadow variables assigned, "recordingsize" must be set in the shadow variable for that input item variable | 7 | 0 | 0 |
95 | [sec-reco_reco] | Yes. | Yes. | When the shadow variable "recordingsize" is set, it must contain the size of the recorded audio in bytes | 7 | 0 | 0 |
96 | [sec-reco_reco] | Yes. | Yes. | when property "recordutterance" is set to true, an input item has been filled and has its shadow variables assigned, "recordingduration" must be set in the shadow variable for that input item variable | 7 | 0 | 0 |
97 | [sec-reco_reco] | Yes. | Yes. | When the shadow variable "recordingduration" is set, it must contain the duration of the recorded audio in milliseconds | 7 | 0 | 0 |
98 | [sec-reco_reco] | Yes. | Yes. | application.lastresult$ must have the shadow variable "recording" set to the same value as the form item shadow variable | 7 | 0 | 0 |
99 | [sec-reco_reco] | Yes. | Yes. | application.lastresult$ must have the shadow variable "recordingsize" set to the same value as the form item shadow variable | 7 | 0 | 0 |
100 | [sec-reco_reco] | Yes. | Yes. | application.lastresult$ must have the shadow variable "recordingduration" set to the same value as the form item shadow variable | 7 | 0 | 0 |
101 | [sec-reco_reco] | Yes. | Yes. | In the case of <link> and <menu>, the interpreter only sets the application.lastresult$ properties. | 7 | 0 | 0 |
102 | [sec-reco_reco] | No. | Yes. | <record> may record user utterances while attempting recognition | 2 | 0 | 5 |
103 | [sec-reco_reco] | Yes. | Yes. | enctype must be "multipart/form-data" when sending the recording on the namelist | 7 | 0 | 0 |
104 | [sec-reco_reco] | Yes. | Yes. | type must be "POST" when sending the recording on the namelist | 7 | 0 | 0 |
105 | [sec-reco_reco-type] | Yes. | Yes. | set the media format of recorded audio during recognition using the recordutterancetype property | 7 | 0 | 0 |
106 | [sec-reco_reco-type] | Yes. | No. | The platform must support the audio file format 'audio/basic' as specified in Appendix E of the VoiceXML 2.0 specification. | 7 | 0 | 0 |
108 | [sec-disconnect] | Yes. | No. | The default for namelist of a disconnect element is to return no variables; this means the interpreter context will receive an empty ECMAScript object. | 7 | 0 | 0 |
109 | [sec-disconnect] | Yes. | No. | The variables specified in the namelist attribute of the disconnect element are returned to the interpreter context. (The precise mechanism by which these variables are made available to the interpreter context is platform specific.) | 7 | 0 | 0 |
111 | [sec-disconnect] | Yes. | Yes. | If the namelist attribute of a disconnect element contains one or more undeclared variables, the interpreter throws error.semantic. | 7 | 0 | 0 |
112 | [sec-transfer] | No. | No. | If type is specified and bridge not specified, type takes precedence over the default value of the bridge attribute. | 6 | 0 | 1 |
113 | [sec-transfer] | No. | No. | If type="consultation" an outgoing call is attempted to the specified destination. | 4 | 0 | 3 |
114 | [sec-transfer] | No. | No. | If type="consultation" and the caller disconnects while the outgoing call is attempted, connection.disconnect.hangup is thrown. | 4 | 0 | 3 |
115 | [sec-transfer] | No. | No. | If type="consultation" and the caller cancels the transfer attempt while the outgoing call is attempted by using a DTMF command, the transfer form item variable is filled with near_end_disconnect. | 4 | 0 | 3 |
116 | [sec-transfer] | No. | No. | If type="consultation" and the caller cancels the transfer attempt while the outgoing call is attempted by using a voice command, the transfer form item variable is filled with near_end_disconnect. | 1 | 0 | 6 |
117 | [sec-transfer] | No. | No. | If type="consultation" and an outgoing call is attempted to a specified destination that is busy, the transfer form item variable will be filled with busy. | 4 | 0 | 3 |
118 | [sec-transfer] | No. | No. | If type="consultation" and an outgoing call is attempted to a specified destination but an intermediate network is busy, the transfer form item variable will be filled with network_busy. | 4 | 0 | 3 |
119 | [sec-transfer] | No. | No. | If type="consultation" and the outgoing call is not answered within the time specified by connecttimeout, the transfer attempt terminates, and the transfer form item variable is filled with noanswer. | 4 | 0 | 3 |
120 | [sec-transfer] | No. | No. | If type="consultation" and the transfer attempt ends but the reason is not known, the transfer form item variable is filled with unknown. | 4 | 0 | 3 |
121 | [sec-transfer] | No. | No. | If type="consultation" and the outgoing call is answered, the platform disconnects from the conversation, connection.disconnect.transfer is thrown, the transfer form item variable is undefined, and the calling and called parties remain connected. | 4 | 0 | 3 |
122 | [sec-transfer] | No. | Yes. | If type="consultation" and the platform does not support consultation transfer, error.unsupported.transfer.consultation is thrown. | 4 | 0 | 3 |
123 | [sec-transfer] | No. | No. | The transfer element's "connecttimeout" value is not honored unless either "bridge" is set to true or "type" is set to "bridge" or "consultation". | 5 | 0 | 2 |
124 | [sec-transfer] | No. | Yes. | Exactly one of "bridge" or "type" may be specified; otherwise an error.badfetch event is thrown. | 6 | 0 | 1 |
125 | [sec-transfer] | No. | No. | The "maxtime" value will only be honored if the "bridge" attribute is set to "true", or the "type" is set to "bridge" | 5 | 0 | 2 |
126 | [sec-transfer] | No. | No. | When "transferaudio" is specified, and the audio file has not completed playing, the audio will cease upon a far-end connection. | 3 | 0 | 4 |
127 | [sec-reco_reco] | Yes. | Yes. | If recordutterance property is set to false, recording shadow variable will be set to undefined after filling a <field> using speech input | 7 | 0 | 0 |
128 | [sec-reco_reco] | Yes. | Yes. | If recordutterance property is set to false, recordingsize shadow variable will be set to undefined after filling a <field> using speech input | 7 | 0 | 0 |
129 | [sec-reco_reco] | Yes. | Yes. | If recordutterance property is set to false, recordingduration shadow variable will be set to undefined after filling a <field> using speech input | 7 | 0 | 0 |
130 | [sec-reco_reco] | No. | Yes. | If recordutterance property is set to false, recording shadow variable will be set to undefined after terminating a <record> with speech | 5 | 0 | 2 |
131 | [sec-reco_reco] | No. | Yes. | If recordutterance property is set to false, recordingsize shadow variable will be set to undefined after termininating a <record> using speech | 4 | 0 | 3 |
132 | [sec-reco_reco] | No. | Yes. | If recordutterance property is set to false, recordingduration shadow variable will be set to undefined after terminating a <record> using speech | 4 | 0 | 3 |
133 | [sec-reco_reco] | No. | Yes. | If recordutterance property is set to false, recording shadow variable will be set to undefined after terminating a <transfer> using speech | 3 | 0 | 4 |
134 | [sec-reco_reco] | No. | Yes. | If recordutterance property is set to false, recordingsize shadow variable will be set to undefined after terminating a <transfer> using speech | 3 | 0 | 4 |
135 | [sec-reco_reco] | No. | Yes. | If recordutterance property is set to false, recordingduration shadow variable will be set to undefined after terminating a <transfer> using speech | 3 | 0 | 4 |
136 | [sec-reco_reco] | Yes. | Yes. | Recorded utterance may be posted using <submit> | 7 | 0 | 0 |
137 | [sec-reco_reco] | Yes. | Yes. | Recorded utterance may be posted using <subdialog> | 7 | 0 | 0 |
138 | [sec-reco_reco] | Yes. | Yes. | Recorded utterance may be posted using <data> | 7 | 0 | 0 |
141 | [sec-mark] | Yes. | Yes. | If nameexpr cannot be evaluated, an error.semantic event is thrown. | 7 | 0 | 0 |
142 | [sec-data] | Yes. | Yes. | If the datafetchhint property is set to "safe", content of that type is never fetched until it is needed | 7 | 0 | 0 |
143 | [sec-data] | Yes. | No. | A cached data resource must be reloaded if the datamaxage property for its type is less than its current age. | 7 | 0 | 0 |
144 | [sec-data] | Yes. | No. | A cached data resource must be reloaded if the datamaxstale property for its type is less than its current staleness. | 7 | 0 | 0 |
145 | [sec-disconnect] | Yes. | No. | The <disconnect> namelist and the <exit> namelist are processed independently. If the interpreter executes both a <disconnect> namelist and an <exit> namelist, both sets of variables are available to the interpreter context. (The precise mechanism by which these variables are made available to the interpreter context is platform specific.) | 7 | 0 | 0 |
146 | [sec-reco_reco] | No. | Yes. | <transfer> may record user utterances while attempting recognition | 1 | 0 | 6 |
147 | [sec-reco_reco-type] | Yes. | No. | platform must support audio file format audio/x-alaw-basic from VXML 2.0 | 7 | 0 | 0 |
148 | [sec-reco_reco-type] | Yes. | No. | platform must support audio file format audio/x-wav from VXML 2.0 | 7 | 0 | 0 |
149 | [sec-foreach] | Yes. | Yes. | The array attribute must evaluate to an ECMAScript Array; otherwise, an error.semantic event is thrown. (Tests various data types from foreach appearing within a block.) | 3 | 0 | 4 |
150 | [sec-foreach] | Yes. | Yes. | The array attribute must evaluate to an ECMAScript Array; otherwise, an error.semantic event is thrown. (Tests various data types from foreach appearing within a prompt in a block.) | 3 | 0 | 4 |
151 | [sec-foreach] | Yes. | Yes. | The array attribute must evaluate to an ECMAScript Array; otherwise, an error.semantic event is thrown. (Tests various data types from foreach appearing within a prompt in a field.) | 3 | 0 | 4 |
152 | [sec-foreach] | Yes. | Yes. | The assigned value could be undefined for a sparse array. (Tests sparse array handling.) | 3 | 0 | 4 |
153 | [sec-foreach] | Yes. | Yes. | The foreach element operates on a shallow copy of the array specified by the array attribute. | 3 | 0 | 4 |
154 | [sec-foreach] | Yes. | Yes. | A shallow copy of the corresponding array element is assigned to the item variable. | 3 | 0 | 4 |
155 | [sec-foreach] | Yes. | Yes. | Executable content is not allowed within foreach contained within a prompt. (This tests a prompt inside block.) | 3 | 0 | 4 |
156 | [sec-foreach] | Yes. | Yes. | Executable content is not allowed within foreach contained within a prompt (this test includes the prompt in a field). | 3 | 0 | 4 |
This appendix describes a framework for authoring VoiceXML tests. The framework abstracts the markup used to define interactions with the user, allowing vendors to use their own test infrastructure by applying an XSLT transformation to the test source. Modifications to the test infrastructure should require a change to the XSLT template only followed by re-transformation of the test source.
The test API described in this document uses the complete schema specified in the VoiceXML 2.1 specification with the addition of a set of twelve elements in their own namespace (http://www.w3.org/2002/vxml-conformance) that greatly simplify the process of authoring tests and abstract the implementation details of the testing infrastructure. The elements are divided into four categories:
These elements are used to signal the completion of a test and, as such, SHOULD terminate test execution. They can appear anywhere that VXML executable.content is legal (e.g. block, event handlers, filled). Final status tags may be rendered in different ways. The most likely candidates are an exit with a return value, a submit, or a log followed by an exit.
reason | Optional. A simple text string explaining the probable cause for failure. |
---|---|
expr | Optional. An ECMAScript expression that evaluates to a string at run-time providing information about the probable cause for failure. |
These elements may be used to signal transitions in a multi-part test. They may appear anywhere that VXML executable.content is legal (e.g. block, event handlers, filled). Intermediate status tags may be rendered in different ways. The most likely candidates are using log or prompt or ignoring the element entirely.
These tags may be used at any point that input is required (e.g. initial, field, record, transfer) or on input-related event handlers (e.g. noinput and nomatch). These elements may be rendered in several different ways A few possibilities include playing DTMF prompts to control an external test driver, using properties to control the recognition result, or using platform-specific test features.
If these tags define prompts, they MUST provide separate prompts with counts 1 through 3.
value | Required. Uniquely identifies the utterance. |
---|
value | Required. The sequence of DTMF digits. |
---|
value | Required. A unique identifier that specifies the desired recording from the user or test driver.
The possible values for the attribute include the following:
|
---|
Grammars are expected to return one of three classes of results:
The utterance attribute specifies which audio input is expected to match this grammar. Grammars may map to a simple result by specifying an interpretation via the interp attribute. More complex results may be returned using the key element.
NOTE: A grammar element may NOT specify an interp attribute and one or more key elements simultaneously.
utterance | Required. Specifies the unique identifier of an utterance. |
---|---|
interp | Optional. Specifies a simple result string returned by the interpreter when the utterance is matched. |
name | Required. The string identifying the key. The string should be a valid ECMAScript variable name. Keys are used to express structured recognition results. Each key may contain either PCDATA or one or more key elements. Multiple keys with the same name may appear; this allows arrays to be built for complex results such as the 'pizza' example. |
---|---|
value | Optional. A string representing the value the key. If the value is omitted, the key element element MUST contain one or more key elements. |
utterance | Specifies the unique identifier of an utterance. |
---|
The stylesheet author is required to select eight utterances, represented in the test framework by the first eight symbols in the International Radio Alphabet. In practice, the actual values will be specific to each language and may differ for each recognizer. These words or phrases should be carefully chosen such that speech utterances match corresponding grammars with high confidence scores. For example, setting the value attribute of the speech element to "alpha" should reliably match (i.e. produce a confidence of at least 0.5) a grammar that is rendered when setting the value of the utterance attribute of the grammar element to "alpha". Likewise, speech utterances should either produce low scores or not match grammars corresponding to different utterances. For example, setting the value attribute of the speech element to "alpha" should reliably return a confidence of less that 0.5 when match against the grammar produced by setting the utterance attribute of the grammar element to "bravo".
It should be reiterated that testing recognition accuracy is not a goal of this suite. Hence, the stylesheet author may freely select any eight phrases.
As defined in the Test API markup, the speech element should be used to request a predefined utterance from the user or test driver. In the document type definition (DTD) below, the 'ir-commands' entity defines the set of valid unique identifiers. The list is easily extended, and the XSLT should be updated to handled additional identifiers when processing the speech, grammar, and phrase elements.
The following DTD succintly declares the Test API markup elements, their attributes, and the legal values for those attributes if applicable.
<!ELEMENT conf:pass EMPTY> <!ELEMENT conf:fail EMPTY> <!ATTLIST conf:fail reason CDATA #IMPLIED expr CDATA #IMPLIED> <!ENTITY % ir-utterances 'alpha|bravo|charlie|delta|echo|foxtrot|golf|hotel'> <!ENTITY % ir-commands '%ir-utterances;|help|cancel|exit|yes'> <!ELEMENT conf:dtmf EMPTY> <!ATTLIST conf:dtmf value CDATA #REQUIRED count CDATA #IMPLIED pre_mark CDATA #IMPLIED post_mark CDATA #IMPLIED> <!ELEMENT conf:hangup EMPTY > <!ELEMENT conf:noinput EMPTY > <!ATTLIST conf:noinput duration CDATA #IMPLIED count CDATA #IMPLIED pre_mark CDATA #IMPLIED post_mark CDATA #IMPLIED> <!ELEMENT conf:nomatch EMPTY > <!ATTLIST conf:nomatch duration CDATA #IMPLIED count CDATA #IMPLIED pre_mark CDATA #IMPLIED post_mark CDATA #IMPLIED> <!ELEMENT conf:recording EMPTY > <!ATTLIST conf:recording value (%ir-utterances;|nonspeech) #REQUIRED count CDATA #IMPLIED pre_mark CDATA #IMPLIED post_mark CDATA #IMPLIED> <!-- Add conf:speech to the menu element decl. --> <!ELEMENT conf:speech EMPTY> <!ATTLIST conf:speech value (%ir-commands;) #REQUIRED count CDATA #IMPLIED pre_mark CDATA #IMPLIED post_mark CDATA #IMPLIED> <!ELEMENT conf:grammar (conf:key*)> <!ATTLIST conf:grammar utterance (%ir-utterances;) #REQUIRED interp CDATA #IMPLIED > <!ELEMENT conf:key (#PCDATA | conf:key)* > <!ATTLIST conf:key name CDATA #REQUIRED value CDATA #IMPLIED > <!ELEMENT conf:phrase EMPTY > <!ATTLIST conf:phrase utterance (%ir-commands;) #REQUIRED > <!ELEMENT conf:comment (#PCDATA | value)*> <!ENTITY % ir-test-ext "conf:pass | conf:fail | conf:comment "> <!ENTITY % ir-prompts "conf:speech | conf:dtmf | conf:hangup | conf:noinput | conf:nomatch | conf:recording"> |
To incorporate the test API into the VoiceXML 2.1 DTD to validate test source against the DTD, perform the following steps:
Alternatively, you can transform your test source through the XSLT, and validate the output against the VoiceXML 2.1 DTD.
The following examples illustrate the use of the proposed tags. These examples were written to help validate the stylesheet used to generate the tests. These tests should all pass before the stylesheet is applied to the main body of tests.
The following example demonstrates simple usage of the conf:pass element. When the block is executed, the transformation of the conf:pass element will be executed.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <form> <block> <conf:pass/> </block> </form> </vxml> |
The following example demonstrates simple usage of the conf:fail element. When the block is executed, the transformation of the conf:fail element will be executed.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <form> <block> <conf:fail/> </block> </form> </vxml> |
The following example demonstrates usage of the reason attribute of the conf:fail element. When the block is executed, the transformation of the conf:fail element will be executed. Although some interpreters may ignore the reason attribute, others may output the value in a log element or submit it to a server-side script for further processing.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <form> <block> <conf:fail reason="roulette"/> </block> </form> </vxml> |
The following example demonstrates usage of the reason attribute of the conf:fail element. When the block is executed, the transformation of the conf:fail element will be executed. Although some interpreters may ignore the expr attribute, others may output the value via a value element contained within a log element. In this example, the expr attribute will evaluate to "pete 3" at runtime.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <form> <block> <conf:fail expr="'pete ' + (1 + 2)"/> </block> </form> </vxml> |
The following example demonstrates usage of the reason attribute of the conf:comment element. Although some interpreters may ignore the element, others may output the contents via a log element. Still others may output the contents via a prompt element. In this example, the interpreter should output "The value of x is 2" at runtime.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <var name="x" expr="1+1"/> <form> <block> <conf:comment> The value of x is <value expr="x"/>. </conf:comment> <conf:pass/> </block> </form> </vxml> |
The following example sends a request to the tester to hangup and catches the connection.disconnect.hangup event. If the event is caught, the interpreter executes the transformation of the conf:pass element. If some other event is executed or no event fires and the block is executed, the transformation of the conf:fail is executed.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <catch><conf:fail expr="_event"/></catch> <form> <field name="one"> <catch event="connection.disconnect.hangup"> <conf:pass/> </catch> <catch><conf:fail expr="_event"/></catch> <conf:hangup/> <conf:grammar utterance="alpha"/> </field> <block><conf:fail reason="block"/></block> </form> </vxml> |
The following example sends a request for no input to the tester when field 'one' is executed. If the tester is silent and a noinput event is generated, the noinput handler should execute, and the interpreter should execute the noinput element. If some other event is executed or no event fires and the block is executed, the transformation of the conf:fail is executed.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <catch><conf:fail reason="catch"/></catch> <form> <field name="one"> <noinput><conf:pass/></noinput> <catch><conf:fail expr="_event"/></catch> <conf:noinput/> <conf:grammar utterance="alpha"/> </field> <block><conf:fail reason="block"/></block> </form> </vxml> |
The following example sends a request for a nomatch to the tester when field 'one' is executed. If the tester says or plays something out of grammar and a nomatch event is generated, the nomatch handler should execute, and the interpreter should execute the nomatch element. If some other event is executed or no event fires and the block is executed, the transformation of the conf:fail is executed.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <catch><conf:fail expr="_event"/></catch> <form> <field name="one"> <nomatch><conf:pass/></nomatch> <catch><conf:fail expr="_event"/></catch> <conf:nomatch/> <conf:grammar utterance="alpha"/> </field> <block><conf:fail reason="block"/></block> </form> </vxml> |
The following example demonstrate the usage of the conf:speech and conf:grammar elements. The conf:speech element is transformed into a series of prompts that correspond to the identifier "alpha". The conf:grammar element is transformed into a simple grammar that corresponds the phrase that matches the alpha utterance mapping. Since the interp attribute of the conf:grammar element is not specified the specific value returned by the interpreter when the grammar is matched cannot be tested. What can be tested is whether or not the form item variable one is defined. The block following the field peforms that check.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <catch><conf:fail expr="_event"/></catch> <form> <block> <if cond="one != undefined"> <conf:fail reason="initial check"/> </if> </block> <field name="one"> <conf:speech value="alpha"/> <conf:grammar utterance="alpha"/> </field> <block> <if cond="one != undefined"><conf:pass/></if> <conf:fail reason="field assignment"/> </block> </form> </vxml> |
The following example demonstrates usage of the interp attribute of the conf:grammar element. If the tester utters the phrase that corresponds to "alpha", the interpreter recognizes the utterance and fills the form item variable one with the value of the interp attribute. When the block following the field is executed, the if element evaluates to true, and the transformation of the conf:pass element is executed.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <catch><conf:fail reason="catch"/></catch> <form> <block> <if cond="one != undefined"> <conf:fail reason="initial check"/> </if> </block> <field name="one"> <conf:speech value="alpha"/> <conf:grammar utterance="alpha" interp="peña"/> </field> <block> <if cond="one=='peña'"><conf:pass/></if> <conf:fail reason="field assignment"/> </block> </form> </vxml> |
The following example demonstrates usage of the conf:key element to generate a structured result from a grammar. The conf:speech element instructs the tester to speak or play the utterance that corresponds to the identifier alpha. Upon recognition of this utterance, the interpreter should assign a reference to an object to the form item variable 'one'. The object should have properties x and y with the respective values 'valX' and 'valY'.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <catch><conf:fail expr="_event"/></catch> <form> <block> <if cond="one != undefined"> <conf:fail reason="initial check"/> </if> </block> <field name="one"> <conf:speech value="alpha"/> <conf:grammar utterance="alpha"> <conf:key name="x" value="valX"/> <conf:key name="y" value="valY"/> </conf:grammar> </field> <block> <if cond="typeof one == 'object' && one.x == 'valX' && one.y == 'valY'"> <conf:pass/> </if> <conf:fail reason="field assignment"/> </block> </form> </vxml> |
The following example demonstrates more complex usage of the conf:key element to generate a structured result from a grammar. The conf:speech element instructs the tester to speak or play the utterance that corresponds to the identifier alpha. Upon recognition of this utterance, the interpreter should assign a reference to an object to the form item variable 'one'. The object should have properties x and y. x is a reference to an object and y is assigned the value 'valY'. The object referred to by x has properties a and b with respective values 'valA' and 'valB'.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <catch><conf:fail expr="_event"/></catch> <form> <block> <if cond="one != undefined"> <conf:fail reason="initial check"/> </if> </block> <field name="one"> <conf:speech value="alpha"/> <conf:grammar utterance="alpha"> <conf:key name="x"> <conf:key name="a" value="valA"/> <conf:key name="b" value="valB"/> </conf:key> <conf:key name="y" value="valY"/> </conf:grammar> </field> <block> <if cond="typeof one != 'object'"> <conf:fail reason="one is not an object"/> <elseif cond="one.y != 'valY'"/> <conf:fail reason="one.y had bad value"/> <elseif cond="typeof one.x != 'object'"/> <conf:fail reason="one.x is not an object"/> <elseif cond="typeof one.x.a != 'valA'"/> <conf:fail reason="one.x.a had bad value"/> <elseif cond="typeof one.x.b != 'valB'"/> <conf:fail reason="one.x.b had bad value"/> <else/> <conf:pass/> </if> </block> </form> </vxml> |
The following example demonstrates the use of the conf:phrase element to build a locale-independent menu.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" xmlns:conf="http://www.w3.org/2002/vxml-conformance"> <catch event="menu-done"> <conf:pass/> </catch> <catch><conf:fail reason="catch"/></catch> <menu> <conf:speech value="alpha"/> <choice event="menu-done"> <conf:phrase utterance="alpha"/> </choice> </menu> </vxml> |
The following is a listing of an XSLT that can be used to transform the previous example into a valid VoiceXML 2.1 document.
<?xml version="1.0"?> <!-- Copyright 1998-2003 W3C (MIT, ERCIM, Keio), All Rights Reserved. See http://www.w3.org/Consortium/Legal/. --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:conf="http://www.w3.org/2002/vxml-conformance" xmlns="http://www.w3.org/2001/vxml" version="1.0"> <xsl:output cdata-section-elements="script"/> <!-- ############################################# --> <!-- D o c u m e n t H e a d e r s --> <!-- ############################################# --> <!-- Copy everything that doesn't match other rules --> <xsl:template match="/ | @* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- strip comments --> <xsl:template match="comment()"/> <!-- ############################################# --> <!-- F i n a l S t a t u s I n d i c a t o r s --> <!-- ############################################# --> <!-- Success criteria --> <xsl:template match="conf:pass"> <prompt>pass</prompt> <exit/> </xsl:template> <!-- Failure criteria --> <xsl:template match="conf:fail"> <prompt>fail</prompt> <!-- the following only comes up in case of failure --> <xsl:if test="@reason != ''"> <log>failure reason: <xsl:value-of select="@reason"/></log> <prompt><xsl:value-of select="@reason"/></prompt> </xsl:if> <xsl:if test="@expr != ''"> <log>failure expression: <value expr="{@expr}"/></log> <prompt><value expr="{@expr}"/></prompt> </xsl:if> <exit/> </xsl:template> <!-- ############################################# --> <!-- I n t e r m e d i a t e R e p o r t s --> <!-- ############################################# --> <!-- Copy everything doesn't match the other rules --> <xsl:template match="conf:comment"> <log> <xsl:apply-templates /> </log> </xsl:template> <!-- ############################################# --> <!-- I n p u t I n d i c a t o r s --> <!-- ############################################# --> <xsl:template match="conf:hangup"> <prompt> Hang up now. </prompt> </xsl:template> <!-- Recite a recording that DOES contain the specified speech command (alpha, bravo, etc) --> <xsl:template match="conf:recording[@value]"> <prompt count="1"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite a sentence containing the word '<xsl:call-template name="emit-name-from-token"> <xsl:with-param name="token" select="@value"/> </xsl:call-template>'. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> <prompt count="2"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite a sentence containing the word '<xsl:call-template name="emit-name-from-token"> <xsl:with-param name="token" select="@value"/> </xsl:call-template>' again. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> <prompt count="3"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite a sentence containing the word '<xsl:call-template name="emit-name-from-token"> <xsl:with-param name="token" select="@value"/> </xsl:call-template>' one more time. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <xsl:template match="conf:recording[@value and @count='0']"> <prompt> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite a sentence containing the word '<xsl:call-template name="emit-name-from-token"> <xsl:with-param name="token" select="@value"/> </xsl:call-template>'. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <xsl:template match="conf:recording[@value and @count > 0]"> <prompt count="{@count}"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite a sentence containing the word '<xsl:call-template name="emit-name-from-token"> <xsl:with-param name="token" select="@value"/> </xsl:call-template>'. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <!-- Recite a recording at least 5 seconds in length that does NOT contain a well-defined speech command (alpha, bravo, etc) --> <!-- Little Miss Muffett sat on her tuffett, eating her curds and whey. Along came a spider ... --> <!-- Jack and Jill went up the hill to fetch a pail of water. Jack fell down and broke his crown ... --> <xsl:template match="conf:recording[@value='nonspeech']"> <prompt count="1"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite your favorite nursery rhyme, for example, 'Little Miss Muffett'. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> <prompt count="2"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite your favorite nursery rhyme again. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> <prompt count="3"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite your favorite nursery rhyme one more time. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <xsl:template match="conf:recording[@value='nonspeech' and @count='0']"> <prompt> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite your favorite nursery rhyme, for example, 'Little Miss Muffett'. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <xsl:template match="conf:recording[@value='nonspeech' and @count > 0]"> <prompt count="{@count}"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Recite your favorite nursery rhyme, for example, 'Little Miss Muffett'. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <!-- ask the user to keep quiet --> <xsl:template match="conf:noinput"> <prompt count="1"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> No input expected. Say nothing <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> <prompt count="2"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> No input expected. Say nothing again <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> <prompt count="3"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> No input expected. Say nothing one more time <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <xsl:template match="conf:noinput[@count = 0]"> <prompt> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> No input expected. Say nothing <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <xsl:template match="conf:noinput[@count > 0]"> <prompt count="{@count}"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> No input expected. Say nothing <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <!-- ask the user to mumble something out of grammar --> <xsl:template match="conf:nomatch"> <prompt count="1"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Say something unrecognizable <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> <prompt count="2"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Say something unrecognizable again <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> <prompt count="3"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Say something unrecognizable one more time <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <xsl:template match="conf:nomatch[@count = 0]"> <prompt> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Say something unrecognizable <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <xsl:template match="conf:nomatch[@count > 0]"> <prompt count="{@count}"> <xsl:if test="@pre_mark != ''"> <mark name="{@pre_mark}"/> </xsl:if> Say something unrecognizable <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="@post_mark != ''"> <mark name="{@post_mark}"/> </xsl:if> </prompt> </xsl:template> <!-- special case a conf:speech inside a nomatch handler --> <xsl:template match="*[name()='nomatch']/conf:speech[@value]" priority="2"> <xsl:call-template name="emit-prompt"> <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param> <xsl:with-param name="pre_mark"><xsl:value-of select="@pre_mark"/></xsl:with-param> <xsl:with-param name="post_mark"><xsl:value-of select="@post_mark"/></xsl:with-param> </xsl:call-template> </xsl:template> <!-- special case a conf:speech inside a noinput handler --> <xsl:template match="*[name()='noinput']/conf:speech[@value]" priority="2"> <xsl:call-template name="emit-prompt"> <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param> <xsl:with-param name="pre_mark"><xsl:value-of select="@pre_mark"/></xsl:with-param> <xsl:with-param name="post_mark"><xsl:value-of select="@post_mark"/></xsl:with-param> </xsl:call-template> </xsl:template> <!-- special case a conf:speech inside a block --> <xsl:template match="*[name()='block']/conf:speech[@value]" priority="2"> <xsl:call-template name="emit-prompt"> <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param> <xsl:with-param name="pre_mark"><xsl:value-of select="@pre_mark"/></xsl:with-param> <xsl:with-param name="post_mark"><xsl:value-of select="@post_mark"/></xsl:with-param> </xsl:call-template> </xsl:template> <xsl:template match="conf:speech[@value]"> <xsl:call-template name="emit-prompt"> <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param> <!-- explicit @count overrides tapering behavior --> <!-- to get a single prompt (no tapering) with no explicit count attribute, set @count="0" --> <xsl:with-param name="count" select="@count"/> <xsl:with-param name="taper"> <xsl:choose> <xsl:when test="@count">0</xsl:when> <xsl:when test="@taper"><xsl:value-of select="@taper"/></xsl:when> <xsl:otherwise>1</xsl:otherwise> </xsl:choose> </xsl:with-param> <xsl:with-param name="pre_mark"><xsl:value-of select="@pre_mark"/></xsl:with-param> <xsl:with-param name="post_mark"><xsl:value-of select="@post_mark"/></xsl:with-param> </xsl:call-template> </xsl:template> <xsl:template match="*[name()='nomatch']/conf:dtmf[@value]" priority="2"> <xsl:call-template name="emit-dtmf"> <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param> <xsl:with-param name="count" select="0"/> <xsl:with-param name="pre_mark" select="@pre_mark"/> <xsl:with-param name="post_mark" select="@post_mark"/> </xsl:call-template> </xsl:template> <xsl:template match="*[name()='noinput']/conf:dtmf[@value]" priority="2"> <xsl:call-template name="emit-dtmf"> <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param> <xsl:with-param name="count" select="0"/> <xsl:with-param name="pre_mark" select="@pre_mark"/> <xsl:with-param name="post_mark" select="@post_mark"/> </xsl:call-template> </xsl:template> <xsl:template match="*[name()='block']/conf:dtmf[@value]" priority="2"> <xsl:call-template name="emit-dtmf"> <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param> <xsl:with-param name="count" select="0"/> <xsl:with-param name="pre_mark" select="@pre_mark"/> <xsl:with-param name="post_mark" select="@post_mark"/> </xsl:call-template> </xsl:template> <xsl:template match="conf:dtmf[@value]"> <xsl:call-template name="emit-dtmf"> <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param> <xsl:with-param name="count" select="@count"/> <xsl:with-param name="pre_mark" select="@pre_mark"/> <xsl:with-param name="post_mark" select="@post_mark"/> </xsl:call-template> </xsl:template> <!-- ############################################# --> <!-- G r a m m a r s --> <!-- ############################################# --> <xsl:template match="conf:grammar[@interp and @utterance]" priority="2"> <xsl:variable name="rootname">CityName<xsl:value-of select="generate-id()"/></xsl:variable> <grammar type="application/srgs+xml" root="{$rootname}" version="1.0"> <rule id="{$rootname}" scope="public"> <one-of> <item> <xsl:call-template name="emit-utterance"> <xsl:with-param name="utterance"><xsl:value-of select="@utterance"/></xsl:with-param> </xsl:call-template> <tag>'<xsl:value-of select="@interp"/>'</tag> </item> </one-of> </rule> </grammar> </xsl:template> <!-- an utterance without an explicit interpretation --> <xsl:template match="conf:grammar[@utterance]" priority="1"> <xsl:variable name="rootname">CityName<xsl:value-of select="generate-id()"/></xsl:variable> <grammar type="application/srgs+xml" root="{$rootname}" version="1.0"> <rule id="{$rootname}" scope="public"> <one-of> <item> <xsl:call-template name="emit-utterance"> <xsl:with-param name="utterance"><xsl:value-of select="@utterance"/></xsl:with-param> </xsl:call-template> </item> </one-of> </rule> </grammar> </xsl:template> <xsl:template match="conf:grammar[@utterance and descendant::conf:key]" priority="2"> <xsl:variable name="rootname">CityName<xsl:value-of select="generate-id()"/></xsl:variable> <grammar type="application/srgs+xml" root="{$rootname}" version="1.0"> <rule id="{$rootname}" scope="public"> <one-of> <item> <xsl:call-template name="emit-utterance"> <xsl:with-param name="utterance"><xsl:value-of select="@utterance"/></xsl:with-param> </xsl:call-template> <tag> <xsl:apply-templates select="conf:key"/> </tag> </item> </one-of> </rule> </grammar> </xsl:template> <xsl:template match="conf:key[@value]" priority="2"> <xsl:param name="path"/> <xsl:choose> <xsl:when test="$path = ''"> <xsl:text>var </xsl:text> </xsl:when> <xsl:when test="$path != ''"> <xsl:value-of select="$path"/><xsl:text>.</xsl:text> </xsl:when> </xsl:choose> <xsl:value-of select="@name"/> <xsl:text>='</xsl:text> <xsl:value-of select="@value"/> <xsl:text>'; </xsl:text> </xsl:template> <xsl:template match="conf:key" priority="1"> <xsl:param name="path"/> <xsl:choose> <xsl:when test="$path = ''"> <xsl:text>var </xsl:text> </xsl:when> <xsl:when test="$path != ''"> <xsl:value-of select="$path"/><xsl:text>.</xsl:text> </xsl:when> </xsl:choose> <xsl:value-of select="@name"/><xsl:text>=new Object(); </xsl:text> <xsl:apply-templates select="conf:key"> <xsl:with-param name="path"> <xsl:if test="$path != ''"> <xsl:value-of select="$path"/><xsl:text>.</xsl:text> </xsl:if> <xsl:value-of select="@name"/> </xsl:with-param> </xsl:apply-templates> </xsl:template> <xsl:template match="conf:phrase[@utterance]"> <xsl:call-template name="emit-name-from-token"> <xsl:with-param name="token" select="@utterance"/> </xsl:call-template> </xsl:template> <!-- ############################################# --> <!-- H e l p e r T e m p l a t e s --> <!-- ############################################# --> <!-- for use in building grammars --> <xsl:template name="emit-utterance"> <xsl:param name="utterance"/> <xsl:choose> <xsl:when test="$utterance='alpha'">chicago</xsl:when> <xsl:when test="$utterance='bravo'">san francisco</xsl:when> <xsl:when test="$utterance='charlie'">new york</xsl:when> <xsl:when test="$utterance='delta'">london</xsl:when> <xsl:when test="$utterance='echo'">tokyo</xsl:when> <xsl:when test="$utterance='foxtrot'">truth or consequences</xsl:when> <xsl:when test="$utterance='golf'">hackensack</xsl:when> <xsl:when test="$utterance='hotel'">standardsville</xsl:when> <xsl:when test="$utterance='help'">help</xsl:when> <xsl:when test="$utterance='cancel'">cancel</xsl:when> <xsl:when test="$utterance='exit'">exit</xsl:when> <xsl:when test="$utterance='yes'">yes</xsl:when> </xsl:choose> </xsl:template> <!-- Truth or Consequences is a real city in New Mexico, US. Hackensack is located in New Jersey, US very close to the site of the Sept. 2001 face-to-face. And finally, yes, there really is a Standardsville. It's in Greene County, Virginia, US. --> <!-- for use in building prompts --> <xsl:template name="emit-name-from-token"> <xsl:param name="token"/> <xsl:choose> <xsl:when test="$token = 'alpha'">Chicago</xsl:when> <xsl:when test="$token = 'bravo'">San Francisco</xsl:when> <xsl:when test="$token = 'charlie'">New York</xsl:when> <xsl:when test="$token = 'delta'">London</xsl:when> <xsl:when test="$token = 'echo'">Tokyo</xsl:when> <xsl:when test="$token = 'foxtrot'">Truth or Consequences</xsl:when> <xsl:when test="$token = 'golf'">Hackensack</xsl:when> <xsl:when test="$token = 'hotel'">Standardsville</xsl:when> <xsl:when test="$token = 'help'">help</xsl:when> <xsl:when test="$token = 'cancel'">cancel</xsl:when> <xsl:when test="$token = 'exit'">exit</xsl:when> <xsl:when test="$token = 'yes'">yes</xsl:when> </xsl:choose> </xsl:template> <xsl:template name="emit-prompt"> <xsl:param name="value"/> <xsl:param name="count" select="0"/> <xsl:param name="pre_mark"/> <xsl:param name="post_mark"/> <xsl:variable name="text_mapping"> <xsl:call-template name="emit-name-from-token"> <xsl:with-param name="token" select="$value"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$count >= 0"> <prompt><xsl:if test="$count > 0"><xsl:attribute name="count"><xsl:value-of select="$count"/></xsl:attribute></xsl:if> <xsl:if test="$pre_mark != ''"> <mark name="{$pre_mark}"/> </xsl:if> Say '<xsl:value-of select="$text_mapping"/>'. <xsl:if test="$post_mark != ''"> <mark name="{$post_mark}"/> </xsl:if> </prompt> </xsl:when> <xsl:otherwise> <!-- taper --> <prompt count="1"> <xsl:if test="$pre_mark != ''"> <mark name="{$pre_mark}"/> </xsl:if> Say '<xsl:value-of select="$text_mapping"/>'. <xsl:if test="$post_mark != ''"> <mark name="{$post_mark}"/> </xsl:if> </prompt> <prompt count="2"> <xsl:if test="$pre_mark != ''"> <mark name="{$pre_mark}"/> </xsl:if> Say '<xsl:value-of select="$text_mapping"/>' again. <xsl:if test="$post_mark != ''"> <mark name="{$post_mark}"/> </xsl:if> </prompt> <prompt count="3"> <xsl:if test="$pre_mark != ''"> <mark name="{$pre_mark}"/> </xsl:if> Say '<xsl:value-of select="$text_mapping"/>' one more time. <xsl:if test="$post_mark != ''"> <mark name="{$post_mark}"/> </xsl:if> </prompt> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="emit-dtmf"> <xsl:param name="value"/> <xsl:param name="count"/> <xsl:param name="pre_mark"/> <xsl:param name="post_mark"/> <xsl:choose> <xsl:when test="$count >= 0"> <prompt><xsl:if test="$count > 0"><xsl:attribute name="count"><xsl:value-of select="$count"/></xsl:attribute></xsl:if> <xsl:if test="$pre_mark != ''"> <mark name="{$pre_mark}"/> </xsl:if> Press '<xsl:value-of select="$value"/>'. <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. <xsl:if test="$post_mark != ''"> <mark name="{$post_mark}"/> </xsl:if> </prompt> </xsl:when> <xsl:otherwise> <prompt count="1"> <xsl:if test="$pre_mark != ''"> <mark name="{$pre_mark}"/> </xsl:if> Press '<xsl:value-of select="@value"/>'. <xsl:if test="$post_mark != ''"> <mark name="{$post_mark}"/> </xsl:if> </prompt> <prompt count="2"> <xsl:if test="$pre_mark != ''"> <mark name="{$pre_mark}"/> </xsl:if> Press '<xsl:value-of select="@value"/>' again. <xsl:if test="$post_mark != ''"> <mark name="{$post_mark}"/> </xsl:if> </prompt> <prompt count="3"> <xsl:if test="$pre_mark != ''"> <mark name="{$pre_mark}"/> </xsl:if> Press '<xsl:value-of select="@value"/>' one more time. <xsl:if test="$post_mark != ''"> <mark name="{$post_mark}"/> </xsl:if> </prompt> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> |
The following is a listing of the output of Example 9 when transformed through the provided XSLT.
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <catch> <log>failure expression: <value expr="_event" /> </log> <audio>fail</audio> <exit /> </catch> <form> <block> <if cond="one != undefined"> <log>failure reason: initial check</log> <audio>fail</audio> <exit /> </if> </block> <field name="one"> <prompt count="1">Say 'Chicago'.</prompt> <prompt count="2">Say 'Chicago' again.</prompt> <prompt count="3">Say 'Chicago' one more time.</prompt> <grammar type="application/grammar+xml" root="CityName"> <rule id="CityName" scope="public"> <one-of> <item>Chicago</item> </one-of> </rule> </grammar> </field> <block> <if cond="one != undefined"> <audio>pass</audio> <exit /> </if> <log>failure reason: field assignment</log> <audio>fail</audio> <exit /> </block> </form> </vxml>
The VoiceXML 2.1 Implementation Report contains assertions that require server-side support to verify HTTP headers and submitted values. To allow disparate test environments to use different server-side technologies, tests describe the server-side processing using a syntax independent of any particular server-side framework.
This appendix describes a server-agnostic XML API that can be transformed easily using XSLT into any server-side framework. Reference Perl and JSP XSLT templates are provided as examples.
The API supports the following:
The XML API does not require the following:
A document conforming to this specification, heretofore referred to as an "IRCGI document", indicates the checks to be made on an HTTP request. Supported checks include:
Checks may be nested. The result of the checks determines the next document to be executed. The next document must continue the test and must determine the success or failure of the test. Once the IRCGI document determines the next document, a response is sent, and the IRCGI document terminates.
An IRCGI document consists of the following elements. The DTD can be found below.
name | Requird. The name of the header. If only the name attribute is specified, the CGI must execute the if-header content only if the named header is present in the request. |
---|---|
value | Optional. The expected value of the header. If this attribute is specified, the CGI must execute the if-header content only if the named header is present in the request and its value matches that of the value attribute. This attribute and the starts-with attribute are mutually exclusive. |
starts-with | Optional. The expected value with which the header begins. If this attribute is specified, the CGI must execute the if-header content only if the named header is present in the request and its value begins with the value of the starts-with attribute. This attribute and the value attribute are mutually exclusive. |
ignore-case | Optional. The value match is case-sensitive if the ignore-case attribute is false, the default. The match is not case-sensitive if the attribute is true. |
type | Required. The HTTP method. Typically 'get' or 'post'. |
---|
name | Required. The parameter's name.
If only the name attribute is specified, the CGI
must execute the if-parameter content only if the
named parameter is present in the request. This attribute and the starts-with attribute are mutually exclusive. |
---|---|
value | Optional. The parameter's expected value. If this attribute is specified, the CGI must execute the if-parameter content only if the named parameter is present in the request and its value matches that of the value attribute. |
starts-with | Optional. The expected value with which the parameter begins. If this attribute is specified, the CGI must execute the if-parameter content only if the named parameter is present in the request and its value begins with the value of the starts-with attribute. This attribute and the value attribute are mutually exclusive. |
ignore-case | Optional. The value match is case-sensitive if the ignore-case attribute is false, the default. The match is not case-sensitive if the attribute is true. |
ref | Required. The id of a <params> element containing the set of expected CGI parameters. |
---|
id | Required. A unique identifier referenced by an <if-all-params> element. |
---|
name | Required. The name of the CGI request parameter. |
---|---|
value | Required. The value of the CGI request parameter. |
name | Required. The name of the parameter containing the uploaded bits. If only the name attribute is specified, the CGI must execute the <if-upload> content only if the named upload is present. |
---|---|
size | Optional. The expected size of the upload. If this attribute is specified, the CGI must execute the <if-parameter> content only if the named upload is present in the request and its size matches that of the value of the size attribute. The value of this attribute can be a static numeric value or a CGI parameter name. If a name is specified, the size of the file upload is compared to the value of the specified CGI parameter. The value of the CGI parameter must resolve to a numeric value. The size value should be specified in bytes. |
code | Optional. The HTTP response code. If the code attribute is specified, its value must be used as the HTTP response status code. The default is 200 (Ok). |
---|---|
dest | Optional. The URL of the next document. If this attribute is specified, its value must be used by the response to designate the next document to be visited. |
include | Optional. true or false
If this attribute is true, the document specified by the dest attribute is returned
as the result document.
If this attribute is false, the default,
the CGI returns a generated VoiceXML document that contains a
goto to the document specified by dest.
The document generated when include is false
may contain the content of comment elements that
were encountered.
Only files that are in the directory immediately above the cgi-bin directory (see Usage below) may be included. Attempts to include other files result in an HTTP 403 (Forbidden) response status code. |
sleep | Optional. An interval for the CGI to sleep before returning its response to the client. |
expires | Optional. Sets an Expires HTTP response header to a date calculated by adding the value of the expires attribute to the current time. The value of this attribute should be a positive or negative integer in seconds. |
The following DTD succintly declares the IRCGI API markup elements, their attributes, and the legal values for those attributes if applicable.
<!ENTITY % ir-checks "if-header | if-method | if-parameter | if-upload | if-all-params" > <!ELEMENT ircgi (params | comment | %ir-checks; | next)*> <!ELEMENT comment (#PCDATA) > <!ELEMENT if-parameter (comment | %ir-checks; | next)* > <!ATTLIST if-parameter name CDATA #REQUIRED value CDATA #IMPLIED starts-with CDATA #IMPLIED ignore-case (true|false) "false" > <!ELEMENT if-all-params (comment | %ir-checks; | next)* > <!ATTLIST if-all-params ref IDREF #REQUIRED> <!ELEMENT params (param+)> <!ATTLIST params id ID #REQUIRED> <!ELEMENT param EMPTY> <!ATTLIST param name CDATA #REQUIRED value CDATA #REQUIRED > <!ELEMENT if-upload (comment | %ir-checks; | next)* > <!ATTLIST if-upload name CDATA #REQUIRED size CDATA #IMPLIED> <!ELEMENT if-header (comment | %ir-checks; | next)* > <!ATTLIST if-header name CDATA #REQUIRED value CDATA #IMPLIED starts-with CDATA #IMPLIED ignore-case (true|false) "false" > <!ELEMENT if-method (comment | %ir-checks; | next)* > <!ATTLIST if-method type (get|post) "get" > <!ELEMENT next EMPTY> <!ATTLIST next code CDATA "200" dest CDATA #IMPLIED include (true|false) "false" sleep CDATA #IMPLIED expires CDATA #IMPLIED> |
The following examples illustrate the use of the IRCGI API elements. The examples validate the XSLT used to generate valid CGI from the test source. These tests should all pass before the XSLT is applied to the main body of tests.
If the HTTP method used is "POST", the next document is "pass.vxml". Otherwise, the next document is "fail.vxml". The match on method name is case-insensitive.
<?xml version="1.0"?> <!-- Check if request method was 'POST'. --> <ircgi> <if-method value="post"> <next dest="pass.vxml" /> </if-method> <next dest="fail.vxml" /> </ircgi> |
If the parameter "p1" was submitted, the next document is "pass.vxml". Otherwise, the next document is "fail.vxml". The value of "p1" does not matter because the value attribute was specified.
<?xml version="1.0"?> <!-- Check if parameter p1 is present. --> <ircgi> <if-parameter name="p1"> <next dest="../pass.vxml" /> </if-parameter> <next dest="../fail.vxml" /> </ircgi> |
If parameter "p1" has the value "42" and if parameter "p2" has the value "quiche", the next document is "pass.vxml". Otherwise, the next document is "fail.vxml".
This document includes comment elements whose content may be included in a log element in the response document to aid in debugging.
<?xml version="1.0"?> <!-- Check if p1 == 42 and p2 == 'quiche'. --> <ircgi> <if-parameter name="p1" value="42"> <comment>p1 is 42.</comment> <if-parameter name="p2" value="quiche"> <comment> p2 is quiche.</comment> <next dest="../pass.vxml" /> </if-parameter> <comment> p2 is not quiche.</comment> <next dest="../fail.vxml" /> </if-parameter> <comment>p1 is not 42.</comment> <next dest="../fail.vxml" /> </ircgi> |
If the "User-Agent" HTTP header is present but is empty, the next document is "fail.vxml". If the "User-Agent" header is present and not empty, the next document is "pass.vxml". If the "User-Agent" header is not present, the next document is "fail.vxml".
<?xml version="1.0" ?> <ircgi> <if-header name="User-Agent"> <if-header name="User-Agent" value="" > <comment> User-Agent header present, but empty. </comment> <next dest="../fail.vxml" /> </if-header> <comment> User-Agent header was supplied and not empty. </comment> <next dest="../pass.vxml" /> </if-header> <comment> User-Agent header was not supplied. </comment> <next dest="../fail.vxml" /> </ircgi> |
If the parameter "p1" was submitted, the next document is "pass.vxml". Otherwise, the HTTP response code is set to "404".
<?xml version="1.0"?> <!-- Send 404 if p1 not present --> <ircgi> <if-parameter name="p1"> <next dest="../pass.vxml" /> </if-parameter> <next code="404" /> </ircgi> |
If the parameter "p1" was "include", then parameter "p2" will be checked. If parameter "p2" was "pass", then the response will be the content of the file "pass.vxml" because the next element's include attribute is true. If parameter "p2" is not "pass", the response will be the content of the file "fail.vxml" because the next element's include attribute is false.
If parameter "p1" was not "include", the response document will be generated by the ircgi and include a goto to "fail.vxml" because the include attribute was false, by default. The generated document may contain a log element containing the content of the IRCGI document's comment element.
<?xml version="1.0"?> <!-- If p1 == 'include', include 'pass.vxml' if p2 == 'pass'. --> <ircgi> <if-parameter name="p1" value="include"> <if-parameter name="p2" value="pass"> <next dest="../pass.vxml" include="true"/> </if-parameter> <next dest="../fail.vxml" include="true" /> </if-parameter> <comment>p1 is not 'include'.</comment> <next dest="../fail.vxml" /> </ircgi> |
This example navigates to a document "fail.vxml" after sleeping for five seconds.
<?xml version="1.0"?> <ircgi> <next dest="../fail.vxml" sleep="5" /> </ircgi> |
This example checks the Content-Type header for a partial match on "multipart/form-data".
The starts-with attribute is used instead of the value attribute since the boundary portion of the value cannot be controlled or predetermined. An example of a Content-Type header value when the encoding is set to "multipart/form-data" follows:
multipart/form-data; boundary=---------------------------7d39216110392
<ircgi> <if-header name="Content-Type"> <if-header name="Content-Type" starts-with="multipart/form-data" ignore-case="true"> <next dest="../pass.vxml" /> </if-header> <comment> Content-Type header was not multipart/form-data . </comment> <next dest="../fail.vxml" /> </if-header> <next dest="../fail.vxml" /> </ircgi> |
The following example includes a .js document. The .js document includes a single statement that sets a variable to the value of the special variable __EPOCH__. At runtime, the CGI detects the special variable and replaces it with the server-calculated number of seconds since 'the epoch'. This feature is useful in testing to verify the caching behavior of a VoiceXML interpreter by making multiple IRCGI requests and comparing the values of __EPOCH__. If the values differ, the document was fetched from the Web. If not, the document was retrieved from the browser's local cache.
The IRCGI follows:
<ircgi> <next sleep="2" dest="../epoch.js" include="true"/> </ircgi> |
The .js document follows:
var epoch = __EPOCH__; |
This example returns the document "cache_me.vxml" along with an Expires header set to 60 seconds after the CGI is requested.
<ircgi> <next dest="../cache_me.vxml" include="true" expires="60"/> </ircgi> |
If the CGI parameter named "recording" is a valid file upload and its size is equal to the value of the CGI parameter 'recsize' the next document is "pass.vxml". Otherwise, the next document is "fail.vxml".
<?xml version="1.0"?> <!-- Check if upload was of a specified size. --> <ircgi> <!-- @name represents the upload parameter name @size can refer to a static numeric value or, as shown here, to a CGI parameter name --> <if-upload name="recording" size="recsize"> <next dest="../pass.vxml" /> </if-upload> <next dest="../fail.vxml" /> </ircgi> |
The following IRCGI expects precisely 3 CGI parameters the names and values of which are designated by the contents of the <params> element referenced by the <if-all-params> element.
<?xml version="1.0"?> <!-- Check if submitted parameters are in the set plist1 --> <ircgi> <params id="plist1"> <param name="p1" value="42"/> <param name="p2.dinner.main" value="quiche"/> <param name="p3" value="a 1 c"/> </params> <if-all-params ref="plist1"> <next dest="../pass.vxml" /> </if-all-params> <next dest="../fail.vxml" /> </ircgi> |
For security purposes, transformed IRCGI documents are deployed to an isolated directory, named "cgi-bin" under the assertion directory. Other, non-IRCGI, server-side programs that may be needed are also located in the "cgi-bin" directory.
The source IRCGI documents must be transformed into files that are executable in the test environment, such as Perl or JSP files. The output files must reside in the "cgi-bin" directory and must have the ".ircgi" file extension. The file extension must be ".ircgi" because this is how other test documents (.txml) will refer to them. The .txml to .vxml transformation process cannot automatically change ".ircgi" ".pl" or ".jsp" because some tests may use ECMAScript expressions to build the reference to the ".ircgi" document.
Two sample XSL stylesheets are provided.
The following XSLT document can be used to transform an IRCGI document to JSP:
<?xml version="1.0"?> <!-- Copyright 1998-2005 W3C (MIT, ERCIM, Keio), All Rights Reserved. See http://www.w3.org/Consortium/Legal/. --> <!-- Transforms an ircgi test file into a Java Server Page.--> <!-- NOTE: This JSP requires the com.oreilly.servlet package available at http://www.servlets.com/cos/ The source code, object code, and documentation in the com.oreilly.servlet package (http://www.servlets.com/cos/) is copyright and owned by Jason Hunter. --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/" > <xsl:apply-templates /> </xsl:template> <xsl:template match="ircgi"> <xsl:call-template name="header" /> <xsl:call-template name="declarations" /> <xsl:call-template name="determineResult" /> </xsl:template> <!-- Official contentType is 'application/voicexml+xml'. Change contentType to 'text/xml' to view generated JSP in IE. NOTE: The "header" template content below must be on a single line so that whitespace is not introduced at the beginning of the resulting XML document. XML parsers will complain. Line breaks are included here for readability in the documentation. --> <xsl:template name="header" ><%@ page language="java" contentType="text/xml" %> <%@ page import="java.io.*" %> <%@ page import="java.net.*" %> <%@ page import="java.util.*" %> <%@ page import="com.oreilly.servlet.multipart.*" %> </xsl:template> <!-- Define a Result class to hold the destination, comments, and HTTP status code that will be set by 'determineResult' method. --> <xsl:template name="declarations"><%! // Handles server side includes so they can be parsed private class JSPIncluder { void readInput(HttpServletRequest request, String strIncludePath) throws JspException { URLConnection conn; // Get URL StringBuffer strUrl = request.getRequestURL(); String strUri = strUrl.toString(); int nFindSlash = strUri.lastIndexOf("/"); if (nFindSlash != -1) { strUri = strUri.substring(0, nFindSlash + 1); } strUri += strIncludePath; // Open connection try { conn = (new URL(strUri)).openConnection(); conn.setDoInput(true); conn.setDoOutput(false); conn.connect(); } catch (Exception e) { throw new JspException(e.toString()); } // Read in contents try { BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); StringBuffer buff = new StringBuffer(); char[] chars = new char[2048]; int nLen; while ((nLen = in.read(chars, 0, chars.length)) >= 0) { buff.append(chars, 0, nLen); } m_strBuffer = buff.toString(); in.close(); } catch (Exception e) { throw new JspException(e.toString()); } } boolean replace(String strFind, String strReplace) { boolean bFound = false; if (m_strBuffer != null && m_strBuffer.length() > 0) { int a = 0; int b = 0; while (true) { a = m_strBuffer.indexOf(strFind, b); if (a != -1) { m_strBuffer = m_strBuffer.substring(0, a) + strReplace + m_strBuffer.substring(a + strFind.length()); b = a + strReplace.length(); bFound = true; } else { break; } } } return bFound; } void doOutput(PageContext context) throws JspException { JspWriter out = context.getOut(); try { out.print(m_strBuffer.toString()); } catch (Exception e) { throw new JspException(e.toString()); } } private String m_strBuffer; } // Handles multipart/form-data private class MultiPartHandler { HttpServletRequest request; public MultiPartHandler(HttpServletRequest req) { request = req; } public boolean find(String strFind, int nOfSize) throws JspException { MultipartParser parser; Part part; String strName; if((request.getContentType() != null)&&(request.getContentType().startsWith("multipart/form-data"))) { try { parser = new MultipartParser(request, request.getContentLength()); while ((part = parser.readNextPart()) != null) { strName = part.getName(); if(strName.equals(strFind)) { if (nOfSize == -1) { return true; } else { if (part.isFile()) { InputStream stream = ((FilePart)part).getInputStream(); if (getSizeOfStream(stream) == nOfSize) { return true; } } } } } } catch (Exception e) { throw new JspException(e.toString()); } } return false; } private long getSizeOfStream(InputStream stream) { if (null == stream) return 0; int nRead = 0; int nSize = 0; byte[] temp = new byte[1024]; try { while ((nRead = stream.read(temp)) != -1) { nSize += nRead; } } catch (IOException e) {} return nSize; } } private class Result { String dest; long sleep = 0; boolean expiresHeaderSet = false; long expires = 0; boolean include = false; StringBuffer comments = new StringBuffer(); int statusCode = 200; } private final String NL = System.getProperty("line.separator"); private void determineResult(HttpServletRequest request, Result result, MultiPartHandler multipart) throws JspException { <xsl:apply-templates /> } %></xsl:template> <!-- Create Result object and call 'determineResult' to set its fields. Return VoiceXML document only if HTTP response status code is 200. Otherwise, return just the status code. --> <xsl:template name="determineResult" ><% Result myResult = new Result(); MultiPartHandler myMultiPart = new MultiPartHandler(request); determineResult(request, myResult, myMultiPart); response.setStatus(myResult.statusCode); if (myResult.sleep > 0) { try { Thread.sleep(myResult.sleep * 1000); } catch (InterruptedException e) { throw new JspException(e.toString()); } } if (myResult.expiresHeaderSet) { Date now = new Date(); long nMillis = now.getTime(); response.setDateHeader("Expires", nMillis + myResult.expires*1000); } if (myResult.include) { Date now = new Date(); long nMillis = now.getTime(); String strEpoch = String.valueOf(nMillis); JSPIncluder includer = new JSPIncluder(); includer.readInput(request, myResult.dest); includer.replace("__EPOCH__", strEpoch); includer.doOutput(pageContext); } else {%><xsl:call-template name="vxml" /><%}%> </xsl:template> <xsl:template match="if-parameter" > if (<xsl:call-template name="genIfExpr"> <xsl:with-param name="type" select="'Parameter'" /> </xsl:call-template>) { <xsl:apply-templates /> } </xsl:template> <xsl:template match="if-header" > if (<xsl:call-template name="genIfExpr"> <xsl:with-param name="type" select="'Header'" /> </xsl:call-template>) { <xsl:apply-templates /> } </xsl:template> <xsl:template match="if-all-params"> <xsl:choose> <xsl:when test="/ircgi/params[@id=current()/@ref][not(param)]"> if (request.getParameterMap().isEmpty()) { <xsl:apply-templates /> } </xsl:when> <xsl:otherwise> if (<xsl:for-each select="/ircgi/params[@id=current()/@ref]/param"> <xsl:call-template name="genIfExpr"> <xsl:with-param name="type" select="'Parameter'" /> </xsl:call-template> <xsl:if test="position() != last()">&&</xsl:if> </xsl:for-each>) { <xsl:apply-templates /> } </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="if-upload" > int nSize = -1; <xsl:if test="@size"> if (null != request.getParameter("<xsl:value-of select='@size'/>")) { try { nSize = Integer.parseInt(request.getParameter("<xsl:value-of select='@size'/>")); } catch (NumberFormatException e) { } } else { try { nSize = Integer.parseInt("<xsl:value-of select='@size'/>"); } catch (NumberFormatException e) { } } </xsl:if> if (multipart.find("<xsl:value-of select="@name"/>", nSize)) { <xsl:apply-templates /> } </xsl:template> <!-- Generate an expression that determines when the condition of an if-parameter / if-header element is true. The 'type' parameter determines the HttpServletRequest method to use to get the value to be checked. --> <xsl:template name="genIfExpr" > <xsl:param name="type" /> <xsl:param name="size" /> <xsl:variable name="method"> <xsl:choose> <xsl:when test="@ignore-case = 'true'" >equalsIgnoreCase</xsl:when> <xsl:otherwise>equals</xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="@value"> request.get<xsl:value-of select="$type"/> ("<xsl:value-of select="@name"/>") != null && request.get<xsl:value-of select="$type"/> ("<xsl:value-of select="@name"/>").<xsl:value-of select="$method"/> ("<xsl:value-of select="@value" />") </xsl:when> <xsl:when test="@starts-with"> request.get<xsl:value-of select="$type"/> ("<xsl:value-of select="@name"/>") != null && request.get<xsl:value-of select="$type"/> ("<xsl:value-of select="@name"/>").startsWith("<xsl:value-of select="@starts-with"/>") </xsl:when> <xsl:otherwise> request.get<xsl:value-of select="$type"/>("<xsl:value-of select="@name"/>") != null || multipart.find("<xsl:value-of select="@name"/>", -1) </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="if-method" > if (request.getMethod().equalsIgnoreCase("<xsl:value-of select="@type" />")) { <xsl:apply-templates /> } </xsl:template> <!-- Disarm double quotes and newline characters from comments, then add to result's comment buffer for use later in 'log' element. --> <xsl:template match="comment" > result.comments.append ("<xsl:value-of select="translate(., '"
', ' ')" />".trim()); result.comments.append(NL); </xsl:template> <xsl:template match="next" > <xsl:if test="@code" > result.statusCode = <xsl:value-of select="@code" />; </xsl:if> <xsl:if test="@dest" > result.dest = "<xsl:value-of select="@dest" />"; </xsl:if> <xsl:if test="@include = 'true'"> result.include = true; </xsl:if> <xsl:if test="@sleep"> result.sleep = <xsl:value-of select="@sleep" />; </xsl:if> <xsl:if test="@expires"> result.expiresHeaderSet = true; result.expires = <xsl:value-of select="@expires" />; </xsl:if> return; </xsl:template> <!-- Generate VoiceXML document that does a 'goto' to the document indicated in myResult. If comment buffer is not empty, include a 'log' element to aid in debugging. --> <xsl:template name="vxml" ><![CDATA[<?xml version="1.0" ?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <form> <block><% String comments = myResult.comments.toString(); if (comments.length()>0) {%> <log>]]> <xsl:text disable-output-escaping="yes"> <![CDATA[<%= comments %>]]> </xsl:text><![CDATA[ </log><%}%> <goto next="<%= myResult.dest %>"/> </block> </form> </vxml> ]]> </xsl:template> </xsl:stylesheet> |
The following XSLT document can be used to transform an IRCGI document to Perl:
<?xml version="1.0"?> <!-- Copyright 1998-2005 W3C (MIT, ERCIM, Keio), All Rights Reserved. See http://www.w3.org/Consortium/Legal/. --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/" > <xsl:apply-templates /> </xsl:template> <!-- root document element --> <xsl:template match="ircgi"> <xsl:call-template name="header" /> <xsl:apply-templates /> <xsl:call-template name="footer" /> </xsl:template> <!-- handle CGI parameter checks --> <xsl:template match="if-parameter" > $val = param("<xsl:value-of select="@name"/>"); <xsl:call-template name="check-value"> <xsl:with-param name="value" select="@value"/> <xsl:with-param name="starts-with" select="@starts-with"/> <xsl:with-param name="ignore-case" select="@ignore-case"/> </xsl:call-template> </xsl:template> <xsl:template match="if-all-params[@ref]" > if (CheckAllParams({<xsl:for-each select="/ircgi/params[@id=current()/@ref]/param">'<xsl:value-of select="@name"/>' => '<xsl:value-of select="@value"/>'<xsl:if test="position() != last()">,</xsl:if></xsl:for-each>}, \@comments)) { <xsl:apply-templates/> } </xsl:template> <!-- if-upload - perform checks on a file upload @name - does an upload exist with the given name @size - (optional) check its size. if the value is a number, compare directly. if it starts with alpha or '_', see if there's a param with that name, and compare against the value @type - (optional) verify that the uploaded data is the specified type <if-upload name="recording" size="recsize"> <next dest="../pass.vxml"/> </if-upload> --> <xsl:template match="if-upload"> if (CheckUpload('<xsl:value-of select="@name"/>', <xsl:choose><xsl:when test="@size">'<xsl:value-of select="@size"/>'</xsl:when> <xsl:otherwise>undef</xsl:otherwise></xsl:choose>, \@comments)) { <xsl:apply-templates/> } </xsl:template> <!-- handle HTTP Request header checks --> <xsl:template match="if-header"> $val = $ENV{<xsl:call-template name="map-header"><xsl:with-param name="header" select="@name"/></xsl:call-template>}; <xsl:call-template name="check-value"> <xsl:with-param name="value" select="@value"/> <xsl:with-param name="starts-with" select="@starts-with"/> <xsl:with-param name="ignore-case" select="@ignore-case"/> </xsl:call-template> </xsl:template> <!-- in Perl, the Request-Method is just another HTTP Request header --> <xsl:template match="if-method"> $val = $ENV{REQUEST_METHOD}; <xsl:call-template name="check-value"> <xsl:with-param name="value"> <xsl:choose> <xsl:when test="@type"><xsl:value-of select="@type"/></xsl:when> <xsl:otherwise>get</xsl:otherwise> <!-- default http request method --> </xsl:choose> </xsl:with-param> <xsl:with-param name="ignore-case" select="'true'"/> </xsl:call-template> </xsl:template> <!-- strip comment elements --> <xsl:template match="comment"> push @comments, qq {<xsl:value-of select="."/>}; </xsl:template> <!-- handle next elements --> <xsl:template match="next"> return { <xsl:choose> <xsl:when test="not(@code) and not(@dest)"> status => "200", </xsl:when> <xsl:otherwise> <xsl:if test="@dest"> next => "<xsl:value-of select="@dest" />", <xsl:if test="@include = 'true'"> include => 1, </xsl:if> </xsl:if> <xsl:if test="@code"> status => "<xsl:value-of select="@code" />", </xsl:if> </xsl:otherwise> </xsl:choose> <xsl:if test="@sleep"> sleep => "<xsl:value-of select="@sleep"/>", </xsl:if> <xsl:if test="@expires"> expires => int(<xsl:value-of select="@expires"/>), </xsl:if> comments => \@comments}; </xsl:template> <!-- check the value, if any, and continue processing child elements --> <xsl:template name="check-value"> <xsl:param name="value"/> <xsl:param name="starts-with"/> <xsl:param name="ignore-case"/> <xsl:param name="equals-upload-size"/> <xsl:choose> <xsl:when test="$starts-with"> my $starts = '<xsl:value-of select="$starts-with"/>'; if (defined($val) && ($val =~ /^$starts/<xsl:if test="$ignore-case='true'">i</xsl:if>)) { <xsl:apply-templates/> } </xsl:when> <xsl:when test="$value"> <!-- XSLT 1.0 11.2: empty attr == missing attr --> <xsl:choose> <xsl:when test="$value=''"> if (defined($val) && ($val =~ /^\s*$/)) { <xsl:apply-templates/> } </xsl:when> <xsl:otherwise> my $match = '<xsl:value-of select="$value"/>'; if (defined($val) && ($val =~ /^$match$/<xsl:if test="$ignore-case='true'">i</xsl:if>)) { <xsl:apply-templates/> } </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> if (defined($val)) { <xsl:apply-templates/> } </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="header">#!/usr/local/bin/perl -w use strict; use CGI qw(param); use CGI::Util qw(expires); use IO::Handle (); # limit sleep time to 1 minute to prevent DOS attack use constant SLEEP_LIMIT => 60; # forward decls sub GetStatusText; sub Run; sub JumpTo; sub GetContentType; sub ExpiresFromDelta; sub GetFileSize; sub CheckUpload; sub CheckAllParams; my $rhRetval = Run(); my $next = $rhRetval->{next}; # where to Mr. Magoo? my $statusCode = $rhRetval->{status}; my $statusText = "unknown status"; my $ctype = GetContentType($next); my $raComments = $rhRetval->{comments}; my $bInclude = $rhRetval->{include}; my $expires_delta = $rhRetval->{expires}; my $epoch = time; if (defined($next) && defined($bInclude) && 1 == $bInclude) { # restrict paths when allowing source inclusion if (($next =~ /^\//) || ($next =~ /\/\.\./)) { $statusCode = 403; } } my $sleep = $rhRetval->{sleep}; if (defined($sleep)) { if (($sleep =~ /^\d+$/) && ($sleep <= SLEEP_LIMIT)) { sleep $sleep; } else { push @$raComments, "Bad sleep interval $sleep"; } } print "Content-Type: $ctype\n"; if (defined($expires_delta)) { print ExpiresFromDelta($expires_delta) . "\n"; } if(defined($statusCode)) { $statusText = GetStatusText($statusCode); print "Status: $statusCode $statusText\n\n"; } else { print "\n"; } if (!defined($next)) { print "$statusText\n"; } else { my $content; if ($bInclude) { $! = 0; # clear i/o errs open HINCLUDE, $next; if ($! != 0) { push @$raComments, "Unable to open $next"; $content = JumpTo($next, $raComments); print STDERR "Unable to open $next\n"; } else { my $eor = $/; undef $/; $content = <HINCLUDE>; # allow caching tests to be performed by interpolating __EPOCH__ $content =~ s/__EPOCH__/$epoch/g; close HINCLUDE; $/ = $eor; } } else { $content = JumpTo($next, $raComments); } print $content; } # Return a simple VoiceXML document that navigates # to the URI specified by $next # Dump the comments in the array $raComments to the call log sub JumpTo { my($next, $raComments) = @_; <![CDATA[ my $content = <<EOF; <?xml version="1.0"?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml" > <form> <block> EOF ]]> foreach my $comment (@$raComments) { $content .= qq{<log>$comment </log>\n}; } <![CDATA[ $content .= <<EOF; <goto next="$next"/> </block> </form> </vxml> EOF ]]> $content; } # Determine what to do next # Return a hash containing one or more of the following keys: # next - the next document to navigate to # code - the HTTP response code # comments - a reference to an array of comments to aid in debugging sub Run { my $val; # temp var to stash param or header value my @comments = (); # array of comments obtained while processing </xsl:template> <xsl:template name="footer" > } # Map a status code to an informative string # http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1 sub GetStatusText { my($code) = @_; my $rhCodes = {100 => "Continue", 101 => "Switching Protocols", 200 => "OK", 201 => "Created", 202 => "Accepted", 203 => "Non-Authoritative Information", 204 => "No Content", 205 => "Reset Content", 206 => "Partial Content", 300 => "Multiple Choices", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 305 => "Use Proxy", 307 => "Temporary Redirect", 400 => "Bad Request", 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden", 404 => "Not Found", 405 => "Method Not Allowed", 406 => "Not Acceptable", 407 => "Proxy Authentication Required", 408 => "Request Time-out", 409 => "Conflict", 410 => "Gone", 411 => "Length Required", 412 => "Precondition Failed", 413 => "Request Entity Too Large", 414 => "Request-URI Too Large", 415 => "Unsupported Media Type", 416 => "Requested range not satisfiable", 417 => "Expectation Failed", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Time-out", 505 => "HTTP Version not supported extension-code"}; return (exists($rhCodes->{$code}) ? $rhCodes->{$code} : "invalid status code"); } sub GetContentType { my($next) = @_; my $ctype = "text/plain"; if (defined($next)) { my $rhTypes = {'txml' => 'text/xml', 'vxml' => 'text/xml', 'xml' => 'text/xml', 'srgs' => 'text/xml'}; my @parts = split /\./, $next; my $ext = $parts[0]; if (exists($rhTypes->{$ext})) { $ctype = $rhTypes->{$ext}; } } $ctype; } # return an expires header given seconds since epoch sub ExpiresFromDelta { my($delta) = @_; $delta = (($delta >= 0 && $delta !~ /^\+/) ? "+" : "") . $delta . "s"; "Expires: " . expires($delta); } # check the size of the file referenced by $fh sub GetFileSize { my($fh) = @_; my $size = 0; if (defined($fh)) { my $io = IO::Handle->new_from_fd(fileno($fh), 'r'); if (defined($io)) { my @stats = $io->stat(); $size = $stats[7]; } } $size; } # check the validity of the named file upload # optionally validate its size sub CheckUpload { my($name, $compsize, $raComments) = @_; my $retval = 0; my $size = GetFileSize(param($name)); if (defined($compsize)) { if ($compsize =~ /^\d+$/) { # if all digits, assume static value for comparison $compsize = int($compsize); } elsif ($compsize =~ /^[a-zA-Z_]/) { # assume a reference to another parameter my $psize = param($compsize); if (defined($psize)) { # we expect digits if ($psize =~ /^\d+$/) { $compsize = int($psize); } else { push @$raComments, 'invalid if-upload/@size ' . $compsize . '; expected number'; } } else { push @$raComments, 'unable to retrieve if-upload/@size ' . $compsize; } } else { # yikes. bad variable name push @$raComments, 'bad if-upload/@size ' . $compsize; } if ($size == $compsize) { $retval = 1; } else { push @$raComments, 'file size ' . $size . ' did not match expected size ' . $compsize; } } else { # just check if we got an upload with this name if ($size > 0) { $retval = 1; } else { push @$raComments, 'no file upload found for ' . $name; } } $retval; } # loop through the CGI params received in the HTTP request and verify that their names/values # exist in the hash reference. also verify that all of the expected values were passed in the request sub CheckAllParams { my($rhExpectedParams, $raComments) = @_; my $ret = 1; my @params = param(); # loop through what we got in the HTTP request, and see if we expected it foreach my $name (@params) { my $vSubmitted = param($name); my $vExpected = $rhExpectedParams->{$name}; if (!defined($vExpected)) { # if the values aren't equal, we'll catch it during the next loop push @$raComments, "unexpected '$name' in request'"; $ret = 0; } } # loop through what we expected to get, and see if we received it foreach my $expected (keys %$rhExpectedParams) { my $vExpected = $rhExpectedParams->{$expected}; my $vSubmitted = param($expected); if (!defined($vSubmitted)) { push @$raComments, "expected '$expected' not found"; $ret = 0; } elsif ($vExpected ne $vSubmitted) { push @$raComments, "expected '$expected' to be '$vExpected' not '$vSubmitted'"; $ret = 0; } } $ret; } </xsl:template> <!-- the headers we're willing to expose. allowing arbitrary header requests is a security risk --> <xsl:template name="map-header"> <xsl:param name="header"/> <xsl:choose> <xsl:when test="$header = 'User-Agent'">HTTP_USER_AGENT</xsl:when> <xsl:when test="$header = 'Request-Method'">REQUEST_METHOD</xsl:when> <xsl:when test="$header = 'Content-Type'">CONTENT_TYPE</xsl:when> <xsl:otherwise>__UNKNOWN__<xsl:value-of select="$header"/></xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> |
The directory convention requires test developers to ensure that paths from and to other test documents follow the convention.
The following example contains a reference to an IRCGI document from a VoiceXML document:
<goto next="cgi-bin/ua.ircgi" />
The following example contains a reference to a VoiceXML document from an IRCGI document:
<next dest="../pass.vxml"/>
Given the directory convention, Web server administrators must do the following:
The following example configures Apache to execute documents with a .ircgi extension as a Perl CGI:
Addhandler cgi-script .ircgi
The following example configures Tomcat to run transformed files with a .ircgi extension as a JSP:
<servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.ircgi</url-pattern> </servlet-mapping>
The VoiceXML 2.1 Implementation Report includes 147 assertions and corresponding tests. The Voice Browser Working Group would like to further acknowledge the contributions of several individuals for authoring and reviewing assertions and for reviewing tests: