With a little help from Simple Object Access Protocol (SOAP), XML, Extensible Style Language (XSL), Wireless Markup Language (WML), and Active Server Pages (ASP), the Wireless Access Protocol (WAP) traffic application is ready! That's right—no more getting up early to watch various news broadcasts with the hopes of catching the traffic update. From your Web-enabled phone or other WAP device, you can now receive up-to-the minute traffic reports (currently, San Diego is the only city available).
To pull this off, I had to find data that exists in a format that would let me extract it and combine it with WML to produce output suitable for a WAP device. Terry Givens described a Web service he created using the SOAP Toolkit in the November 28 XML UPDATE Commentary, and I decided to use that to get the XML data file for the traffic application.
I used the Remote Object Proxy Engine (ROPE) to call the Web service methods that return the XML data. Once I had the string, I needed a way to query the XML document. But first, I had to determine the type of XML document I was dealing with. Here's the document that I was testing with:
<XML ID="xmlData"> <?xml version="1.0" ? > <trees> <tree> <name>Aspen</name> <height unit="foot">4</height> </tree> </trees> </XML>
I'm leading to an example that shows you what to expect when you're dealing with SOAP and the XML string that it returned for this particular application. Here's an example, called a RowSchema:
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <s:Schema id="RowsetSchema"> ... </s:Schema> <rs:data> <z:row StateID="CA" StateName="California" /> </rs:data> </xml>
The following code illustrates how I found out what the XML string looked like in my ASP page:
sXML = oProxy.GetStates() Response.ContentType = "text/xml" Response.Write sXML Response.End
I could see the data, but I still had to figure out how to get to it and present it. For this, I created a couple of XMLDOMDocument objects. I used the same ASP page for both the Web browser and WAP browser versions; I detected the different user agents and called different XSL style sheets accordingly:
Set XMLdocument = Server.CreateObject("MSXML2.DOMDocument") Set XSLdocument = Server.CreateObject("MSXML2.DOMDocument") ...
if InStr(Request.ServerVariables("HTTP_USER_AGENT"), "Mozilla") then ... else 'WAP guy Response.ContentType = "text/vnd.wap.wml" xslfile = "../XSL/stateWml.xsl" XSLdocument.async = false XSLdocument.load(Server.MapPath(xslfile)) strResult=XMLdocument.transformNode(XSLdocument.documentElement) Response.Write strResult Response.End end if
At this point, I ran into difficulties creating the style sheets to transform the XML data into WML output. Also, I wondered what means to use to refer to the elements and attributes in the source tree. One problem was that I didn't understand the XSL namespace declarations, as the following code illustrates:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <xsl:pi name="xml"> <xsl:attribute name="version">1.0</xsl:attribute> </xsl:pi> <xsl:element name="xsl:stylesheet"> <xsl:attribute name="xmlns:xsl"<"http://www.w3.org/TR/WD-xsl</xsl:attribute> <xsl:element name="xsl:template"> <xsl:attribute name="match">/</xsl:attribute> <!\[CDATA\[ <?xml version="1.0" ?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> \]\]> <wml> ...
Using this declaration, the WML Parser kept producing errors that referred to the DOCTYPE and other elements in the declaration. I knew that some type of transformation was occurring because "Yeh Baby" (which I included for debugging purposes) kept appearing in the emulator information box. As I read up on XSL declarations and namespaces, it occurred to me that a lot of this declaration was unnecessary for my purposes. Finally, on MSDN I found an example that helped:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"gt; <xsl:template match="/"> <xsl:pi name="xml">version="1.0"</xsl:pi> <xsl:doctype>wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"</xsl:doctype> <wml> ...
Voila! My data! The problem with the previous declaration—at least for my application—was the way the WML Document Type Definition (DTD) was wrapped in the CDATA section. The MSDN example used the XSL namespace to define a DOCTYPE element and used the WML DTD as the element's value.
If you remember in the RowSchema example, the actual data was not a value of the element tag per se (<element>value</element>); it was the value of the attribute element:
<rs:data> <z:row StateID="CA" StateName="California" /> </rs:data>
To get to this point, I used XPATH, which lets you get the exact information you want by way of XPATH expressions. You specify a starting point (context node) and a location path (xml/rs:data/z:row), and from there, you specify the following to get the data:
<xsl:value-of select="@StateName" />
You can access my WAP traffic application on the Interknowlogy Web site. Many thanks to Gail Fitzmaurice, Terry Givens, Bruce Russell, Clyde Revilee, and Randy Broderdorf.