Using XSL to Present XML Documents

[Previous] [Next]

Extensible Stylesheet Language (XSL) is closely related to XML and can be used for a multitude of purposes. Although there are similarities between XSL and the Cascading Style Sheets (CSS) that are used to format HTML pages, there are also important differences.

In this chapter, we don't have room to cover a huge subject such as XSL in detail, especially since we must talk about several other things related to XML. So all we can really do is rake over the surface of XSL. But that should be more than enough to give you an idea of how XSL could be of use to you. We'll concentrate on one type of use only, namely the presentation on Web pages of XML documents, but we remind you that this use is one out of many possible.

We'll use the following hierarchical XML document as the example in the XSL section of this chapter:

<?xml version="1.0" encoding="windows-1252" ?> <XML xmlns:dt="urn:schemas-microsoft-com:datatypes"> <Racedays> <Raceday> <Date>25 May 1999</Date> <Track>Täby Galopp</Track> <Races> <Race> <Raceno>1</Raceno> <Distance>1600</Distance> <Class>Gold</Class> </Race> <Race> <Raceno>2</Raceno> <Distance>1150</Distance> <Class>Listed</Class> </Race> <Race> <Raceno>3</Raceno> <Distance>1950</Distance> <Class>Amateur</Class> </Race> </Races> </Raceday> <Raceday> <Date>2 June 1999</Date> <Track>Täby Galopp</Track> <Races> <Race> <Raceno>1</Raceno> <Distance>1600</Distance> <Class>Gold</Class> </Race> <Race> <Raceno>2</Raceno> <Distance>1950</Distance> <Class>Listed</Class> </Race> </Races> </Raceday> </Racedays> </XML> 

Looking closely at the content of this document, you can see that it contains one element named Racedays. This element in turn contains two subelements of the Raceday element type. Notice the use of singular and plural here, just as in an object model containing one collection object named Racedays, and that collection containing a number of individual Raceday objects. Also notice that each Raceday element contains one Date element, one Track element, and one Races element. The Races element is a collection that contains a number of Race elements, each Race element containing three elements that define the number of the race, the distance of the race, and the class of the race. Figure 20-12 shows the result of opening in Internet Explorer a file containing this document.

click to view at full size.

Figure 20-12. A hierarchical XML document, opened as a file in Internet Explorer.

Our first XSL example features this XML document and an XSL stylesheet that's interesting in a special way. We'll use XSL not only to decide how information should be presented but also to decide which parts of the information available in the XML document to present.

Using the First XSL Stylesheet

Let's first show you the result of a test run in Figure 20-13, using the same XML document we used in Figure 20-12 and an XSL stylesheet soon to be presented.

click to view at full size.

Figure 20-13. An XSL stylesheet has been used here to show just the date and the track name for two racing days, hiding the details of races run on those days.

Notice that only the date and the track name of each race day are shown. All the detailed information about individual races and horses running in them that's available in the XML document is suppressed. Let's take a look at the HTML code used to present the information shown in Figure 20-13:

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <style> <!-- tr { font-family: Verdana; font-size: 10pt; font-weight: normal } --> </style> <HEAD> <SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onload"> var source = new ActiveXObject("Microsoft.xmldom"); source.load("RaceDays.xml"); var style = new ActiveXObject("Microsoft.xmldom"); style.load("RaceDays1.xsl"); document.all.item("xslContainer").innerHTML = source.transformNode(style.documentElement); </SCRIPT> <TITLE>XML with XSL</TITLE> </HEAD> <BODY> <DIV ID="xslContainer"></DIV> </BODY> </HTML> 

This is all the HTML and JavaScript code needed for this example. The rest comes from the XML document and the XSL stylesheet. As shown by the script embedded in the previous HTML page, the XML document stored in the Racedays.xml file loads into the XML DOM referenced by the source variable. There's nothing new about that: you've seen such code before in this chapter. What is new is that this page makes use of another XML DOM object, referenced by the style variable. This object loads the XSL stylesheet contained in the Racedays1.xsl file.

Even though there's so little script code in this file, the script code totally dominates it. There's very little HTML too. The body segment, in fact, contains only one element—a DIV element named xslContainer. It's to the innerHTML property of that DIV element that the last script line sends the result of calling the transformNode method of the DOM object that contains the XSL stylesheet. Let's briefly talk about the work that the transformNode method does.

The transformNode method's job is to send the entire XML document loaded in the first XML DOM object through the XSL stylesheet that's loaded in the second XML DOM object. The result is flown out as ordinary HTML text to the innerHTML property of the specified DIV element. The result is exactly what you saw in Figure 20-13. It's completely up to the XSL stylesheet to determine which parts of the XML document should be displayed, and the XSL stylesheet also determines the form of the presentation. Here's the content of the stylesheet used for this example:

<?xml version="1.0" encoding="windows-1252" ?> <xsl:stylesheet xmlns:xsl="uri:xsl"> <xsl:template match="/"> <HTML> <BODY> <P><FONT face='Verdana' size='3' color='maroon'><STRONG>Racedays</STRONG> </FONT></P> <TABLE border = '0'> <TR style = 'font-family:Verdana; font-size: 10pt; font-weight:bold'> <TD>Date</TD> <TD>Track</TD> </TR>  <xsl:for-each select ="XML/Racedays/Raceday"> <TR> <TD bgcolor="#FFCC66"> <xsl:value-of select="DATE"/></TD> <TD bgcolor="#FFCC66"> <xsl:value-of select="TRACK"/></TD> </TR> </xsl:for-each> </TABLE> </BODY> </HTML> </xsl:template> </xsl:stylesheet> 

Two concepts often used in connection with XSL are template and pattern. We'll briefly explain both, but only by giving you a few examples. The third line from the top of the code sample specifies a template. Every XSL stylesheet must contain at least one template, but it can contain as many templates as you need. An XSL template always specifies which parts of the XML document the content of the template should match. In this case, the "/" symbol is used, representing the root element. This template, then, is to be used throughout the entire XML document, not only for some inner part of it.

After the template matching the root element comes a segment of HTML. This segment is just carried over to the HTML page that the transformNode method is creating. If not the most exciting part of the XSL stylesheet, this part still creates an HTML table and also its first row, making that first row into a table heading. The next part of the stylesheet, printed in boldface type, is much more interesting. It begins with an XSL for-each structure, using the select keyword to specify what's going to be executed within the for-each loop. The for-each structure is an XSL pattern, the second concept we mentioned right after showing the content of the XSL stylesheet used here. This very pattern in effect says, "For each Raceday element that's part of a Racedays element that's part of the XML root element of this document, do what follows until my end tag." The end tag, of course, is the </xsl:for-each> tag that corresponds to the <xsl:for-each select ="XML/Racedays/Raceday"> tag. The end tag also defines the end of the pattern.

Inside the for-each pattern, you can see HTML code that creates one table row (<TR>) and two table cells (<TD>). You can also see two other XSL patterns, both of which are value patterns. The first of them retrieves the date value from the XML document, putting it in the first table cell; the second retrieves the track name and puts it in the second cell.

Taking a new look at the XML document, you can easily see that inside every Raceday element there are several other elements. Because there's no XSL pattern retrieving these elements, the HTML page doesn't display them. The XSL stylesheet, then, has decided not only which parts of the XML document to show but also that the parts shown should be shown as a table with rows and cells. And it has dynamically created an HTML page that does exactly what the stylesheet wants it to do.

Using the Second XSL Stylesheet

Our next example uses the same HTML page and the same XML document but a different XSL stylesheet. Reconsidering this statement, there's one small bit of difference in the HTML page; it loads the XSL stylesheet we want to use in this example rather than the one we used in the preceding example. Running the second example renders a different result, as shown in Figure 20-14.

click to view at full size.

Figure 20-14. The same HTML page, the same XML document, a different XSL stylesheet.

As you can see in Figure 20-14, the second XSL stylesheet goes deeper; it shows information not only about the race days but also about the races run on each day. Here follows that second XSL stylesheet:

<?xml version="1.0" encoding="windows-1252" ?> <xsl:stylesheet xmlns:xsl="uri:xsl"> <xsl:template match="/"> <HTML> <BODY> <P><FONT face='Verdana' size='3' color='maroon'><STRONG>Racedayswith Races </STRONG></FONT></P> <TABLE border = '0'> <TR style = 'font-family:Verdana; font-size: 10pt; font-weight:bold'> <TD>Date</TD> <TD>Track</TD> </TR> <xsl:for-each select ="XML/Racedays/Raceday"> <TR> <TD bgcolor="#FFCC66"> <xsl:value-of select="DATE"/></TD> <TD bgcolor="#FFCC66"> <xsl:value-of select="TRACK"/></TD> </TR> <TR> <TD colspan='2'> <TABLE border='0'> <TR style = 'font-family:Verdana; font-size: 8pt; font-weight:bold'> <TD width='10'></TD> <TD>Race</TD> <TD>Distance</TD> <TD>Class</TD> </TR>  <xsl:for-each select ="Races/Race"> <TR> <TD></TD> <TD bgcolor="#FFCCCC"> <xsl:value-of select="Raceno"/> </TD> <TD bgcolor="#FFCCCC"> <xsl:value-of select="Distance"/> </TD> <TD bgcolor="#FFCCCC"> <xsl:value-of select="Class"/> </TD> </TR> </xsl:for-each> </TABLE> </TD><TD></TD> </TR> </xsl:for-each> </TABLE> </BODY> </HTML> </xsl:template> </xsl:stylesheet> 

The code doing the trick here is, as usual, the code printed in boldface type—what a coincidence. This code defines yet another for-each-select pattern, this one looping through "each Race element that's part of a Raceday element that's part of a Racedays element that's part of the XML root element of this document." The race pattern doesn't specify the "XML/Racedays/Raceday" part of the select statement, only the "Races/Race" part; the position of the second pattern, inside the first pattern, makes the second pattern relative to the first.

Multiple Templates in the Same XSL Stylesheet

The following example gives exactly the same result as the preceding one. We use the same HTML page and the same XML document; the only difference is the structure of the XSL stylesheet. Rather than using one single template, using the "/" symbol to specify the root element, we use multiple templates.

<?xml version="1.0" encoding="windows-1252" ?> <xsl:stylesheet xmlns:xsl="uri:xsl">  <xsl:template match="/"> <HTML> <BODY> <P><FONT face='Verdana' size='3' color='maroon'> <STRONG>Racedayswith Races </STRONG></FONT> </P> <TABLE border = '0'> <TR style = 'font-family:Verdana; font-size: 10pt; font-weight:bold'> <TD>Date</TD> <TD>Track</TD> </TR> <xsl:for-each select ="XML/Racedays/Raceday"> <TR> <TD bgcolor="#FFCC66"> <xsl:value-of select="Date"/></TD> <TD bgcolor="#FFCC66"> <xsl:value-of select="Track"/></TD> </TR> <TR> <TD colspan='2'> <TABLE border='0'> <TR style = 'font-family:Verdana; font-size: 8pt;font-weight:bold'> <TD width='10'></TD> <TD>Race</TD> <TD>Distance</TD> <TD>Class</TD> </TR>  <xsl:for-each select ="Races"> <xsl:apply-templates/> </xsl:for-each> </TABLE> </TD> <TD></TD> </TR> </xsl:for-each> </TABLE> </BODY> </HTML> </xsl:template>  <xsl:template match="Race"> <TR> <TD></TD> <TD bgcolor="#FFCCCC"> <xsl:value-of select="Raceno"/> </TD> <TD bgcolor="#FFCCCC"> <xsl:value-of select="Distance"/> </TD> <TD bgcolor="#FFCCCC"> <xsl:value-of select="Class"/> </TD> </TR> </xsl:template> </xsl:stylesheet> 

Three parts of this stylesheet are printed in boldface type. The following list comments on each of the three parts:

  • The first part in boldface type is the original template, specifying the root element as the object of the stylesheet. We highlighted this template only to emphasize that it's still there.
  • The third part, at the bottom of the stylesheet, specifies a second template that identifies each particular race as a match for the code of the template. The code in this template is the same as in the preceding stylesheet; the only difference is that it has been removed from one template, thereby making that template less complex, and placed in a template of its own, equally simple in structure.
  • The second part, near the middle of the stylesheet, defines a pattern using <xsl:apply-templates> to apply all the templates defined at the bottom of the stylesheet. In this particular stylesheet there's only one such pattern, but in an application of greater complexity than our example's, you could have several such templates. Each of them would be applied, one after the other. The effect, of course, of applying the templates is the execution of any template that makes sense to execute at the time its template is applied.

As we already said, the result of using this stylesheet is exactly the same as using the one that precedes it. We think that the most important advantage of using it is that the code in an XSL stylesheet that features multiple templates tends to be better structured than the code in an XSL stylesheet featuring a single template. Therefore, in general it's easier to make such a stylesheet work as it should, it's easier to understand what it's supposed to do (and why it doesn't do it), and it's easier to maintain and also to enhance it.



Designing for scalability with Microsoft Windows DNA
Designing for Scalability with Microsoft Windows DNA (DV-MPS Designing)
ISBN: 0735609683
EAN: 2147483647
Year: 2000
Pages: 133

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