Extending the Golf Reservation System Application to Wireless Devices

In this section we will extend the Golf Reservation System application client from Chapter 9 to the wireless realm. The Golf Reservation System client interfaces a large database of golf courses and tee times via Web Services. Users will be able to browse local courses and reserve tee times. We will look at design requirements from the project and discuss two implementation strategies. The first strategy will use the Mobile Explorer Developer's Toolkit. The second approach will extend the Golf Reservation System client XSLT skins library to add a WML front-end to the application.

Application Requirements

The wireless front-end to the Golf Reservation System application will include the following features. (Please note that this is not a production system and should be used only for illustrative purposes.)

  • Users can search for golf courses against the same criteria available in the PC browser interface (name, city, state, zip code, and country).
  • Users can review the results of their selection in a list format.
  • Users can link to a specific golf course and review information about that course. This information will include the course's name, address, and price.
  • Users will be able to request a tee time on a specific date.
  • The mobile client will display all available tee times for the date chosen by the user.
  • The user will be able to select an open tee time and reserve the spot.
  • The mobile client will report the success or failure of the operation to the user. If the reservation is approved, the client will thank the user and display detailed information about the approved tee time.

Using the Mobile Explorer Developer's Toolkit

We will use the Mobile Explorer Developer's Toolkit to take a first crack at implementing our Golf Reservation System mobile client. Installing the toolkit will immediately update the .NET Developer Studio with two new features.

The toolkit is available at Microsoft's MSDN Web site at http://www.microsoft.com/mobile/phones/default.asp.

The first feature is the ability to add Mobile Web Forms to your project. Mobile Web Forms are similar to regular Web forms in structure and design. The Mobile Web Form wizard creates two new files for you: the .aspx file that contains the display logic and the .aspx.cs file that contains the super class definition that the Web forms page extends. The class definition declares protected properties that are available for use in the .aspx page and contains all server-side event handling subroutines.

The second key feature of the Mobile Explorer Developer's Toolkit is its cell phone emulator. You can use the emulator to test your programs without the need for an expensive phone. The emulator, which can emulate two styles of phone, makes iterative development and testing a snap.

Upon creating a new Mobile Web Form, the .NET Developer Studio presents you with a palette of controls suitable for use on WAP clients. These include simple form-input controls such as text boxes and selection lists. The wireless control palette also provides more advanced controls such as expression validators and a calendar control. The calendar control is particularly useful for creating a cross-device interactive date chooser.

In this example we will use the Mobile Explorer Toolkit to implement the first three functions in our requirements list: the search, search results, and course detail pages. We will create a single Mobile Web Form that contains three separate forms (one for each view). The Mobile Toolkit will handle breaking the forms down into individual WML decks and cards that will be retrieved by the WAP client. The Mobile Toolkit will also handle the creation and maintenance of the server-side session state by using URL session identifiers.

Dragging a Mobile Toolkit control from the palette onto a form adds a corresponding XML element from the mobile namespace to the .aspx page source. For example, these two lines of source code appear in the search.aspx page:

 <mobile:Label id=Label1 runat="server">Course Name</mobile:Label> <mobile:TextBox id=GCName runat="server"></mobile:TextBox>  

The first line adds a label to the form with the description Course Name. The second line creates an adjoining text input control with the id GCName. The value inserted into this control can be submitted to the server or referenced by WMLScript within the page.

Why does the Mobile Toolkit use its own XML markup language instead of using WML directly? The answer is that any mobile .aspx page can be used to create either WML or HTML, depending on the capabilities of the client device. The following excerpt from Search.aspx shows the source code behind the mobile search form.

 <body xmlns:mobile="Mobile Web Form Controls"> <mobile:form  runat="server"> <P> <mobile:Label  runat="server">Course Name</mobile:Label> <mobile:TextBox  runat="server"></mobile:TextBox> <mobile:Label  runat="server">City</mobile:Label> <mobile:TextBox  runat="server"></mobile:TextBox> <mobile:Label  runat="server">State</mobile:Label> <mobile:TextBox  runat="server"></mobile:TextBox> <mobile:Label  runat="server">Country</mobile:Label> <mobile:TextBox  runat="server"></mobile:TextBox> <mobile:Label  runat="server">Postal Code</mobile:Label> <mobile:TextBox  runat="server"></mobile:TextBox> <mobile:Command  runat="server">Search</mobile:Command> </P> </mobile:form> . . .  </body> 

Whenever this page is requested the .NET run-time environment will determine the type and capabilities of the client. The DLL created out of the Mobile Web Form will format the result document using the most appropriate markup language. The Mobile Web Form produces the following output when called by a mobile device:

 <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" 
"http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <head> <meta http-equiv="Cache-Control" content="max-age=0"/> </head> <card > <do type="prev" label="Back"> <prev/> </do> <p> <do type="accept" label="Search"><go href="search.aspx?__ufps=631317431691368096"
method="post"> <postfield name="__EVENTTARGET" value="Command1"/> <postfield name="GCName" value="$(GCName:noesc)"/> <postfield name="GCCity" value="$(GCCity:noesc)"/> <postfield name="GCState" value="$(GCState:noesc)"/> <postfield name="GCCountry" value="$(GCCountry:noesc)"/> <postfield name="GCPostalCode" value="$(GCPostalCode:noesc)"/> </go></do> Course Name <br/> <input name="GCName"/> City <br/> <input name="GCCity"/> State <br/> <input name="GCState"/> Country <br/> <input name="GCCountry"/> Postal Code <br/> <input name="GCPostalCode"/> </p> </card> </wml>

Notice that the Mobile Web Form run time generated all the WML form logic necessary to post back to the server. It transformed each <mobile:TextBox> element into two WML elements: an <input> element to capture user input and a <postfield> element to send the result back to the server. However, the results are quite different when an HTML browser hits the page.

 <html> <body> <form  name="Search" method="post" action="Search.aspx?__ufps=631317428385013792"> <input type="hidden" name="__EVENTTARGET" value=""> <input type="hidden" name="__EVENTARGUMENT" value=""> <script language=javascript> <!-- function __doPostBack(target, argument){ var theform = document.Search theform.__EVENTTARGET.value = target theform.__EVENTARGUMENT.value = argument theform.submit() } // --> </script> <span>Course Name</span><br> <input style="" name="GCName"/><br> <span>City</span><br> <input style="" name="GCCity"/><br> <span>State</span><br> <input style="" name="GCState"/><br> <span>Country</span><br> <input style="" name="GCCountry"/><br> <span>Postal Code</span><br> <input style="" name="GCPostalCode"/><br> <input style="" name="Command1" type="submit" value="Search"/><br> </form> </body> </html>   

The result this time is a perfectly well-formed HTML page that uses a traditional form to collect and submit user input. Obviously, the Mobile Web Form framework does a good job of sorting out what kind of markup language should be returned to a particular client. Therefore, if Mobile Web Forms support HTML clients as well as WML clients, why not use them to build your entire UI? The problem is that the Mobile Web Forms only support controls that will work correctly on small devices. The richness of your full-blown HTML client will suffer if you use Mobile Web Forms to develop it.

Another caveat about Mobile Web Forms is that both the .aspx file and the code-behind .aspx.cs file must extend the System.Web.UI.MobileControls.MobilePage class. This limitation means that you cannot directly reuse regular Web form content that you've already developed to drive your Mobile Web Forms. Without restructuring your business logic, you might need to rewrite a significant amount of content when building your Mobile Web Forms.

Now let's take a closer look at the search.aspx.cs file (complete code is available on the CD), which implements the MobileWebForm1 class that the Search.aspx file extends. Much of this file is auto-generated by the .NET Developer Studio as controls are added to the form. All the control declarations at the top of the file were added this way.

 using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Web; using System.Web.Mobile; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.MobileControls; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace MobileClient { /// <summary> /// Summary description for MobileClient. /// </summary> public class MobileWebForm1 : System.Web.UI.MobileControls.MobilePage { protected System.Web.UI.MobileControls.Form Search; protected System.Web.UI.MobileControls.TextBox GCName; protected System.Web.UI.MobileControls.Label Label2; protected System.Web.UI.MobileControls.TextBox GCCity; protected System.Web.UI.MobileControls.TextBox GCState; protected System.Web.UI.MobileControls.Label Label3; protected System.Web.UI.MobileControls.Label Label4; protected System.Web.UI.MobileControls.TextBox GCCountry; protected System.Web.UI.MobileControls.Label Label5; protected System.Web.UI.MobileControls.TextBox GCPostalCode; protected System.Web.UI.MobileControls.List gcList; protected System.Web.UI.MobileControls.Form SearchResult; protected System.Web.UI.MobileControls.Command Command1; protected System.Web.UI.MobileControls.Form GolfCourseDetail; protected System.Web.UI.MobileControls.Label Label6; protected System.Web.UI.MobileControls.Label Label7; protected System.Web.UI.MobileControls.Label Label8; protected System.Web.UI.MobileControls.Label Label9; protected System.Web.UI.MobileControls.Label DetailName; protected System.Web.UI.MobileControls.Label DetailDescription; protected System.Web.UI.MobileControls.Label Label1; protected System.Web.UI.MobileControls.Call DetailTelephone; protected System.Web.UI.MobileControls.TextView DetailAddress; 

The GolfCourseService variable is declared as a protected instance property. Taking this step avoids the performance penalty inherit in reinstantiating this variable each time the client calls an event handler.

 protected localhost.GolfCourseService gs; public MobileWebForm1() { Page.Init += new System.EventHandler(Page_Init); } 

The GolfCourseService variable is instantiated once on page load here.

 private void Page_Load(object sender, System.EventArgs e) { gs = new localhost.GolfCourseService(); } private void Page_Init(object sender, EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Windows Form 
//Designer. // InitializeComponent(); } #region Web Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.Command1.Click += new
System.EventHandler(this.Command1_Click); this.Search.Activate += new
System.EventHandler(this.Form1_Activate); this.gcList.ItemCommand += new System.Web.UI.
MobileControls.ListCommandEventHandler(this.gcList_ItemCommand); this.Load += new System.EventHandler(this.Page_Load); } #endregion private void Form1_Activate(object sender, System.EventArgs e) { } private void Command1_Click(object sender, System.EventArgs e) {

This method is called when the user clicks the Submit button on the search form. The method sets the form's ActiveForm property to the SearchResult form. This action will cause the search result page to be returned to the client upon the completion of this method call. Next the method gathers the search criteria entered by the user and prepares the arguments required by the FindGeneric( ) Web method.

 this.ActiveForm = SearchResult; String[] fields = new String[5]; String[] values = new String[5]; fields[0] = "name"; string nameValue = Request.QueryString.Get("name"); if (nameValue == null || nameValue == "") { nameValue = "*"; } values[0] = nameValue; fields[1] = "city"; string cityValue = Request.QueryString.Get("city"); if (cityValue == null || cityValue == "") { cityValue = "*"; } values[1] = cityValue; fields[2] = "state"; string stateValue = Request.QueryString.Get("state"); if (stateValue == null || stateValue == "") { stateValue = "*"; } values[2] = stateValue; fields[3] = "country"; string countryValue = Request.QueryString.Get("country"); if (countryValue == null || countryValue == "") { countryValue = "*"; } values[3] = countryValue; fields[4] = "postalCode"; string postalCodeValue = Request.QueryString.Get("postalCode"); if (postalCodeValue == null || postalCodeValue == "") { postalCodeValue = "*"; } values[4] = postalCodeValue; 

The method calls the FindGeneric( ) Web method associated with the GolfCourseService Web Service. The Web method returns an array of GolfCourse objects, which are inserted into a List control on the Mobile Web Form.

 localhost.GolfCourse[] gc = gs.FindGeneric(fields,values); for (int i=0 ; i < gc.Length; i++) { gcList.Items.Add(gc[i].name); gcList.Items[i].Value = gc[i].id.ToString(); } } 

This event handler is called when the user selects one of the items from the list of golf courses returned by the search. Once again, the event handler switches the ActiveForm to the GolfCourseDetail page. The handler calls the GetCourseDetail( ) Web method to retrieve detailed information about the selected GolfCourse. The course details are loaded into the label controls that have been pasted on the GolfCourseDetail form. Finally the Call control's PhoneNumber property is set to the value of the course's telephone property. This feature lets the user auto-dial the golf course with the click of a button.

 private void gcList_ItemCommand(object source, System.Web.UI.
MobileControls.ListCommandEventArgs e) { ActiveForm = GolfCourseDetail; String gcid = e.ListItem.Value; localhost.GolfCourse gc = gs.GetCourseDetail(gcid); DetailName.Text = gc.name; DetailDescription.Text = gc.description; DetailAddress.Text = gc.address.street+"<br/>
"+gc.address.city+", "+gc.address.state+" "+gc.address.
postalCode+"<br/>"+gc.address.country; DetailTelephone.PhoneNumber = gc.telephone; } } }

Now let's move on to the search.aspx page. The forms themselves are straightforward. They are created by dragging Mobile Web Forms controls onto the page and editing their properties. Figure 13-4 shows how the Mobile Web Form looks after all of the controls have been inserted and positioned correctly.

Figure 13-4 All three Golf Reservation System Mobile Web Forms using the Mobile Explorer Toolkit.

Next we look at the XML source that lies beneath the GUI form display. Search.aspx contains all the mobile XML code the .NET Developer Studio creates for us.

 <%@ Register TagPrefix="mobile" Namespace="System.Web.UI.
MobileControls" Assembly="System.Web.Mobile" %> <%@ Page language="c#" Codebehind="Search.aspx.cs" Inherits=
"MobileClient.MobileWebForm1" AutoEventWireup="false" %> <meta content="Microsoft Visual Studio 7.0" name="GENERATOR"> <meta content="C#" name="CODE_LANGUAGE"> <meta content="Mobile Web Page" name="vs_targetSchema">

The search form contains the labels and text boxes needed to query the Golf Reservation System golf course database.

 <body xmlns:mobile="Mobile Web Form Controls"> <mobile:form  runat="server"> <P> <mobile:Label  runat="server">Course Name
</mobile:Label> <mobile:TextBox runat="server"></mobile:TextBox> <mobile:Label runat="server">City</mobile:Label> <mobile:TextBox runat="server"></mobile:TextBox> <mobile:Label runat="server">State</mobile:Label> <mobile:TextBox runat="server"></mobile:TextBox> <mobile:Label runat="server">Country</mobile:Label> <mobile:TextBox runat="server"></mobile:TextBox> <mobile:Label runat="server">Postal Code
</mobile:Label> <mobile:TextBox runat="server"></mobile:TextBox> <mobile:Command runat="server">Search</mobile:Command> </P> </mobile:form>

The SearchResult form contains only a single mobile List control, gcList. The list is populated at runtime with the results of the FindGeneric( ) Web method call.

 <mobile:form  runat="server"> <P> <mobile:List  Runat="Server"></mobile:List> </P> </mobile:form> 

The golf course detail form displays detailed information about a specific golf course. Notice the inclusion of the <mobile:Call> element. This control allows you to take advantage of a cell phone's dialing capability.

 <mobile:form  runat="server">  <P> <mobile:Label  runat="server" Font-Bold="True">
Name
</mobile:Label> <mobile:Label runat="server"></mobile:Label> <mobile:Label runat="server" Font-Bold="True">
Description
</mobile:Label> <mobile:Label runat="server">
</mobile:Label> <mobile:Label runat="server"
Font-Bold="True">Address</mobile:Label> <mobile:TextView runat="server"></mobile:
TextView> <mobile:Label runat="server" Font-Bold="True">
Telephone
</mobile:Label> <mobile:Call runat="server">
</mobile:Call> </P> </mobile:form> </body>

Figure 13-5 shows how this implementation looks on the Mobile Explorer.

Figure 13-5 The course search form shown inside the Mobile Explorer.

Certainly, the Mobile Explorer Toolkit is a useful tool for developing mobile clients quickly. The only downside to the product is that it forces you to assemble an entirely new library of Mobile Web Forms, often duplicating code you've written for other clients. This duplicate code base might become difficult to maintain over time.

Using The Golf Reservation System Skin Architecture

We will now explore an alternative implementation of a mobile Golf Reservation System client, one that uses the application's "skins" approach to UI design to incrementally provide WML support. The project requires two steps:

  1. Modify the controller.asp script to detect the browser type. If it supports WAP, load the WML skin and use it instead of the HTML skin for transforming the page content. The controller must also be sensitive to the content type of the result document. It must be set to text/vnd.wap.wml.
  2. Create a new XSLT skin targeted at WAP devices and place it in the /xslt directory of the Golf Reservation System client application. This skin will only produce WML code.

The required modification to the controller.asp script is trivial. We just need to add the following lines of code before loading the XSLT document:

 If InStr(1,Request.ServerVariables("ALL_HTTP"),"text/vnd.wap.wml",1) Then skin = "mobile" Response.ContentType = "text/vnd.wap.wml" End if 

This code will force the controller to load the "mobile" skin to perform the final page transformation, and sets the MIME type of the response to the correct setting. Note the over simplicity of the browser detection algorithm used here. It is used for demonstration purposes only.

The Golf Reservation System XML content follows an object-based schema instead of a presentation-based schema, which makes repurposing small devices much easier. Because our content and presentation layers are cleanly divided this way, we will be able to implement a mobile interface without making any changes to the content layer. Thus, the code that interacts with the business layer of the application will remain intact and will not need to be replicated.

To begin we need to create templates for structural elements in the Golf Reservation System client schema that are common to multiple pages. These elements include <document>, <header>, <section>, <form>, <input> (text and hidden), <choice>, <option>, <properties>, and <property>. With the exception of form, the templates in the WML skin will be extensively reduced versions of their HTML counterparts. We don't need to worry about building complicated tables to handle layout or aesthetic style sheets to make the client look pretty. We are striving for functionality, first and foremost.

As we see in Mobile.xsl, the <document> and <header> transformation templates act as little more than placeholders.

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
version="1.0"> <xsl:output method="xml" omit-xml-declaration="yes" indent="no" encoding="" doctype-public="-//WAPFORUM//DTD WML1.2//EN"
doctype-system="http://www.wapforum.org/DTD/wml12.dtd" /> <xsl:template match="document"> <wml> <xsl:apply-templates /> </wml> </xsl:template> <xsl:template match="header"> <xsl:apply-templates /> </xsl:template> <xsl:template match="header/title"></xsl:template> <xsl:template match="header/description"></xsl:template>

The form template needs to accommodate the WML form posting semantics. First it needs to create <do> and <go> tags to submit the form back to the server. The template must also create a <postfield> element for each <input> element that appears in the source document. Textual input fields are also transformed into WML <input> elements (Hidden inputs require no WML <input> element; their values are inserted directly into the corresponding <postfield> element).

 <xsl:template match="form"> <card  title="{.//header/title}"> <do type="accept" label="Accept"> <go href="{@action}"> <xsl:for-each select=".//input|.//choice"> <postfield name="{@name}"> <xsl:choose> <xsl:when test="@type='hidden'"> <xsl:attribute name="value"> <xsl:value-of select="@value" /> </xsl:attribute> </xsl:when> <xsl:otherwise> <xsl:attribute name="value">$(<xsl:value-of select="@name" />)</xsl:attribute> </xsl:otherwise> </xsl:choose> </postfield> </xsl:for-each> </go> </do> <p> <fieldset title="{section/header/title}"> <xsl:apply-templates select="section/*" /> </fieldset> </p> </card> </xsl:template> <xsl:template match="section[count(courseDetail) = 0]"> <card  title="{header/title}"> <p> <xsl:apply-templates /> </p> </card> </xsl:template> <xsl:template match="view"> <xsl:apply-templates /> </xsl:template> <xsl:template match="properties"> <xsl:apply-templates /> </xsl:template> <xsl:template match="property"> <xsl:value-of select="@description" /> <xsl:apply-templates /> <br /> </xsl:template> 

Here the template creates the WML input elements. The <choice> element in the source document is converted into a WML <select> element.

 <xsl:template match="input[@type='text']"> <input name="{@name}" value="{@value}" /> </xsl:template> <xsl:template match="choice"> <select name="{@name}"> <xsl:apply-templates /> </select> </xsl:template> <xsl:template match="option"> <option value="{@value}"><xsl:value-of select="." /></option> </xsl:template> 

These general tags are actually enough to handle the course search view. Let's load the view into the Mobile Explorer and see the results. The URL should be http://localhost/GolfReservationSystemClient/controller.asp?view=courseSearch.

Figure 13-6 shows the course search page on the Mobile Explorer.

Figure 13-6 The course search view shown in the Mobile Explorer.

Transforming the courseSearchResult view is just as easy. All we have to do is match the template and create hyperlinks for all of the <courseListItem> elements. We will also show the course's city and state below each link.

WAP devices have a larger degree of freedom when rendering WML than browsers do when rendering HTML. Various device restrictions make strict specification of presentation rules impossible. For example, identical <select> lists can appear entirely different on two different WAP devices.

 <xsl:template match="courseList"> <xsl:apply-templates /> </xsl:template> <xsl:template match="courseListItem"> <a href="controller.asp?view=courseDetail&amp;id={id}"> <xsl:value-of select="name" /> </a> <br /> <xsl:value-of select="city" />, <xsl:value-of select="state" /><br /> </xsl:template> 

Figure 13-7 illustrates what this page looks like on a mobile device. The page can be reached by submitting the course search form.

Figure 13-7 The course search result view shown in the Mobile Explorer.

The courseDetail template is responsible for laying out specific course information in an organized fashion. This template will create a deck with two cards in it: one to show the course's information and another to request a tee time. The courseDetail XML content page contains another section describing hole yardages and difficulty, but the mobile skin ignores this information as it is too big to display neatly on a small screen and is not critical to the page.

The teetime reservation form is generated automatically by the <form> transformation logic we looked at earlier. We do need to supply a link to the card, though. The <do> and <go> tags in the following listing prepare the hyperlink in the result WML document.

 <xsl:template match="section[count(courseDetail) > 0]"> <xsl:apply-templates select="courseDetail" /> </xsl:template> <xsl:template match="courseDetail"> <xsl:for-each select="courseDetailBlock"> <xsl:if test="courseItem[@type != 'holeInfo']"> <card  title="{@description}"> <do type="accept" label="Schedule a Tee Time"> <go href="#{generate-id(//form)}" /> </do> <xsl:apply-templates /> </card> </xsl:if> <xsl:if test="form"> <xsl:apply-templates /> </xsl:if> </xsl:for-each> </xsl:template> 

Here we extract the name and address of the course for viewing.

 <xsl:template match="courseItem[@type='courseInfo']"> <p> <xsl:value-of select="//courseDetail/name" /><br /> <xsl:value-of select="address/address1" /><br /> <xsl:value-of select="address/city" />, <xsl:value-of select="address/state" /> <xsl:value-of select="address/postalCode"/>
<br /> <xsl:value-of select="address/country" /> </p> </xsl:template>

Figure 13-8 shows the tee time scheduling screen.

Figure 13-8 The tee time scheduling screen, the second card in the course detail deck, shown on the Mobile Explorer.

The teeTimes view displays a list of available tee times on the selected date and course. Each list item is wrapped inside a hyperlink to the scheduleTeeTime page. The anchor tag passes in all the tee time, course, and golfer information.

 <xsl:template match="view[teeTimes]"> <xsl:apply-templates select="teeTimes" /> </xsl:template> <xsl:template match="teeTimes"> Choose a time below<br /> <xsl:for-each select="teeTime"> <xsl:if test="not(taken)"> <a href="controller.asp?view=scheduleTeeTime&amp;golferId={../golferId}&amp;courseId={../courseId}&amp;teeTime={teeTimeSystemDate}"><xsl:value-of select="date" /> - <xsl:value-of select="time" 
/></a><br /> </xsl:if> </xsl:for-each> </xsl:template>

The teeTimes view is shown in Figure 13-9.

Figure 13-9 The viewTeeTimes page shown in the Mobile Explorer.

Finally, assuming everything posts correctly, we show the user a friendly note of success. The teeTimeDetail page also reviews the tee time's logistics.

 <xsl:template match="teeTimeDetail"> A new tee time has been created for:<br/> <xsl:value-of select="golfer/name"/><br/> <xsl:value-of select="course/name"/><br/> <xsl:value-of select="date"/> <xsl:value-of select="time"/> </xsl:template> </xsl:stylesheet> 

The primary advantage to the skin approach is that we get to preserve all the logic and content that went into the original HTML client. We did not need to rewrite any XML Web services code, as all our interaction was limited to the data coming out of the content layer.

For a production system this example should be extended to use the Content Adapter model discussed earlier. This action would provide maximum flexibility and control over style and layout. The Golf Reservation System client skin library can be augmented with new transformations for voice or television.



XML Programming
XML Programming Bible
ISBN: 0764538292
EAN: 2147483647
Year: 2002
Pages: 134

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net