Blogging is another topic that more and more people seem to do these days to increase their visibility, and so their voice can be heard. Why not use VoiceXML to actually interact with your blog or tweet using your own voice? In this article, you learn to do this very thing and to:
- Generate dynamic VoiceXML from remote data
- Pass through the content to VXML
- Submit the request to the blog and report back through VXML
- Submit status updates to Twitter
Voice, and audio in general, is more and more popular on the Web. Examples include the plethora of music and webcasts currently available online. This series shows several ways to combine voice and XML to develop the following useful applications:
- Part 1—a voice-enabled RSS reader.
- Part 2—a voice-enabled calendar.
- Part 3—a voice-enabled blogging and Twitter application.
- Part 4—an voice-enabled Yahoo search application.
For a blogger, nothing worse than being away from your blog and unable to make a post. With VoiceXML though, you needn't be quite so lost. You can build a VoiceXML-enabled application that will enable a user to blog over the telephone.
Unfortunately, current VoiceXML (VXML) platforms are limited and you cannot dictate a complete blog post, but you can use VoiceXML to post some standardized messages to an existing blog.
To achieve this, you'll build a Java™ servlet that will generate the VXML and process the input to assemble the blog post and send the post to the user's blog. For the moment, you'll ignore the issues of blog selection, user names and passwords, for reasons that will become clear when you look at the blogging interface.
For the workflow, the blogging interface servlet will:
- Get a list of categories from the blog
- Generate a VXML file that outputs a list of the accepted phrases, and then a list of the accepted categories
- The VXML uses the input method to submit the category and phrase information to the servlet
- The servlet assembles the blog post and sends it to the blog for posting
- The VXML then outputs a "completed" message and the process is complete
You can see the basic structure in Figure 1.
Figure 1. Voice blogging structure

Before you work on the VXML, you need to examine the blogging interface that will support your connection to the blog.
You'll find several solutions for posting to most blogs, but the majority support the XML-RPC (XML Remote Procedure Call) standards based on either the MetaWeblog/MovableType or Blogger API interfaces. The two are very similar, but the former was specially designed to get around some limitations of the latter and is therefore more practical.
Before you can even consider making a Web post, you need to set up the environment that will make the XML-RPC calls to the users blog. To communicate with most blogs, you need three pieces of information:
- The XML-RPC URL of the blog—For systems like WordPress, a special component usually handles the process. For example, WordPress provides the xmlrpc.php script. You need the full URL, for example http://mcslp.com/xmlrpc.php.
- Username—The username for your blog user.
- Password—The password for your blog user.
For all blogs you will also need one final piece of information, the blog ID. For sites and systems that host only one blog (that is, WordPress) the blog ID is always one. For sites and systems that host multiple blogs on the same site, you need the unique blog ID of your blog. MovableType, b2evolution and blogs that are part of a larger content management system fall into this latter category.
Obviously, none of this information is something that you can easily exchange over the VoiceXML interface. But if you set up a larger service, you might offer a login service using numbers to allow the user to login to their account and then load their service properties.
Back to the issue of opening up the connection to your blog, you'll produce a system by creating a new wrapper class around the XML-RPC connection that resolves the two necessary functions:
- Get a list of categories
- Make a post into methods of the main class
The bulk of the main class instance is therefore concerned with setting the up the core parameters you need, and creating an instance of the XML-RPC object you will use to communicate with the blog system.
To make the process easier, you'll use the XML-RPC library from Apache. Listing 1 shows the core of the BlogPost class and the method that will create an instance of the class.
Listing 1. Setting up a
BlogPost class
import java.util.*;
import java.io.*;
import java.net.URL;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
public class BlogPost {
String username;
String password;
String blogid;
String blogurl;
XmlRpcClientConfigImpl xmlrpcConfig = new XmlRpcClientConfigImpl();
XmlRpcClient client = new XmlRpcClient();
public BlogPost(String user,
String pass,
String id,
String url) {
username = user;
password = pass;
blogid = id;
blogurl = url;
try {
xmlrpcConfig.setServerURL(new URL(blogurl));
client.setConfig(xmlrpcConfig);
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("ERROR: " + ex.getMessage());
}
}
|
In Listing 1, you can see how you accept the input and then create a basic XmlRpcClient instance that will enable you to communicate with the XML-RPC service of the blog.
Now, to create a BlogPost object, supply the username, password, URL and blog ID using Listing 2.
Listing 2. Creating a
BlogPost object
BlogPost bp = new BlogPost("user",
"pass",
"1",
"http://myblog.com/xmlrpc.php");
|
Before making a post, you want to be able to provide the caller with the ability to set a category based on the existing categories currently configured within the blog.
The XML-RPC based weblog API provides a single function, getCategories, that returns a list of the categories configured for the specified blog. To obtain the information you need to supply the blog ID, username and password as part of the call.
The return value is more complex. In base data terms it is an array of hashes, where each hash consists of the information about the category, including the category ID, category name, source blog reference URL (for that category) and RSS feed URL (for that category). Thus, for each category you get a hash containing the information in Table 1.
Table 1. Hash containing category information
| categoryId | 3 |
| htmlUrl | http://www.thewriting.biz/?cat=3 |
| rssUrl | http://www.thewriting.biz?feed=rss2&cat=4 |
| categoryName | Making Money |
| description | Making Money |
Much of this you don't need—the information that you need is the categoryId and the categoryName. When you
make the blog post, you require the ID to set the category. You'll use the category name that is provided in the VoiceXML side of the application to give the user the option to select the category by name.
To make the information useful, you will send the request, get the information back, and resolve the category ID and name into a Java hashtable that you can use within the VoiceXML portion of the application to produce the list of categories. Listing 3 shows the GetCategories() method to your BlogPost object.
Listing 3. Getting categories from your blog into usable hashtable
public Hashtable GetCategories() {
Hashtable categories = new Hashtable();
Object[] cats = new Object[] {};
try {
cats = (Object [])
this.client.execute("metaWeblog.getCategories",
new Object[] {this.blogid,
this.username,
this.password});
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("ERROR: " + ex.getMessage());
}
for(int i = 0; i < cats.length; i++ ) {
HashMap category = (HashMap)cats[i];
categories.put(category.get("categoryId"),
category.get("categoryName"));
}
return categories;
}
|
You will use the resulting hash table in your servlet to output the list of categories.
When making a blog post, you go through several steps, particularly if you want to append categories to the post. You can do this all in one submission with some blog systems, but some are unable to accept the blog categories at the point you submit the post. For that reason a better solution is this sequence:
- Add a blog post, to get a unique blog post ID, but mark the post so that it is not automatically published (this is the
newPostRPC). - Using the blog post ID, set the categories you want for the blog post (using the
setCategoriesRPC). - Load the details of the entire blog post (using the
getPostRPC). - Republish the post, this time marking the post as ready for publish (using the
editPostRPC).
Listing 4 shows the sequence using the various XML-RPC calls to the remote service.
Note that, as with the categories, the format of the information is more complex than a
simple arguments. You have to construct a hashtable to contain the blog post
information. To set categories, create yet another hashtable, which is then passed as an array when you submit the category information (in the same way as the return value from getCategories was an array of hashtables).
Listing 4. Publishing a blog post
public Boolean PostIt(String title,
String description,
Integer category) {
Hashtable post = new Hashtable();
if (title != null) post.put("title", title);
post.put("dateCreated", new Date());
post.put("description", description);
Hashtable categories = new Hashtable();
categories.put("categoryId",category);
String blogpostid = "";
Boolean result = Boolean.FALSE;
try {
blogpostid = (String)
this.client.execute("metaWeblog.newPost",
new Object[] {this.blogid,
this.username,
this.password,
post,
Boolean.FALSE});
result = (Boolean)
this.client.execute("mt.setPostCategories",
new Object[] {blogpostid,
this.username,
this.password,
new Object[] {categories}});
HashMap postdetail = (HashMap)
this.client.execute("metaWeblog.getPost",
new Object[] {blogpostid,
this.username,
this.password, });
result = (Boolean)
this.client.execute("metaWeblog.editPost",
new Object[] {blogpostid,
this.username,
this.password,
postdetail,
Boolean.TRUE });
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("ERROR: " + ex.getMessage());
}
return(result);
}
|
For reference, the actual blog posting process is a single call to the PostIt() function:
bp.PostIt("Title","Content",5); |
With the blog posting mechanism and class in place, you only need to build a wrapper Java servlet that will output the VXML you need, and later, accept the input to generate the blog post.
Before you look at the VXML needed to generate your blog post, it's worth examining some of the rules that you can use to accept input from the user.
The test base grammar format uses a format of parentheses and brackets to help specify the grammar to use. As already mentioned, you cannot have any dictated content, but you can accept some basic phrases for use in your blog post.
Table 2 shows the main operators that are most useful.
Table 2. Main operators
| Operator | Example | Description |
|---|---|---|
| Disjunction | [happy sad] | Any one of the words is accepted as valid. |
| Concatenation | (very happy) | The entire phrase must be said to be accepted as valid. |
| Optional Phrase | (?very happy) | The phrase following the question mark (?) is optional, so both "very happy" and "happy" would be accepted from this example. |
| Positive Closure | (+very happy) | The phrase following the plus (+) must be said at least once, so "very happy" and "very very happy" are equally valid. |
| Kleene Closure | (*very happy) | The phrase following the asterisk (*) is optional, but can be repeated. Here "happy," "very happy," and "very very happy'"are all valid. |
Obviously you can combine all these different options, so you might have a list of valid phrases by combining the concatenation and disjunction operators.
For your blogging application you'll use the grammar shown in Listing 5.
Listing 5. Blogging topic grammar
(eye am [happy {<phrase "I am happy">}
sad {<phrase "I am sad">}
traveling {<phrase "I am traveling">}
(on business){<phrase "I am on business">}
] )
|
First of all, notice the "eye" in place of "I." Most VoiceXML systems are unable to identify the distinction between the word and the single letter, and some will simply refuse to accept words with less than two characters. Hence, you have to explicitly use the sound of the word, and then use a defined field value to capture what you really want.
For the rest, you simply provide a list of available choices. From the grammar in Listing 5, all of these statements are valid input:
- I am happy
- I am sad
- I am traveling
- I am on business
Next, look at the VXML source that you'll use to accept the input.
The core of the VXML source is shown here in Listing 6.
Listing 6. The main VXML sequence
<?xml version="1.0" encoding ="UTF-8"?>
<!DOCTYPE vxml PUBLIC "-//W3C//DTD VOICEXML 2.1//EN"
"http://www.w3.org/TR/voicexml21/vxml.dtd">
<vxml version="2.1" xmlns="http://www/w3/org/2001/vxml"
xml:lang="en-US">
<form id="blogging">
<block>
<prompt>
Welcome to the blogging service.
</prompt>
</block>
<field name="phrase">
<prompt>Please state your current status to be used on your blog.</prompt>
<grammar type="text/gsl">
<![CDATA[
(eye am [happy {<phrase "I am happy">}
sad {<phrase "I am sad">}
traveling {<phrase "I am traveling">}
(on business) {<phrase "I am on business">}
] )
]]>
</grammar>
</field>
<field name="location">
<prompt>Please state your current location</prompt>
<option>Edinburgh</option>
<option>New York</option>
<option>London</option>
<option>Paris</option>
<option>Stockholm</option>
</field>
<filled>
<prompt>
Your blog post will be: <value expr="phrase"/>.
Current location: <value expr="location"/>
</prompt>
<submit name="/VXMLBlogPost/blogpost"
namelist="phrase category location"/>
</filled>
</form>
</vxml>
|
The basic sequence from this file is similar to Listing 7.
Listing 7. Basic sequence
Service: Welcome to the blogging service. S: Please state your current status to be used on your blog. User: I am happy S: Please state your current location U: London S: Your blog post will be: I am happy. Current location: London |
You'll need to output this dynamically to add the final field, the list of categories configured in your blog.
To produce the list of categories, you generate the VXML in your Java servlet and then insert a blog that outputs the prompt to request a category. You can use the <option> tag to accept potential values from the user and assign the numerical category ID you need to use when submitting the information when making a blog post. The code in Listing 8 is the fragment that outputs the category list.
Listing 8. Outputting the category list
Hashtable cats = this.bp.GetCategories();
Enumeration keys = cats.keys();
while ( keys.hasMoreElements() ) {
String key = (String)keys.nextElement();
String cat = (String)cats.get( key );
out.println("<option value=\"" + key + "\">" + cat + "</option>");
}
|
The resulting VXML (including the surrounding field definitions) outputs the content in Listing 9.
Listing 9. Resulting VXML
<field name="category"> <prompt>Please state the category to be used for this post.</prompt> <option value="1">Commentary</option> <option value="2">Holiday Travel</option> </field> |
Now you're ready to accept the input.
Parsing on the input and making the post
The submit tag within VXML passes on the field values to a specified remote application as standard HTTP parameters. In your VXML the block is located within the filled section (see Listing 10).
Listing 10. The submit tag
<submit name="/VXMLBlogPost/blogpost"
namelist="phrase category location"/>
|
To accept the input and make the blog post, you only need to parse these parameters on
the input and then submit the blog post content details to the PostIt() method of your BlogPost class
instance, something which you can see in Listing 11.
Listing 11. Parsing the input and making the blog post
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
PrintWriter out = null;
out = res.getWriter();
res.setContentType("text/xml");
this.bp.PostIt( req.getParameter("title"),
req.getParameter("title") +
". I am currently located in " +
req.getParameter("location"),
Integer.parseInt(req.getParameter("category")));
printHeader(out);
out.println("<form><block>" +
"<prompt>Blog posted</prompt><disconnect/>" +
"</block></form>");
printFooter(out);
}
|
Now you should be able to make a blog post from any telephone in the world just by speaking your desired statement, location and category.
Now, look at how you can voice enable Twitter to generate mini-blogs.
Twitter is a Web 2.0 service that's getting a lot of attention lately. (See Resources for a link to Twitter.) This service lets you keep tabs on your friends not only on the Web, but also on your cell phone or in your Instant Messenger. Your friends can also keep tabs on you.
The idea of the service is that you send short bursts of text (less than 140 characters) to let other people know where you are and what you're doing right at that very moment. Originally intended for simple status messages, Twitter has morphed into a sort of "quick blog", in which people enter quick thoughts and send them off to their friends.
So what does this have to do with voice blogging? Everything! Remember, because real-time transcription isn't an option (at the moment) you have to satisfy yourself with choosing from a series of short, predefined statements. Perfect for the Twitterer on the go. If you have statements you use frequently, you can make sure they're available, or you can provide a Web interface in which users can enter new statements for use later.
The overall process is exactly the same as it is for blogging in general, but Twitter doesn't use XML-RPC. Instead, you'll need to submit your message, or "tweet", as the body of an HTTP POST request (see Listing 12).
Listing 12. Posting to Twitter using HTTP POST
import java.net.*;
import java.io.*;
public class BlogPost {
public BlogPost(String user,
String pass, String status) {
try{
Authenticator.setDefault(new PostAuthenticator(user, pass));
URL url = new URL ("http://twitter.com/statuses/update.xml");
URLConnection conn = url.openConnection();
conn.setDoInput (true);
conn.setDoOutput (true);
conn.setUseCaches (false);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
DataOutputStream printout = new DataOutputStream (conn.getOutputStream ());
String requestBody = "status=" + URLEncoder.encode (status);
printout.writeBytes (requestBody);
printout.flush ();
printout.close ();
DataInputStream input = new DataInputStream (conn.getInputStream ());
String str;
while (null != ((str = input.readLine()))){
System.out.println (str);
}
input.close ();
} catch (Exception e){
e.printStackTrace();
}
}
public static void main (String args[]){
BlogPost bp = new BlogPost("myusername", "mypassword",
"Playing with voice blogging to the Twitter API!");
}
}
|
You'll see the Authenticator in a moment. In Listing 12 you can see that you open a simple HTTP connection to Twitter,
and tell the system that you will write to and read from that connection.
What makes it a POST request is the fact that rather than add parameters (such as the status to the URL itself, they're sent as the body of the actual request.
Depending on whether you send the request to update.xml or update.json, you'll get a response in the appropriate format, which you can examine if necessary, but you don't necessarily need for blogging.
Of course, you don't want just anybody updating your Twitter, so you'll need to provide authentication. That's the Authenticator you saw at the top of the class.
The Authenticator class is abstract, so you'll need to subclass it and implement the getPasswordAuthentication()
method to store the username and password (see Listing 13).
Listing 13. Authenticating you to the server
import java.net.Authenticator;
import java.net.PasswordAuthentication;
public class PostAuthenticator extends Authenticator {
private String user;
private String pass;
public PostAuthenticator (String user, String pass){
this.user = user;
this.pass = pass;
}
protected PasswordAuthentication getPasswordAuthentication(){
char[] passwd = new String(this.pass).toCharArray();
PasswordAuthentication auth = new PasswordAuthentication(this.user, passwd);
return auth;
}
} |
Returning the object lets you set it as the default for the Authenticator class at large, which the Java servlet checks when it's confronted with a need for authentication in a URLConnection.
Then end result is that you can "tweet" at will.
In this article, you saw how to build a blogging solution that uses VoiceXML to provide the input method to make the blog post. Unfortunately, transcription or dictation is not widely supported, so instead of a free form input, you enabled the use of simple phrases through a detailed grammar specification, but that works just fine for Twitter. For variety, you also added the ability to state your current location.
The resulting application, written as a Java servlet, generates both the query information and then parses the input before it makes the post submission.
Be sure to read Part 4, the final article in this series, where you will develop an application that takes VoiceXML as input and queries the Yahoo Search API for both basic Web searches and Yahoo local searches.
| Description | Name | Size | Download method |
|---|---|---|---|
| Part 3 sample code | x-voicexml3-blog.zip | 5KB | HTTP |
Information about download methods
Learn
- Create VoiceXML pages within a Java Web developer framework, Part 1: Generate VoiceXML using Java servlets and JSPs (Brett McLaughlin, developerWorks, January 2006): Learn how Java servlets could easily power a VoiceXML application.
- Create VoiceXML pages
within a Java Web developer framework, Part 2: Expanding Java-driven VoiceXML applications (Brett McLaughlin, developerWorks, January 2006): Learn how to use servlets to go beyond single-page applications.
- VoiceXML 2.1 specification: Read about the set of features commonly implemented by Voice Extensible Markup Language platforms.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
- XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
- developerWorks technical events and webcasts: Stay current with technology in these sessions.
- The technology
bookstore: Browse for books on these and other technical topics.
Get products and technologies
- Twitter: Keep tabs on your friends not only on the Web, but also on your cell phone or in your Instant Messenger.
- Rome RSS/Atom syndication: Download these open source Java tools and libraries for parsing, generating and publishing RSS and Atom feeds.
- Apache XML-RPC Client: Get a simplified interface for connecting to XML-RPC sources.
- Voxeo: Find a wealth of information and a hosting solution for VoiceXML applications that provides access through traditional, VoIP and Skype.
- IBM trial software: Build your next development project with trial software available for download directly from developerWorks.
Discuss
- Participate in the discussion forum.
- XML zone discussion forums: Participate in any of several XML-related discussion forums.
- developerWorks XML zone: Share your thoughts: After you read this article, post your comments and thoughts in this forum. The XML zone editors moderate the forum and welcome your input.
- developerWorks blogs: Check out these blogs and get involved in the developerWorks community.

Martin Brown has been a professional writer for over eight years. He is the author of numerous books and articles across a range of topics. His expertise spans myriad development languages and platforms -- Perl, Python, Java, JavaScript, Basic, Pascal, Modula-2, C, C++, Rebol, Gawk, Shellscript, Windows, Solaris, Linux, BeOS, Mac OS/X and more -- as well as Web programming, systems management and integration. Martin is a regular contributor to ServerWatch.com, LinuxToday.com and IBM developerWorks, and a regular blogger at Computerworld, The Apple Blog and other sites, as well as a Subject Matter Expert (SME) for Microsoft. He can be contacted through his Web site at http://www.mcslp.com.
Comments (Undergoing maintenance)





