Over the past few months Ive been laboring away at a new book for Cisco Press, which has the snappy title Developing Cisco IP Phone Productivity Services. In a nutshell, Cisco IP Phone Services are simply XML files served up to the phone over a standard HTTP link. XML objects can be used to display a wide variety of data on the phone, enabling programs running on a web server to use the phone as a flexible I/O device.
This means that anybody who can put together a web page can create nifty programs that interact with Ciscos IP phones. Examples that have been created so far include flight tracking apps, appointment books, and joke-a-day services. A well-loved productivity application is shown in Figure 1.
When the programmers at Ciscos Dallas engineering center were designing these services, they naturally chose to use XML to wrap up the various objects that were being sent back and forth. Yes, XML was in the air at the time, but there were practical reasons as well. First among these was the availability of a compact XML parser that fit in the phones firmware footprint. Second was the general feel-good vibe that comes with using an accepted standard as an integral part of our product. An additional boon was the support for XML in off-the-shelf tools, such as Microsofts Internet Explorer or Altovas XML Spy.
The menagerie of XML objects that the phone knows how to render and/or execute is fairly small. There are XML definitions for menus, graphics, directory listings, and so on. As an example, the simplest XML object supported by the phone is the CiscoIPPhoneText element. A typical example of this element might look like this:
<CiscoIPPhoneText> <Title>Magic Cube</Title> <Text>When you take the pebble from my hand</Text> </CiscoIPPhoneText>
This XML would lead to a display on the phone like that shown in Figure 2.
How the Phone Handles Bad XML
Unfortunately, there isnt much to do when the phone gets badly formed XML. Weve all had times when a fat finger on the keyboard accidentally introduced an extra character. In this example, a web designer might inadvertently type </Text.>. The errant period in the closing tag for the Text element would be enough to turn this into a badly formed XML file. When the Cisco IP Phone attempts to render such an XML object, its parser naturally rejects the input. With not many good options at this point, the phone simply displays a blank screen.
This is a bad situation for the user of the IP Phone, but its even worse for the designer of the web page. There are virtually no clues here to identify the problem. In theory, we could load up the phone firmware with additional debugging code to identify problems such as this one, but we are up against constraints in memory space, developer time, and parser intelligence.
The good news is that existing tools such as Internet Explorer can help a lot with problems such as this. Looking at the same XML served up by the web server, Internet Explorer produces the display shown in Figure 3. This kind of display is great it takes you directly to the problem and identifies it clearly. Unfortunately, there is an entire class of XML problems that are not detected by Internet Explorer. Specifically, Internet Explorer (as of today) cant help diagnose an XML streamed that is well formed but invalid.
Valid Versus Well Formed
The XML standard defines two different standards for XML documents: well formed and valid. A well-formed document is one that follows the basic rules of XML regarding basic syntax, such as nesting of tags, placement of attributes, and so on. Creating well-formed documents is fairly easy for developers, because you can simply add new elements and attributes as the need arises, confident that the parser reading the document will know what to do.
On the other hand, a valid document is held to a somewhat higher standard. A valid document has to adhere to a well-defined set of rules regarding the type, order, and placement of tags that appear in it. In the early days of XML, these rules were typically defined in what was called a Document Type Definition, or DTD.
For various reasons, the DTD format first used with XML proved to be unpopular, and a revised schema definition system called XML Schema was introduced. XML Schema does all that the original DTDs did, with some enhancements. In addition to knowing about the placement and types of tags, XML Schema allows you to specify information about the text that is embedded inside the markup. So, for example, XML Schema allows me to specify that a value between the <Price> and </Price> tags should be a floating-point value between 1.0 and 9.99.
The World Wide Web Consortium ratified XML Schema as an official recommendation in 2001. Were seeing the first set of tools available that support it. Ive been using XML Spy 4.0, both to create schema files and to test them against XML data. Writing a parser that validates against XML Schema is considerably more difficult than a plain-vanilla parser, so it may be some time before a wide selection of tools are available.
The Invalid XML Problem
The difference between a well-formed and a valid file is easy to demonstrate with the XML objects used for the Cisco IP Phone. Figure 4 shows Internet Explorer happily parsing a well-formed XML document and displaying it on a PC. A quick look at this document makes it look as if all is well, but oddly enough, the IP Phone fails to parse and display the data.
This is the kind of problem that can be pretty tough to spot. In this particular case, the programmer of the web page used a lower case p in the opening and closing tags for element CiscoIPPhoneText. Since XML is case-sensitive, this error tripped up the phone, which determined that this is not a recognized document. The end user was faced with the unfriendly blank screen.
The solution was to write a validation tool that compared the XML document to the schema defined for the Cisco IP Phones. For this particular project, I chose to use the MSXML parser from Microsoft. Version 4 was released in the fall of last year, and will validate XML documents against DTDs and XML Schema. (A popular alternative is the Xerces parser, available for both C and Java.)
My simple version of this tool allows the user to input either a file name or a URL, then press the Validate button. The data is read from the source, parsed, and the result shown in a dialog box. The XML document from Figure 4 results in the error display in Figure 5. As you can see, MSXML does a pretty good job of identifying the offending location in the XML, saving the programmer from quite a bit of head scratching. The next section of this article will show you how to put together a program that accomplishes the same thing as my Validator.
Visual C++ 6.0 has some language extensions that make working with COM objects a bit easier. (For example, using the #include statement to include a DLL directly, creating type libraries on the fly.) I didnt use these in this application, which means the code you see here should be easily portable to other C++ compilers. Perhaps this philosophy will help when porting the code used here to other languages as well.
In October of 2001, Microsoft released MSXML 4.0 as a free download. All versions of the XML parser are found at Microsofts XML page, http://www.microsoft.com/XML. You will need to download and install the MSXML 4.0 SDK to build programs that use the new parser. The install procedure for the parser by default copies header and library files to C:\Program Files\MSXML 4.0, with the header files in the inc subdirectory and the library files in lib. The include file msxml2.h contains all the definitions you will need in your C++ code, and msxml2.lib contains links to the appropriate parser routines.
My Validator project is a simple MFC dialog-based application. A complete listing is available online, so I wont go into it in detail. After creating the project using Microsofts Wizard, I made two minor modifications to accommodate the use of MSXML. First, I added C:\Program Files\MSXML 4.0\inc to my include path for both the debug and release versions of the program. This is where the header file msxml2.h is located, and it will be included in the main project. Second, I added the file C:\Program Files\MSXML 4.0\lib\msxml2.lib to the project. This library contains the CLSID and other definitions needed to access the functions in MSXML 4.0. To this skeleton, I added some code to let the user either browse to select an XML file for input, or simply type in a URL. These pieces of infrastructure are shown in action in Figure 6.
The Real Work Validation
There are two steps to perform in order to actually validate an XML document using MSXML 4.0. After the necessary plumbing needed to instantiate a copy of the MSXML COM Object of type XMLDOMDocument2, I have to create an XMLSchemaCache object, then add a copy of the Cisco IP Phone schema to it. A reference to that schema container is then passed to the DOM Document. The fragment of code that accomplishes this is shown in Example 1.
As is usually the case, C++ code that uses COM objects is unattractive, and a bit opaque. But in this simple example, you should be able to look past that and see what is actually happening. Most importantly, you can see that this program expects to find a copy of CiscoIPPhone.xsd in the current directory. This file is the file that actually contains the schema for all the Cisco IP Phone XML objects.
Once the DOM Document has a reference to the schema, it is ready to do the actual parsing. Microsofts DOM Document object is flexible enough to load either a reference to a local file, or to a URL, which will supply an HTTP stream. The fragment in Example 2 does this by simply calling the load method of the object. It then pops up a dialog with one of two possible outcomes: the successfully parsed XML content or a formatted error message.
Figure 5 shows an example of what you see when the parser reports a failure. Figure 7 shows what it does upon success, which is to just present a copy of the parsed data found in the xml property of the DOM object.
MXSML 4.0 is a great step forward for users of Microsofts parser. Adding validation to the tool provides a great leap forward for developers, and for end users who benefit from better checking of the data. There is one feature I wish Microsoft had implemented differently. As the control works now, when parsing fails, the document only keeps a copy of one line from the bad input. It would be nice to keep the entire document, or at least a little more context, which would make interpretation of the error a little bit easier.
However, given the price tag and the capabilities the control brings to my programs, I have to give it a better than passing grade.
Mark Nelson is a developer for Cisco Systems in Dallas, TX, and works on various projects dealing with IP Telephony. You can contact Mark at firstname.lastname@example.org or via his web site at http://www.dogma.net/markn.