My XML, Your Browser

 

Charlie Heinemann
Microsoft Corporation

January 11, 1999

Click here to download the source code for this article from the Downloads Center.

Contents

ASP Technology to the Rescue
Save Time, Too

Sometime between the holiday turkey and the turkey soup, I polished off a Web-based scheduling application that utilized the new XML functionality within Internet Explorer 5. Proud of myself, I phoned up a colleague and had him take a look. He was a little annoyed at my timing, but he nevertheless humored me and took a peak at my new site. He wasn't very impressed.

I sat dumbfounded for a couple of seconds, and then realized why he was not as elated as I was: He wasn't running Internet Explorer 5 on his home machine. Upon this epiphany, I hung up and began work on a version of my Web site that would be friendlier to other browsers.

To give you an idea of what I did, I'll explain a particular page that was not showing up in my colleague's browser. This page is fairly simple. It downloads an XML file and an XSL style sheet, puts them together, and displays the HTML that results. The XML file contains basic information about a day's meetings:

<schedule date="1/22/99">
  <meeting>
    <start-time>09:00</start-time>
    <end-time>10:30</end-time>
    <location>1020/3</location>
    <attendees>
      <attendee>
        <name>John Jackson</name>
        <email>johnJa</email>
      </attendee>
      <attendee>
        <name>Regina Caplan</name>
        <email>regCap</email>
      </attendee>
    </attendees>
    <subject>HeffHousen deal</subject>
  </meeting>
  <meeting>
    <start-time>16:30</start-time>
    <end-time>18:00</end-time>
    <location>1020/3</location>
    <attendees>
      <attendee>
        <name>Calvin Richards</name>
        <email>calvinr</email>
      </attendee>
      <attendee>
        <name>John Jackson</name>
        <email>johnJa</email>
      </attendee>
      <attendee>
        <name>Regina Caplan</name>
        <email>regCap</email>
      </attendee>
    </attendees>
    <subject>How the HeffHousen deal
      fits into our general strategy</subject>
  </meeting>
  <meeting>
    <start-time>13:00</start-time>
    <end-time>16:00</end-time>
    <location>1037/3</location>
    <attendees>
      <attendee>
        <name>Calvin Richards</name>
        <email>calvinr</email>
      </attendee>
    </attendees>
    <subject>General strategy</subject>
  </meeting>
</schedule>

Using the "order-by" attribute, the XSL style sheet sorts the meeting nodes by time. It then displays the information within the meeting nodes as indicated. The "xsl:for-each" element is used to ensure that each meeting node is processed and each attendee node for each meeting is processed:

<HTML xmlns:xsl="http://www.w3.org/TR/WD-xsl">
  <BODY STYLE="font-family:Arial, helvetica,
    sans-serif; font-size:12pt;
        background-color:#EEEEEE">
    <DIV STYLE="font-weight:bold;font-size=16pt">
      <xsl:value-of select="@date"/>
    </DIV>
    <xsl:for-each select="meeting" order-by="+ start-time">
      <DIV STYLE="background-color:#8B0000;
        color:#FFFFFF; padding:4px">
        <SPAN STYLE="font-weight:bold; color:white">
          <xsl:value-of select="start-time"/>
        - <xsl:value-of select="end-time"/>
          Subject: <xsl:value-of select="subject"/></SPAN>
      </DIV>
      <DIV STYLE="font-weight:bold">LOCATION:
        <xsl:value-of select="location"/>
        </DIV>
      <DIV STYLE="font-weight:bold">ATTENDEES: </DIV>
        <xsl:for-each select="./attendees/attendee">
          <DIV STYLE="text-indent:1cm">
            <xsl:value-of select="name"/>
            </DIV>
        </xsl:for-each>
    </xsl:for-each>
  </BODY>
</HTML>

In the original page, I used the following HTML to display the XML according to the XSL style sheet:

<HTML>
  <BODY>
    <XML ID="XMLDoc"></XML>
    <XML ID="XSLDoc"></XML>
    <DIV ID="insertHTML"></DIV>
    <SCRIPT LANGUAGE=VBScript>
      XMLDoc.async = false
      XMLDoc.load("schedule.xml")
      XSLDoc.async = false
      XSLDoc.load("schedule.xsl")
      result = XMLDoc.documentElement.transformNode
        (XSLDoc.documentElement)
      insertHTML.innerHTML = result
    </SCRIPT>
  </BODY>
</HTML>

This produces the following in the browser:

That's if you are running Internet Explorer 5. If you aren't—as in the case of my colleague—you will instead see an error, because the browser will not have the proper XML support. I could have solved this problem by hard-coding the data into an HTML file. However, I would then have to maintain both the XML and the HTML files. It would be better if, in those situations where the client is running a browser other than Internet Explorer 5, I could dynamically create the proper HTML on the server and simply ship that down. So that is what I did.

ASP Technology to the Rescue

First, I made the HTML file an ASP file and wrote a little script that would sniff out whether the client was running Internet Explorer 5:

<%@Language=VBScript%>
<%
client = Request.ServerVariables("HTTP_USER_AGENT")
version = Split(client,";",-1,1)

Within the HTTP header sent by the client is the variable HTTP_USER_AGENT. This variable contains information about the client, such as its type and version. Because my machine is running Internet Explorer 5, the HTTP_USER_AGENT variable is set to "Mozilla/4.0 (compatible; MSIE 5.0b2; Windows NT; ITG-IE401SP1)". The version of the browser is stated in the text after "compatible;". I therefore use the Split function in Visual Basic® Scripting Edition (VBScript) to parse out the string and retrieve the text providing the browser information.

In this specific case, I sniff to see whether the browser is Internet Explorer 5. If it is, I allow the client machine to download and process the XML and XSL files. If it is not, I do the processing on the server and ship the results down to the client as an HTML string:

IF version(1) = " MSIE 5.0b2" Then%>
  <HTML>
    <BODY>
      <XML ID="XMLDoc"></XML>
      <XML ID="XSLDoc"></XML>
      <DIV ID="insertHTML"></DIV>
      <SCRIPT LANGUAGE=VBScript>
        XMLDoc.async = false
        XMLDoc.load("schedule.xml")
        XSLDoc.async = false
        XSLDoc.load("schedule.xsl")
        result =
          XMLDoc.documentElement.transformNode
           (XSLDoc.documentElement)
        insertHTML.innerHTML = result
      </SCRIPT>
    </BODY>
  </HTML>
<%
Else
  Set XMLDoc = Server.CreateObject("Microsoft.XMLDOM")
  Set XSLDoc = Server.CreateObject("Microsoft.XMLDOM")
  XMLDoc.async = false
  XMLDoc.load(Server.MapPath("schedule.xml"))
  XSLDoc.async = false
  XSLDoc.load(Server.MapPath("schedule.xsl"))
  response.write(XMLDoc.documentElement.transformNode
    (XSLDoc.documentElement))
End IF
%>

Having the above ASP file serves two purposes. First, it allows me to display my XML and have clients running browsers other than Internet Explorer 5 view that data. Second, it allows those clients running Internet Explorer 5 to download and process the XML and XSL themselves. This is beneficial to the server, because it frees up valuable server resources. This is also beneficial to the client, because it allows the client to cache the XML and XSL. Consequently, when the XML and XSL are reused in other contexts, the data will not have to be reloaded from the server.

Save Time, Too

Local caching of the data could save quite a bit of time, particularly when presenting multiple views of the same data. For instance, what if we wanted a slimmed-down version of the above schedule—say, one that gives only meeting times and subjects. For clients running other than Internet Explorer 5, we would have to process each view on the server. This means loading the XML and XSL each time. For clients running Internet Explorer 5, however, we could simply apply a different XSL style sheet on the client. It would still cost us the time necessary to load the XSL, but we wouldn't have to load the XML over again.

Charlie Heinemann is a program manager for Microsoft's Weblications team. Coming from Texas, he knows how to think big.