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" "http://resources.tellme.com/toolbox/vxml-tellme.dtd">
<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.