In "The WAP Traffic Application," I explained how I created a Wireless Markup Language (WML) traffic application that lets you render the current traffic speeds for San Diego on any Wireless Application Protocol (WAP) device and HTML browser. In this column, I use VoiceXML to take that application a step further and make it voice or punch-key driven and add voice response. (If you're not familiar with VoiceXML, see "Adding VoiceXML to our .NET Wireless Repertoire" and "Adding VoiceXML to Our .NET Wireless Repertoire, Part 2".)

To get the traffic data I need, I call a Web service that one of my colleagues developed ( see, "Two Web Services Solutions"). Then, I create an XML Document Object Model (XMLDOM) object similar to the following:

                              <!DOCTYPE vxml PUBLIC "-//Tellme Networks//Voice Markup Language                              1.0//EN" "">                              <vxml>                               <meta name="scoping" content="new"/>                              <form id="speed">                                 <block>                                 <%                                 Set xmlDoc = CreateObject("Microsoft.XMLDOM")                                                                  xmlDoc.async = False                                 xmlDoc.loadXML sXML                                                                  Set objNodeList = xmlDoc.getElementsByTagName("z:row")                                 . . .

This XMLDOM object provides access to the elements and the values I need from the XML that the GetTraffic method returns. Here's a sample of the XML that has the information I use:

<z:row TheFreeway='805 s' LocationDescription='Mira Mesa Blvd'                                   Speed='71' SourceTime='2001-06-10T13:42:00'/>

Below is the basic format of the information I need the system to read back to the caller:

<audio>Freeway exit name</audio> <audio> Speed</audio>

But I thought it would sound a lot better with a human voice—not just for the traffic speed, but also for the freeway exits. So I changed the above audio tags to the following:

<audio src="exitname.wav">Freeway exit name</audio>                              <audio src="speed.wav"> Speed</audio>

Instead of letting the computer read out the exits and speeds, I use my recorded voice. Instead of letting the computer read out the exits and speeds, I use my recorded voice. If the application can't retrieve the .wav files, it generates a computer voice rendition of the attributes from the node list.

I created .wav files for each freeway exit and for speeds from 0 mph to 86 mph. Then, the trick was to get the application to read each .wav file that matched the exit name and its corresponding speed in the node list. I accomplished this with a For loop that matches the node list index with the exit name and repeats the same process to get the speeds. I saved all the exit name .wav files in the same format (e.g., 2_0.wav, which translates to the first exit on freeway 805). Because the exits aren't the same for the north and south freeways and the east and west freeways, I created different folders for each direction.

Then, I massaged each node to get it into a format that made sense to the caller when the system reads the data back. I wrote a couple of functions that strip out the date, time, and speed from the data that the GetTraffic method returns. However, I ran into one little challenge. The node list usually includes four attributes and their values. For some reason, sometimes the Web service (which relies on an outside source for its data) returns no speed attribute value. Below is the code and function I developed:

For intExitNameCount = 0 To (objNodeList.length - 1)                                         'See function below                              strReturnSpeed = chkAttributeCount(objNodeList,intExitNameCount)                              strReturnSpeedNoWav= strReturnSpeed 'If there is a problem                              retrieving the wav file for the speed, then the actual value that                              the Web service returns is used.                                for intSpeedMatch = 0 To 86                                 if strReturnSpeed = intSpeedMatch then                              strReturnSpeed = intSpeedMatch                                  end if                              next                              'Data Output:                              Response.write "<audio src = "exitNameWavs/" & strFolderDirection &                              "/" & _   strFreeWayID & "_" & intExitNameCount & "'>" & _                                    objNodelist.item(intExitNameCount).Attributes(1).Text & _                                    " </audio> <audio src='speedWavs/" & _                                    strReturnSpeed & ".wav'>" & strReturnSpeedNoWav & "</audio>"                              next                              Function chkAttributeCount(NodeObject,NodeNumber)                              dim strSpeed                              if NodeObject.item(NodeNumber).Attributes(2).name = "SourceTime"                               then                                 'This happens only if there are only 3 Attributes                                  strTime = NodeObject.item(NodeNumber).Attributes(2).text                                    strSpeed = "No Value   Returned"                                  chkAttributeCount = strSpeed                              else strSpeed = objNodelist.item(NodeNumber).Attributes(2).Text                                  strTime = NodeObject.item(NodeNumber).Attributes(3).text                                  chkAttributeCount = strSpeed                              end if                               End Function

To access the application, dial 1-800-555-8355. You will hear a Tellme advertisement for about 15 seconds. When you hear the Main Menu, dial 1-24671.