| VoiceXML 2.1 Development Guide | Home | Frameset Home |
|
<vxml> tag. Now that we have that out of the way, we will now bore you with a listing of the errors that we will want to catch in our code. From looking in the Voxeo VoiceXML Development Guide, we can see the listing of shorthand exceptions, such as 'nomatch' that we might want to log, and probably all the fatal errors such as a 'badfetch' that are worth saving. Let's insert them as catchable events at the application scope of our code. And since we are writing a ColdFusion application, it would probably make sense to add in our CF-specific caching headers as well:<?xml version="1.0" encoding="UTF-8"?>
<vxml version = "2.1">
<cfheader name="Cache-Control" value= "no-cache">
<cfheader name="Expires" value="#Now()#">
<meta name="maintainer" content="youremail@here.com"/>
<property name="universals" value="help"/>
<var name="MyEvent"/>
<!-- ******************** -->
<!-- START EVENT HANDLERS -->
<catch event="help nomatch noinput error connection.disconnect.hangup">
<assign name="MyEvent" expr="_event"/>
<log expr="'***** TRAPPED A' + _event +'EVENT *****'"/>
</catch>
<!-- END EVENT HANDLERS -->
<!-- ****************** -->
<form id="Form1">
</form>
</vxml>
<log> element:
<log expr="'***** TRAPPED A' + _event +'EVENT *****'"/>
***** TRAPPED A error.badfetch.500 EVENT *****
<var name="MyEvent"/>
....
<assign name="MyEvent" expr="_event"/>
<property> element, as this grammar is not enabled by default. Now that we have our error handling in place, let's flesh out the rest of our code...<field> results that we wish to keep. Since we are logging this data in hopes of tuning our dialogs and grammars, let's assume that we want to get the values for grammar confidence scores, user utterances, and grammar return values.
<?xml version="1.0" encoding="UTF-8"?>
<vxml version = "2.1">
<cfheader name="Cache-Control" value= "no-cache">
<cfheader name="Expires" value="#Now()#">
<meta name="maintainer" content="youremail@here.com"/>
<property name="universals" value="help"/>
<var name="Current_Location"/>
<var name="MyEvent"/>
<var name="MyException"/>
<var name="MyConfidence"/>
<var name="MyUtterance"/>
<var name="MyInterp"/>
<var name="MySessionID" expr="session.id"/>
<var name="MySize"/>
<var name="MyDur"/>
<var name="MyTermChar"/>
<!-- ******************** -->
<!-- START EVENT HANDLERS -->
<catch event="help nomatch noinput error connection.disconnect.hangup logresults">
<assign name="MyEvent" expr="_event"/>
<log expr="'***** TRAPPED A' + _event +'EVENT *****'"/>
</catch>
<!-- END EVENT HANDLERS -->
<!-- ****************** -->
<form id="Form1">
<block>
<prompt>
Lets step through our app and, log some results to our text file.
For fun, we can give the app a few no inputs and no matches, just to log the events.
</prompt>
<goto next="#Form2"/>
</block>
</form>
<form id="Form2">
<field name="F_1">
<grammar type="text/gsl">
<![CDATA[[
[nick] {<F_1 "Nick">}
(ay jay) {<F_1 "AJ">}
[brian] {<F_1 "Brian">}
[kevin] {<F_1 "Kevin">}
[howee] {<F_1 "Howie">}
]]]>
</grammar>
<prompt>
who is your favorite back street boy?
is it nick, brian, ayy jay, kevin, or howie?
</prompt>
<filled>
<assign name="MyConfidence" expr="F_1$.confidence"/>
<assign name="MyInterp" expr="F_1"/>
<assign name="MyUtterance" expr="F_1$.utterance"/>
<prompt>
Oh yes, <value expr="F_1"/> sure is dreamy. for a cast rat eye, that is.
</prompt>
</filled>
</field>
<field name="F_2">
<grammar>
<![CDATA[[
(river dancing) {<F_2 "River Dancing">}
(break dancing) {<F_2 "Break Dancing">}
(white ?boy dancing) {<F_2 "White Folks Dancing">}
]]]>
</grammar>
<prompt>
Which is the absolute stupidest form of dancing known to man?
Is it river dancing, break dancing, or just any kind of white boy dancing?
</prompt>
<!--
See Also:
The Achy-Breaky Stomp, The Electric Slide, The Polka, The Cabbage Patch, any form of Disco, etc.
-->
<filled>
<prompt>
How right you are, <value expr="F_2"/> is quite goofy looking.
</prompt>
<assign name="MyConfidence" expr="F_2$.confidence"/>
<assign name="MyInterp" expr="F_2"/>
<assign name="MyUtterance" expr="F_2$.utterance"/>
</filled>
</field>
<record name="R_1" beep="true" maxtime="10s">
<prompt>
You now have ten seconds to expound on your views in regards to <value expr="F_2"/>
looking unimaginably dorky.
</prompt>
<filled>
<assign name="MyDur" expr="R_1$.duration"/>
<assign name="MySize" expr="R_1$.size"/>
<assign name="MyTermChar" expr="R_1$.termchar"/>
<prompt>
Wow, thats quite a manifesto. Kazzinski would be proud.
</prompt>
</filled>
</record>
</form>
</vxml>
<var name="Current_Location"/>
<form>, this way, the value will always indicate the <form> where an event or exception happened:
<form id="Form1">
<block>
<assign name="Current_Location" expr="'ApplicationLog.cfm#Form1'"/>
....
<data> element to send our event logs off to our catcher script, (which we will cover in the next Step of the Lesson). The <data> element is generally used for gathering xml-formatted data from an external source, but it also works very much like the more familiar <submit> element, in that we can also use it to 'blindly' submit application data. To explain, when using the <data> element, we can send off a series of variable-value pairs to an external file, but, unlike the <submit> element, invoking this tag does not transfer the caller to the destination specified in the 'src' attribute. Using this tag will simply send our variable value pair to the specified URL, and the caller will remain within the current execution context.
<data name="MyData"
src="Catcher.cfm"
namelist="MyEvent Current_Location MyUtterance MyInterp MyConfidence MySessionID"
method="get"/>
<data> element to each of our <catch> handlers, as well as to each <filled> statement within our existing code, and while we are at it, let's also code some conditional statements into those catch handlers so that we can plan for an appropriate response to our callers if such events do crop up. And just for kicks, let's add an additional <form> that will throw us an 'unsupported.language' error , (non-fatal), and then a 'badfetch/semantic' error, (fatal), just so that we can see a 'true' error be caught and logged. We will also add a few <goto> statements within our code so that we have an intelligent call flow. Let's now take a gander at what our New and Improved VoiceXML code looks like:
<?xml version="1.0" encoding="UTF-8"?>
<vxml version = "2.1">
<cfheader name="Cache-Control" value= "no-cache">
<cfheader name="Expires" value="#Now()#">
<meta name="maintainer" content="youremail@here.com"/>
<property name="universals" value="help"/>
<var name="Current_Location"/>
<var name="MyEvent"/>
<var name="MyException"/>
<var name="MyConfidence"/>
<var name="MyUtterance"/>
<var name="MyInterp"/>
<var name="MySessionID" expr="session.id"/>
<var name="MySize"/>
<var name="MyDur"/>
<var name="MyTermChar"/>
<!-- ******************** -->
<!-- START EVENT HANDLERS -->
<catch event="help nomatch noinput error connection.disconnect.hangup logresults">
<assign name="MyEvent" expr="_event"/>
<log expr="'***** TRAPPED A' + _event +'EVENT *****'"/>
<if cond="MyEvent =='help'">
<prompt>
God helps children, God helps elves.
God helps those who help themselves.
</prompt>
<elseif cond="MyEvent == 'nomatch'"/>
<prompt>
Sorry, but that isnt a valid choice.
</prompt>
<elseif cond="MyEvent == 'noinput'"/>
<prompt>
Hey buddy, speak up.
I didnt hear you say anything at all.
</prompt>
<elseif cond="MyEvent == 'error.unsupported.language'"/>
<prompt>
Yes, the Klingon language is strictly for dorks.
</prompt>
<goto next="ApplicationLog.cfm#Form4"/>
<elseif cond="MyEvent == 'error.badfetch'"/>
<data name="MyDataName" src="Catcher.cfm" namelist="MyEvent Current_Location MySessionID" method="get"/>
<exit/>
<elseif cond="MyEvent == 'error.semantic'"/>
<data name="MyDataName" src="Catcher.cfm" namelist="MyEvent Current_Location MySessionID" method="get"/>
<exit/>
<elseif cond="MyEvent == 'disconnect.hangup'"/>
<data name="MyDataName" src="Catcher.cfm" namelist="MyEvent Current_Location MySessionID" method="get"/>
<exit/>
<else/>
<log expr="'***** AN ERROR WITHOUT A CATCH HANDLER HAS OCCURED: ' + _error ' + *****'"/>
</if>
<data name="MyDataName" src="Catcher.cfm" namelist="MyEvent Current_Location MySessionID" method="get"/>
<goto expr="Current_Location"/>
</catch>
<!-- END EVENT HANDLERS -->
<!-- ****************** -->
<form id="Form1">
<block>
<assign name="Current_Location" expr="'ApplicationLog.cfm#Form1'"/>
<prompt>
Lets step through our app and, log some results to our text file.
For fun, we can give the app a few no inputs and no matches, just to log the events.
</prompt>
<goto next="#Form2"/>
</block>
</form>
<form id="Form2">
<block>
<assign name="Current_Location" expr="'ApplicationLog.cfm#Form2'"/>
</block>
<field name="F_1">
<grammar type="text/gsl">
<![CDATA[[
[nick] {<F_1 "Nick">}
(ay jay) {<F_1 "AJ">}
[brian] {<F_1 "Brian">}
[kevin] {<F_1 "Kevin">}
[howee] {<F_1 "Howie">}
]]]>
</grammar>
<prompt>
Who is your favorite back street boy?
Is it nick, brian, ayy jay, kevin, or howie?
</prompt>
<filled>
<assign name="MyConfidence" expr="F_1$.confidence"/>
<assign name="MyInterp" expr="F_1"/>
<assign name="MyUtterance" expr="F_1$.utterance"/>
<prompt>
Oh yes, <value expr="F_1"/> sure is dreamy. for a cast rat eye, that is.
</prompt>
<data name="MyDataName" src="Catcher.cfm" namelist="MyEvent Current_Location MyUtterance MyInterp
MyConfidence MySessionID" method="get"/>
</filled>
</field>
<field name="F_2">
<grammar type="text/gsl">
<![CDATA[[
(river dancing) {<F_2 "River Dancing">}
(break dancing) {<F_2 "Break Dancing">}
(white ?boy dancing) {<F_2 "White Folks Dancing">}
]]]>
</grammar>
<prompt>
Which is the absolute stupidest form of dancing known to man?
Is it river dancing, break dancing, or just any kind of white boy dancing?
</prompt>
<!--
See Also:
The Achy-Breaky Stomp, The Electric Slide, The Polka, The Cabbage Patch, Disco, etc.
-->
<filled>
<prompt>
How right you are, <value expr="F_2"/> is quite goofy looking.
</prompt>
<assign name="MyConfidence" expr="F_2$.confidence"/>
<assign name="MyInterp" expr="F_2"/>
<assign name="MyUtterance" expr="F_2$.utterance"/>
<data name="MyDataName" src="Catcher.cfm" namelist="MyEvent Current_Location MyUtterance
MyInterp MyConfidence MySessionID" method="get"/>
</filled>
</field>
<record name="R_1" beep="true" maxtime="10s">
<prompt>
You now have ten seconds to expound on your views in regards to <value expr="F_2"/>
looking unimaginably dorky.
</prompt>
<filled>
<assign name="MyDur" expr="R_1$.duration"/>
<assign name="MySize" expr="R_1$.size"/>
<assign name="MyTermChar" expr="R_1$.termchar"/>
<prompt>
Wow, thats quite a manifesto. Kazzinski would be proud.
</prompt>
<data name="MyDataName" src="Catcher.cfm" namelist="MyEvent Current_Location MyDur MySize
MyTermChar MySessionID" method="get"/>
<goto next="#Form3"/>
</filled>
</record>
</form>
<form id="Form3">
<block>
<assign name="Current_Location" expr="'ApplicationLog.cfm#Form3'"/>
<prompt>
Just for kicks, we will throw the app an unsupported Klingon language error to log.
</prompt>
<prompt xml:lang="Klingon">
Klaatu Barrada Nictu!
</prompt>
</block>
</form>
<form id="Form4">
<block>
<assign name="Current_Location" expr="'ApplicationLog.cfm#Form4'"/>
<prompt>
The last thing we will do is to transition to a bogus page,
and log the error result to our text file.
</prompt>
<goto next="Bogus.cfm"/>
</block>
</form>
</vxml>
<exit/>, so we can avoid any kind of post-hangup application 'looping'. Since we are dealing with a pretty static piece of VXML code, we also added some navigational directions within our catch handlers that will allow us to sequentially navigate through every event we have coded in the application. This is why some <catch> events have explicit <goto> statements written for them, and others use the 'generic' <goto expr="Current_Location"/> directive at the very bottom of our catch handler.<data> element, and write it to a text file for safekeeping. The code presented below assumes that we will have a subdirectory named 'txt' that resides in the same location of our code, so before running the script for the first time, be sure that you have indeed created this directory.
<CFSILENT>
<CFPARAM NAME="url.MyEvent" default=""/>
<CFPARAM NAME="url.MyException" default=""/>
<CFPARAM NAME="url.CurrentLocation" default=""/>
<CFPARAM NAME="url.MyUtterance" default=""/>
<CFPARAM NAME="url.MyConfidence" default=""/>
<CFPARAM NAME="url.MyInterp" default=""/>
<CFPARAM NAME="url.MySessionID" default=""/>
<CFPARAM NAME="url.MyDur" default=""/>
<CFPARAM NAME="url.MySize" default=""/>
<CFPARAM NAME="url.MyTermChar" default=""/>
</CFSILENT>
<CFSILENT> tags. <CFOUTPUT> tags. Since we will also want to log the time and date that events occured, we should then use the #dateformat# and #timeformat# functions within these tags, and set up how we want these values to be formatted:
<CFOUTPUT>
<CFSET MyDate="#dateformat(now(),"mm-dd-yyyy")# - #timeformat(now(),"HH:mm:ss")#"/>
</CFOUTPUT>
02-14-2003 - 21:21:17
<CFFILE> tag to effectively write the CF querystring values to our text file:
<CFOUTPUT>
<CFSET MyDate="#dateformat(now(),"mm-dd-yyyy")# - #timeformat(now(),"HH:mm:ss")#"/>
<CFFILE
action="APPEND"
file="c:\MyDirectory/MyFile.txt"
output=""/>
</CFOUTPUT>
<CFFILE> tag. ALso note that since we are using the <data> tag, our target page must be a plain-vanilla XML document, hence the <xml> declaration at the very top:
<?xml version="1.0" ?>
<cfheader name="Cache-Control" value= "no-cache">
<cfheader name="Expires" value="#Now()#">
<CFOUTPUT>
<CFSET MyDate="#dateformat(now(),"mm-dd-yyyy")# - #timeformat(now(),"HH:mm:ss")#"/>
<CFFILE action="APPEND"
file="c:\MyDirectory/MyFile.txt"
output="
=== APPLICATION EVENT LOG ===
Date: #MyDate#
Event: #url.MyEvent#
Code Location: #url.Current_Location#
Grammar Utterance: #url.MyUtterance#
Grammar Interpretation: #url.MyInterp#
Grammar Confidence: #url.MyConfidence#
SessionID: #url.MySessionID#
Recording Size: #url.MySize#
Recording Duration: #url.MyDur#
Recording TermChar: #url.MyTermChar#
"/>
</CFOUTPUT>
</xml>
=== APPLICATION EVENT LOG ===
Date: 02-18-2003 - 23:55:01
Event: undefined
Code Location: ErrorLog.cfm#Form2
Grammar Utterance: howee
Grammar Interpretation: Howie
Grammar Confidence: 0.7
SessionID: abc123...
Recording Size:
Recording Duration:
Recording TermChar:
<data> element | ANNOTATIONS: EXISTING POSTS |
agonzalez
|
|
| in the motorola source there are two errors log is placed not in the txt folder so in the same folder as the catcher and the xml tags are bad placed thank you | |
MattHenry
|
|
|
Hello Angel, I'm really sorry, but I don't know what it is that you are talking about here; your statement seems to be out of context for the concepts covered in the tutorial. If you can provide specific details as to what is 'wrong', I would be happy to take a look..... ~Matthew Henry |
| login |
|