XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Creating VoiceXML Applications With Perl

Creating VoiceXML Applications With Perl

August 09, 2001

Introduction

VoiceXML is an XML-based language used to create Web content and services that can be accessed over the phone. Not just those nifty WAP-enabled "Web phones", mind you, but the plain old clunky home models that you might use to order a pizza or talk to your Aunt Mable. While HTML presumes a graphical user interface to access information, VoiceXML presumes an audio interface where speech and keypad tones take the place of the screen, keyboard, and mouse. This month we will look at a few samples that demonstrate how to create dynamic voice applications using VoiceXML, Perl, and CGI.

A rigorous introduction to VoiceXML and how it works is beyond the scope of this tutorial. For more complete introductions to VoiceXML's moving parts see Didier Martin's Hello, Voice World or the The VoiceXML Forum's FAQ.

Reach Out and Surf Somewhere

To demonstrate how easy it can be to make existing Web content available over the phone we will create a simple Perl CGI script that fetches an RSS channel file containing a list of the most recent uploads to CPAN and converts parts of it to VoiceXML so that it may be accessed over the phone via a VoiceXML gateway.

use strict;
use XML::XPath;
use LWP::UserAgent;

After loading the necessary module we begin our script by creating new HTTP::Request and LWP::UserAgent objects. We then call LWP::UserAgent's simple_request method to ask the remote server for the RSS file.

my $news_url = 'http://search.cpan.org/recent.rdf';
my $request = HTTP::Request->new('GET', $news_url);
my $ua = LWP::UserAgent->new();
my $response = $ua->simple_request($request);

Now that the request has been made, we will begin the VoiceXML output. We start by creating the mandatory vxml root element and a minimal form that contains a single block element. Inside the block element we put an audio element that asks the user to be patient while the RSS file is processed and a goto element that tells the VoiceXML browser to jump to the section of the current document labeled "headlines".

print qq*
<?xml version="1.0"?>
<vxml>
  <form id="greeting">
    <block>
      <audio>
        Please wait while I process the c pan news feed.
      </audio>
      <goto next="#headlines"/>
    </block>
  </form>
*;

Also in Perl and XML

OSCON 2002 Perl and XML Review

XSH, An XML Editing Shell

PDF Presentations Using AxPoint

Multi-Interface Web Services Made Easy

Perl and XML on the Command Line

Next we test the response object to ensure that we received the remote RSS file. If the file was successfully fetched, we create a new XML::XPath instance and pass it the content section of the response object for parsing. If anything goes awry during the request, or while parsing the returned content, we trap the error in the scalar $error for later processing. Although the eval block that wraps the initial call to XML::XPath adds a fair bit of overhead to the script, it nevertheless gives us a way to fail gracefully in the event of a parsing error. Without the surrounding eval, a parser error would cause the script to die unexpectedly.

my ($error, $xp);

if ($response->is_success) {
    eval {
        $xp = XML::XPath->new(xml => $response->content);
        $xp->find('/');
    };
    $error = 'Error parsing RSS file ' . $@ if $@;
}
else {
   $error = 'Remote server returned ' . $response->message();
}

If an error does occur along the way, we return a simple audio message that describes the error, disconnect (hang up on) the current user, and close the VoiceXML document.

if ( defined($error) ) {
    print qq*
   <form id="headlines">
     <block>
       <audio>
         I'm sorry. The following error occurred while fetching
         the headlines file. $error Please try again later.
       </audio>
       <disconnect/>
     </block>
  </form>
</vxml>
    *;
}
Comment on this article How are you using VoiceXML to connect the Web and the telephone?
Post your comments

If the RSS file has been fetched and parsed successfully we create a new form element; then, using an audio element inside a block wrapper, we tell the caller about the success and prepare them to hear the list of modules.

else {
    print qq*
  <form id="headlines">
    <block>
      <audio>
        The RSS file has been fetched and processed successfully. The
        following modules have recently been up loaded to c pan.
      </audio>
    </block>
    <block>
    *;

Next we loop through all the item elements in the RSS document. For each item element encountered we print a corresponding audio element for our VoiceXML document using the value of each item's title child element as the text.

    foreach my $news_item ($xp->findnodes('//item')) {
        print "<audio>" .
          $news_item->findvalue('title') .
          "</audio>\n";
    }

Finally we signal the caller that the entire list has been read, invite them to call again the next day, disconnect, and close the VoiceXML document.

    print qq*
    <audio>
      This completes the latest c pan up loads. Please call again tomorrow.
    </audio>
    <disconnect/>
    </block>
  </form>
</vxml>
    *;
}

While this script is not terribly useful in and of itself, think for a moment about just exactly what we have done here. In a few lines of code we have taken a resource from a distant part of the Web, extracted the information that we care about, and made that information available from any phone anywhere in the world.

Pages: 1, 2

Next Pagearrow