Version: June 13, 2005
Contributors:
Copyright ©2004 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.
The planned date for entering Proposed Recommendation is 1 August 2005. 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:
The public is 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.
Note: The testimonials with pink background from "Acme Labs" and "Beta Inc." are just examples and will be replaced with the actually submitted testimonials.
The W3C VoiceXML 2.1 Specification is well-written, easily implementable and extremely useful. Acme Labs used it to make waffles, to transcribe telephone calls, to chase roadrunners, and to straighten the Tower of Pisa.
The W3C VoiceXML 2.1 Specification is extremely useful, easily implementable and well-written. Beta Inc. used it to make waffles, to transcribe telephone calls, to chase roadrunners, and to straighten the Tower of Pisa.
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 | |||||
42 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the code property of the DOMException object as specified in DOM Level 2 . | 0 | 0 | 0 |
43 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the documentElement property of the Document object as specified in DOM Level 2 . | 0 | 0 | 0 |
44 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getElementsByTagName method of the Document object as specified in DOM Level 2 . | 0 | 0 | 0 |
45 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getElementsByTagNameNS method of the Document object as specified in DOM Level 2 . | 0 | 0 | 0 |
46 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getElementById method of the Document object as specified in DOM Level 2 . | 0 | 0 | 0 |
47 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the nodeName property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
48 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the nodeValue property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
49 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the nodeType property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
50 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the parentNode property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
51 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the childNodes property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
52 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the firstChild property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
53 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the lastChild property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
54 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the previousSibling property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
55 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the nextSibling property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
56 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the attributes property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
57 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the ownerDocument property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
58 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the namespaceURI property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
59 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the prefix property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
60 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the localName property of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
61 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the hasChildNodes method of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
63 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the hasAttributes method of the Node object as specified in DOM Level 2 . | 0 | 0 | 0 |
64 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the length property of the NodeList object as specified in DOM Level 2 . | 0 | 0 | 0 |
65 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the item method of the NodeList object as specified in DOM Level 2 . | 0 | 0 | 0 |
66 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the length property of the NamedNodeMap object as specified in DOM Level 2 . | 0 | 0 | 0 |
67 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getNamedItem method of the NamedNodeMap object as specified in DOM Level 2 . | 0 | 0 | 0 |
68 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the item method of the NamedNodeMap object as specified in DOM Level 2 . | 0 | 0 | 0 |
69 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getNamedItemNS method of the NamedNodeMap object as specified in DOM Level 2 . | 0 | 0 | 0 |
70 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the data property of the CharacterData object as specified in DOM Level 2 . | 0 | 0 | 0 |
71 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the length property of the CharacterData object as specified in DOM Level 2 . | 0 | 0 | 0 |
72 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the substringData method of the CharacterData object as specified in DOM Level 2 . | 0 | 0 | 0 |
73 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the name property of the Attr object as specified in DOM Level 2 . | 0 | 0 | 0 |
74 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the specified property of the Attr object as specified in DOM Level 2 . | 0 | 0 | 0 |
75 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the value property of the Attr object as specified in DOM Level 2 . | 0 | 0 | 0 |
76 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the ownerElement property of the Attr object as specified in DOM Level 2 . | 0 | 0 | 0 |
77 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the tagName property of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
78 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getAttribute method of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
79 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getAttributeNode method of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
80 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getElementsByTagName method of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
81 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getAttributeNS method of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
82 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getAttributeNodeNS method of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
83 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the getElementsByTagNameNS method of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
84 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the hasAttribute method of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
85 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the hasAttributeNS method of the Element object as specified in DOM Level 2 . | 0 | 0 | 0 |
86 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the target property of the ProcessingInstruction object as specified in DOM Level 2 . | 0 | 0 | 0 |
87 | D | Optional. | Yes. | The DOM exposed by the <data> tag must support the data property of the ProcessingInstruction object as specified in DOM Level 2 . | 0 | 0 | 0 |
1 | 2 | Required. | Yes. | Grammar element may include a srcexpr attribute to dynamically generate grammar URL | 0 | 0 | 0 |
2 | 2 | Required. | Yes. | If both src and srcexpr are included, error.badfetch is thrown | 0 | 0 | 0 |
3 | 2 | Required. | Yes. | If both srcexpr and inline grammar are included, error.badfetch is thrown | 0 | 0 | 0 |
4 | 2 | Required. | Yes. | If none of src, srcexpr nor inline grammar are included, error.badfetch is thrown | 0 | 0 | 0 |
5 | 2 | Required. | Yes. | srcexpr must be evaluated every time the grammar element needs to be executed | 0 | 0 | 0 |
6 | 2 | Required. | Yes. | If both srcexpr and inline grammar are included, error.badfetch is thrown | 0 | 0 | 0 |
7 | 2 | Required. | Yes. | If srcexpr cannot be evaluated, an error.semantic is thrown | 0 | 0 | 0 |
8 | 2 | Required. | Yes. | If both src and inline grammar are included, error.badfetch is thrown | 0 | 0 | 0 |
9 | 3 | Required. | Yes. | Script element may include an srcexpr attribute to dynamically generate script URL | 0 | 0 | 0 |
10 | 3 | Required. | Yes. | If both src and srcexpr are included, error.badfetch is thrown | 0 | 0 | 0 |
11 | 3 | Required. | Yes. | If none of src, srcexpr nor inline script are included, error.badfetch is thrown | 0 | 0 | 0 |
12 | 3 | Required. | Yes. | srcexpr must be evaluated every time the script element needs to be executed | 0 | 0 | 0 |
13 | 3 | Required. | Yes. | If both srcexpr and inline script are included, error.badfetch is thrown | 0 | 0 | 0 |
14 | 3 | Required. | Yes. | If both src and inline script are included, error.badfetch is thrown | 0 | 0 | 0 |
15 | 3 | Required. | Yes. | If srcexpr cannot be evaluated, an error.semantic is thrown | 0 | 0 | 0 |
16 | 4 | Required. | 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. | 0 | 0 | 0 |
17 | 4 | Required. | 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>. | 0 | 0 | 0 |
18 | 4 | Required. | Yes. | Exactly one of "name" and "nameexpr" must be specified; otherwise, an error.badfetch event is thrown. | 0 | 0 | 0 |
19 | 4 | Required. | 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. | 0 | 0 | 0 |
20 | 4 | Required. | Yes. | If no <mark> was executed, the markname and marktime properties of application.lastresult$ are undefined. | 0 | 0 | 0 |
141 | 4 | Required. | Yes. | If nameexpr cannot be evaluated, an error.semantic event is thrown. | 0 | 0 | 0 |
21 | 5 | Required. | Yes. | If content is not returned within the specified fetchtimeout, an error.badfetch event is thrown. | 0 | 0 | 0 |
22 | 5 | Required. | Yes. | The interpreter fetches the URI specified by the src attribute. | 0 | 0 | 0 |
23 | 5 | Optional. | Yes. | If the name attribute is specified, the interpreter exposes the DOM through the ECMAScript variable corresponding to the value of the name attribute. | 0 | 0 | 0 |
24 | 5 | Optional. | Yes. | If the name attribute is present, and the interpreter doesn't support DOM, the interpreter must throw error.unsupported.data.name. | 0 | 0 | 0 |
25 | 5 | Required. | 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. | 0 | 0 | 0 |
26 | 5 | Required. | Yes. | If srcexpr cannot be evaluated, error.semantic is thrown. | 0 | 0 | 0 |
27 | 5 | Required. | Yes. | Exactly one of "src" or "srcexpr" must be specified; otherwise, an error.badfetch event is thrown. | 0 | 0 | 0 |
28 | 5 | Required. | Yes. | Interpreters must support the methods GET and POST when submitting an HTTP request. GET is the default method. | 0 | 0 | 0 |
29 | 5 | Required. | Yes. | Specifying a URL that points to a non-existent resources causes the interpreter to throw a catchable error.badfetch event. | 0 | 0 | 0 |
30 | 5 | Required. | Yes. | If the name attribute is specified, and the interpreter retrieves an XML document that is not well-formed, the interpreter must throw a catchable error.badfetch. | 0 | 0 | 0 |
31 | 5 | Required. | Yes. | The <data> element can occur in executable content or as a child of <form> or <vxml>. | 0 | 0 | 0 |
32 | 5 | Required. | Yes. | The <data> element shares the same scoping rules as the <var> element. | 0 | 0 | 0 |
33 | 5 | Required. | 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. | 0 | 0 | 0 |
34 | 5 | Required. | 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. | 0 | 0 | 0 |
35 | 5 | Required. | Yes. | When an ECMAScript variable is submitted to the server its value is first converted into a string before being submitted. | 0 | 0 | 0 |
36 | 5 | Required. | Yes. | The default encoding type of the submitted document is "application/x-www-form-urlencoded". | 0 | 0 | 0 |
37 | 5 | Required. | Yes. | If the enctype attribute is set to "multipart/form-data", the interpreters must submit the document using that encoding type. | 0 | 0 | 0 |
38 | 5 | Required. | Yes. | If the namelist is not specified, no variables are submitted. | 0 | 0 | 0 |
39 | 5 | Required. | Yes. | If <data> has a namelist attribute, all and only those variables are submitted. | 0 | 0 | 0 |
40 | 5 | Required. | Yes. | If a namelist is supplied, it may contain individual variable references which are submitted with the same qualification used in the namelist. | 0 | 0 | 0 |
41 | 5 | Required. | Yes. | If specified, fetchaudio plays during a long fetch. | 0 | 0 | 0 |
142 | 5 | Required. | Yes. | If the datafetchhint property is set to "safe", content of that type is never fetched until it is needed | 0 | 0 | 0 |
143 | 5 | Required. | Yes. | A cached data resource must be reloaded if the datamaxage property for its type is less than its current age. | 0 | 0 | 0 |
144 | 5 | Required. | Yes. | A cached data resource must be reloaded if the datamaxstale property for its type is less than its current staleness. | 0 | 0 | 0 |
88 | 6 | Required. | Yes. | The <foreach> element can occur as a child of a <prompt> element. | 0 | 0 | 0 |
89 | 6 | Required. | Yes. | The array attribute must be an ECMAScript expression that evaluates to an array; otherwise an error.semantic is thrown. | 0 | 0 | 0 |
90 | 6 | Required. | 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. | 0 | 0 | 0 |
92 | 7 | Required. | Yes. | 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. | 0 | 0 | 0 |
93 | 7 | Required. | Yes. | When the shadow variable "record" is set, it must contain a reference to the recorded audio | 0 | 0 | 0 |
94 | 7 | Required. | Yes. | when property "recordutterance" is set to true, "recordingsize" must be set in the shadow variable for the form item variable | 0 | 0 | 0 |
95 | 7 | Required. | Yes. | When the shadow variable "recordingsize" is set, it must contain the size of the recorded audio in bytes | 0 | 0 | 0 |
96 | 7 | Required. | Yes. | when property "recordutterance" is set to true, "recordingduration" must be set in the shadow variable for the form item variable | 0 | 0 | 0 |
97 | 7 | Required. | Yes. | When the shadow variable "recordingduration" is set, it must contain the duration of the recorded audio in milliseconds | 0 | 0 | 0 |
98 | 7 | Required. | Yes. | application.lastresult$ must have the shadow variable "recording" set to the same value as the form item shadow variable | 0 | 0 | 0 |
99 | 7 | Required. | Yes. | application.lastresult$ must have the shadow variable "recordingsize" set to the same value as the form item shadow variable | 0 | 0 | 0 |
100 | 7 | Required. | Yes. | application.lastresult$ must have the shadow variable "recordingduration" set to the same value as the form item shadow variable | 0 | 0 | 0 |
101 | 7 | Required. | Yes. | In the case of <link> and <menu>, the interpreter only sets the application.lastresult$ properties. | 0 | 0 | 0 |
102 | 7 | Optional. | Yes. | <record> and <transfer> may record user utterances while attempting recognition | 0 | 0 | 0 |
103 | 7 | Required. | Yes. | enctype must be "multipart/form-data" when sending the recording on the namelist | 0 | 0 | 0 |
104 | 7 | Required. | Yes. | type must be "POST" when sending the recording on the namelist | 0 | 0 | 0 |
127 | 7 | Required. | Yes. | If recordutterance property is set to false, recording shadow variable will be set to undefined after filling a <field> using speech input | 0 | 0 | 0 |
128 | 7 | Required. | Yes. | If recordutterance property is set to false, recordingsize shadow variable will be set to undefined after filling a <field> using speech input | 0 | 0 | 0 |
129 | 7 | Required. | Yes. | If recordutterance property is set to false, recordingduration shadow variable will be set to undefined after filling a <field> using speech input | 0 | 0 | 0 |
130 | 7 | Optional. | Yes. | If recordutterance property is set to false, recording shadow variable will be set to undefined after terminating a <record> with speech | 0 | 0 | 0 |
131 | 7 | Optional. | Yes. | If recordutterance property is set to false, recordingsize shadow variable will be set to undefined after termininating a <record> using speech | 0 | 0 | 0 |
132 | 7 | Optional. | Yes. | If recordutterance property is set to false, recordingduration shadow variable will be set to undefined after terminating a <record> using speech | 0 | 0 | 0 |
133 | 7 | Optional. | Yes. | If recordutterance property is set to false, recording shadow variable will be set to undefined after terminating a <transfer> using speech | 0 | 0 | 0 |
134 | 7 | Optional. | Yes. | If recordutterance property is set to false, recordingsize shadow variable will be set to undefined after terminating a <transfer> using speech | 0 | 0 | 0 |
135 | 7 | Optional. | Yes. | If recordutterance property is set to false, recordingduration shadow variable will be set to undefined after terminating a <transfer> using speech | 0 | 0 | 0 |
136 | 7 | Required. | Yes. | Recorded utterance may be posted using <submit> | 0 | 0 | 0 |
137 | 7 | Required. | Yes. | Recorded utterance may be posted using <subdialog> | 0 | 0 | 0 |
138 | 7 | Required. | Yes. | Recorded utterance may be posted using <data> | 0 | 0 | 0 |
91 | 7.1 | Required. | Yes. | recordutterancetype defaults to a platform specified type | 0 | 0 | 0 |
105 | 7.1 | Required. | Yes. | set the media format of recorded audio during recognition using the recordutterancetype property | 0 | 0 | 0 |
106 | 7.1 | Required. | Yes. | platform must support audio file formats from VXML 2.0 | 0 | 0 | 0 |
107 | 7.1 | Required. | Yes. | platform may support other audio file formats in addition to VXML 2.0 ones. | 0 | 0 | 0 |
108 | 8 | Required. | Yes. | The default for disconnect element is to return no variables; this means the interpreter context will receive an empty ECMAScript object. | 0 | 0 | 0 |
109 | 8 | Required. | Yes. | If specified, the namelist attribute of disconnect element contains the names of the variables to be returned to interpreter context. | 0 | 0 | 0 |
111 | 8 | Required. | Yes. | If the namelist attribute of a disconnect element contains one or more undeclared variables, the interpreter throws error.semantic. | 0 | 0 | 0 |
112 | 9 | Optional. | Yes. | If type is specified and bridge not specified, type takes precedence over the default value of the bridge attribute. | 0 | 0 | 0 |
113 | 9 | Optional. | Yes. | If type="consultation" an outgoing call is attempted to the specified destination. | 0 | 0 | 0 |
114 | 9 | Optional. | Yes. | If type="consultation" and the caller disconnects while the outgoing call is attempted, connection.disconnect.hangup is thrown. | 0 | 0 | 0 |
115 | 9 | Optional. | Yes. | 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. | 0 | 0 | 0 |
116 | 9 | Optional. | Yes. | 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. | 0 | 0 | 0 |
117 | 9 | Optional. | Yes. | 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. | 0 | 0 | 0 |
118 | 9 | Optional. | Yes. | 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. | 0 | 0 | 0 |
119 | 9 | Optional. | Yes. | 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. | 0 | 0 | 0 |
120 | 9 | Optional. | Yes. | If type="consultation" and the transfer attempt ends but the reason is not known, the transfer form item variable is filled with unknown. | 0 | 0 | 0 |
121 | 9 | Optional. | Yes. | 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. | 0 | 0 | 0 |
122 | 9 | Optional. | Yes. | If type="consultation" and the platform does not support consultation transfer, error.unsupported.transfer.consultation is thrown. | 0 | 0 | 0 |
123 | 9 | Optional. | Yes. | The transfer element's "connecttimeout" value is not honored unless either "bridge" is set to true or "type" is set to "bridge". | 0 | 0 | 0 |
124 | 9 | Optional. | Yes. | Either the "bridge" or "type" attribute must be specified, else an "error.badfetch" event is thrown. | 0 | 0 | 0 |
125 | 9 | Optional. | Yes. | The "maxtime" value will only be honored if the "bridge" attribute is set to "true", or the "type" is set to "bridge" | 0 | 0 | 0 |
126 | 9 | Optional. | Yes. | When "transferaudio" is specified, and the audio file has not completed playing, the audio will cease upon a far-end connection. | 0 | 0 | 0 |
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 VoiceXML 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>
<!ELEMENT conf:hangup EMPTY >
<!ELEMENT conf:noinput EMPTY >
<!ATTLIST conf:noinput
duration CDATA #IMPLIED>
<!ELEMENT conf:nomatch EMPTY >
<!ATTLIST conf:nomatch
duration CDATA #IMPLIED>
<!ELEMENT conf:recording EMPTY >
<!ATTLIST conf:recording
value (%ir-utterances;|nonspeech) #REQUIRED
count CDATA #IMPLIED>
<!-- Add conf:speech to the menu element decl. -->
<!ELEMENT conf:speech EMPTY>
<!ATTLIST conf:speech
value (%ir-commands;) #REQUIRED
count 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"> Recite a sentence containing the word '<xsl:call-template name="emit-name-from-token"> <xsl:with-param name="token" select="@value"/> </xsl:call-template>'. </prompt> <prompt count="2"> 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. </prompt> <prompt count="3"> 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. </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"> Recite your favorite nursery rhyme, for example, 'Little Miss Muffett'. </prompt> <prompt count="2"> Recite your favorite nursery rhyme again.</prompt> <prompt count="3"> Recite your favorite nursery rhyme one more time.</prompt> </xsl:template> <xsl:template match="conf:noinput"> <prompt count="1"> No input expected. Say nothing <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. </prompt> <prompt count="2"> No input expected. Say nothing again <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. </prompt> <prompt count="3"> No input expected. Say nothing one more time <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. </prompt> </xsl:template> <xsl:template match="conf:nomatch"> <prompt count="1"> Say something unrecognizable <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. </prompt> <prompt count="2"> Say something unrecognizable again <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. </prompt> <prompt count="3"> Say something unrecognizable one more time <xsl:if test="@duration"> for <xsl:value-of select="@duration"/> seconds</xsl:if>. </prompt> </xsl:template> <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:call-template> </xsl:template> <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:call-template> </xsl:template> <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: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> <xsl:with-param name="taper">1</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="taper">0</xsl:with-param> </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="taper">0</xsl:with-param> </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="taper">0</xsl:with-param> </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="taper">1</xsl:with-param> </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="taper">0</xsl:param> <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="$taper = 1"> <prompt count="1"> Say '<xsl:value-of select="$text_mapping"/>'. </prompt> <prompt count="2"> Say '<xsl:value-of select="$text_mapping"/>' again. </prompt> <prompt count="3"> Say '<xsl:value-of select="$text_mapping"/>' one more time. </prompt> </xsl:when> <xsl:otherwise> <prompt> Say '<xsl:value-of select="$text_mapping"/>'. </prompt> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="emit-dtmf"> <xsl:param name="value"/> <xsl:param name="taper">0</xsl:param> <xsl:choose> <xsl:when test="$taper = 1"> <prompt count="1"> Press '<xsl:value-of select="@value"/>'. </prompt> <prompt count="2"> Press '<xsl:value-of select="@value"/>' again. </prompt> <prompt count="3"> Press '<xsl:value-of select="@value"/>' one more time. </prompt> </xsl:when> <xsl:otherwise> <prompt> Press '<xsl:value-of select="$value"/>'. </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. |
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" > <!ELEMENT ircgi (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-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> |
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-2003 W3C (MIT, ERCIM, Keio), All Rights Reserved. See http://www.w3.org/Consortium/Legal/. --> <!-- Transforms an ircgi test file into a Java Server Page.--> <!-- 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. --> <xsl:template name="header" ><%@ page language="java" contentType="text/xml" %><%@ page import="java.io.BufferedInputStream" %><%@ page import="java.io.InputStreamReader" %><%@ page import="java.net.URL" %><%@ page import="java.net.URLConnection" %><%@ page import="java.io.BufferedReader" %><%@ page import="java.util.Date" %><%@ page import="com.oreilly.servlet.multipart.MultipartParser" %><%@ page import="com.oreilly.servlet.multipart.Part" %></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; private MultiPartHandler(HttpServletRequest req) { request = req; } boolean find(String strFind) 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)) { return true; } } } catch (Exception e) { throw new JspException(e.toString()); } } return false; } } 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> <!-- Generate an expression that determines when the condition of an 'if-*' 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: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"/>") </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-2003 W3C (MIT, ERCIM, Keio), All Rights Reserved. See http://www.w3.org/Consortium/Legal/. --> <!-- Brought to you by... matto@tellme.com on 10/21/2002 --> <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> <!-- 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: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); # 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; 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); } </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>