Back Contents Next

XSL Stylesheets

XML documents can contain actual XML data or a query that will be executed to retrieve the XML data from SQL Server. We have seen how XML data is displayed in a browser from the examples that we have executed. While the data displayed is well formed and we can identify the various elements in the XML document, it really does not provide the type of data that we would want to display in a browser.

 

XSL helps solve this problem; it is an acronym for Extensible Stylesheet Language and describes the way that XML data should be formatted and displayed. Like XML, XSL also uses tags to describe and format the XML data. Each tag has a corresponding closing tag that begins with a forward slash (/). XSL, like XML, uses strict formatting standards to create well-formed documents.

 

Using XSL we can define a stylesheet. This can contain an entire HTML document within the XSL document. The HTML is intermixed with XSL elements and will be merged with the resulting XML data to form a completed HTML document that will be displayed in a browser.

 

An XSL file is like an XML file, but for stylesheets, and must begin with the XML declaration. The following code fragment shows the beginning of an XSL stylesheet:

 

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

<xsl:template match = "/">

 

The first line of code here is the XML declaration, which is included as the first line of every XML document.

 

The next line of code is the <xsl:stylesheet> element that defines this XML document as an XSL stylesheet. It should be noted here that your XSL stylesheets will have a .xsl file extension. Within the <xsl:stylesheet> element we have declared a namespace of xmlns:xsl=http://www.w3.org/TR/WD-xsl. This is the standard namespace supported by Microsoft Internet Explorer 5.0. A namespace allows you to declare elements of a certain namespace and differentiate these elements from others of the same name. In other words you can specify a collection of names that can be used as element or attribute names in your document.

At this point it is worth noting that, like XML, XSL is also case sensitive. This includes the elements themselves and their attributes.

Following the <xsl:stylesheet> element we declare the <xsl:template> element to indicate that the stylesheet template corresponds to the root element of the XML document. We are going to look at how to use templates in a little while.

 

These three lines of code are the standard beginning of every XSL stylesheet that you will create. Keep in mind that the <xsl:stylesheet> and <xsl:template> elements require a closing tag at the end of the stylesheet, as shown:

 

</xsl:template>

</xsl:stylesheet>

 

The XSL language provides many elements that help us to process and display XML data. We can even include VBScript or JScript/JavaScript in our XSL stylesheets, although that is beyond the scope of this chapter. At the core of XSL is the <xsl:for-each> element that sets up a loop for processing XML data.

This element accepts the select attribute, which specifies the XSL pattern for the node of XML data to be iterated. A node is an element in the XML tree structure that has links to one or more nodes below it. An example of this is shown in the next code fragment:

 

<xsl:for-each select="Employees/Employee_T">

 

The nodes that we have specified in the select attribute specify the root node of Employees and a sub node of Employee_T. Let's take a look again at the figure we saw earlier. The root node is listed as Employees and the sub-node under the root is listed as Employee_T, which is the name of our table. SQL Server placed this node name here automatically for us and derived the name from the table name.

 

 

 

 

Notice that for each Employee_T node there are several XML attributes that we want to process, such as Employee_ID, First_Name_VC, and Last_Name_VC. These are processed using the <xsl:value-of> element.

 

The code fragment below shows how we use the <xsl:value-of> element. The select attribute specifies the pattern to match and the data from this match is then inserted as a text string into your document. Because our data is being generated from SQL Server we must specify the 'at' sign (@) before the element name to be matched. After the pattern name we include a forward slash to indicate the closing of this element.

 

<xsl:value-of select="@Employee_ID "/>

<xsl:value-of select="@First_Name_VC"/>

<xsl:value-of select="@Last_Name_VC"/>

 

This demonstrates the point made earlier; remember that while all XML and XSL elements require a closing tag, we can sometimes specify a forward slash at the end of the element to indicate a closing tag for that element, such as we have done in the previous code fragment.

 

Try It Out XSL Stylesheet

Now that we know the basic elements that make up an XSL stylesheet, let's create one to display the first and last name of all employees from the Employee_T table.

 

1.       To create this stylesheet you can use any text editor you want; the complete code for this XSL stylesheet is listed below:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

<xsl:template match = "/">

<HTML>

<HEAD>

<STYLE>

TH

{

background-color: #CCCCCC;

}

</STYLE>

</HEAD>

<BODY>

<TABLE Border="1">

<TR>

<TH ColSpan="2">Hardware Tracking Employees</TH>

</TR>

<TR>

<TH>First Name</TH>

<TH>Last Name</TH>

</TR>

<xsl:for-each select="Employees/Employee_T">

<TR>

<TD><xsl:value-of select="@First_Name_VC"/></TD>

<TD><xsl:value-of select="@Last_Name_VC"/></TD>

</TR>

</xsl:for-each>

 

</TABLE>

</BODY>

</HTML>

</xsl:template>

</xsl:stylesheet>

 

2.       Once you have entered the code save the stylesheet in the htData directory as Employee.xsl. On my machine I created the htData directory under the \Inetpub\wwwroot\ directory.

3.       We can test this XSL stylesheet by running another query in the URL of our web browser. Enter the following URL in your browser and press the Enter key:

http://localhost/htData?SQL=SELECT+First_Name_VC,+Last_Name_VC+FROM+Employee_T+FOR+XML+AUTO&XSL=Employee.xsl&ContentType=Text/HTML&Root=Employees

 

You should now see results similar to those shown in the following screenshot:

 

How It Works XSL Stylesheet

As we mentioned earlier, the first three lines of our stylesheet are standard. The first line is the XML declaration and is required to identify this as an XML document so it can be parsed correctly by the browser. The second line is the <xsl:stylesheet> element that defines this XML document as an XSL stylesheet. The third line contains the <xsl:template> element and specifies that the stylesheet should match all elements starting at the root element of the XML document:

 

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

<xsl:template match = "/">

 

Now we start defining an HTML document within our XSL stylesheet. This will cause an HTML document to be generated using HTML elements and XML data. The first thing we do here is to specify the <HTML> tag, which signifies the beginning of an HTML document. Then we specify the <HEAD> tag, which specifies information about the HTML document:

 

<HTML>

<HEAD>

 

The <STYLE> element defines an in-line cascading stylesheet within the HTML document. A cascading stylesheet is a set of styles (such as font size, font color) that are defined in the HTML document and that can be applied to any HTML element. So we can use the styles we define here throughout our HTML document.

<STYLE>

 

The first style that is defined is one that is automatically applied to the table header, <TH>, element. The style object is given a name of TH and the properties of this style are enclosed in curly brackets ({}). Here we have set the background-color property to a color of #CCCCCC, a light shade of gray. This property has been terminated with a semicolon. Each property that we set in our style object must be terminated with a semicolon.

 

When setting properties that change the color of the background or text, we can specify the

RGB (Red-Blue-Green) value, as we have done here, or specify the color name. However, be aware that not all browsers recognize color names, while they should recognize all the RGB value for a color, so it is a good habit to specify the RGB value.

 

TH

{

background-color: #CCCCCC;

}

 

Since this is the only style that we want to define we specify the closing tags for the <STYLE> and <HEAD> elements. Then we begin the body of the HTML document by specifying the <BODY> tag:

 

</STYLE>

</HEAD>

<BODY>

 

The first thing that we specify in the body of our HTML document is a table. Using a table helps keep the data that we want to display aligned correctly in rows and columns. Using the <TABLE> element we specify that a table should be drawn and we set the Border attribute to a value of 1. This specifies that a one-pixel border is to be drawn in and around the table.

 

We define a row in a table by specifying the <TR> tag, which begins a row of data in a table. Then we specify that a column header be placed in this row by specifying the <TH> tag. We set the ColSpan attribute to a value of 2, which indicates that this column header will span two columns of the table. Then we place the text to be displayed in the column header and close the column header by specifying the closing tag for the <TH> element. Next we specify the closing tag for the table row:

<TABLE Border="1">

<TR>

<TH ColSpan="2">Hardware Tracking Employees</TH>

</TR>

 


The next row in our table specifies the column headers for each column. The first column in our table will contain the employee's first name and the second column in our table will contain the employee's last name:

<TR>

<TH>First Name</TH>

<TH>Last Name</TH>

</TR>

 

Now we want to iterate through the nodes in our XML data. Using the XSL <xsl:for-each> element we iterate through the Employees/Employee_T node of our XML data. For each iteration through the Employees/Employee_T node we specify that a row of HTML data be built, by specifying the opening <TR> tag:

<xsl:for-each select="Employees/Employee_T">

<TR>

 

Within the table row we want to specify two columns as indicated by the <TD> element. This HTML element specifies that a cell in the table be built. Within this cell we have specified the XSL <xsl:value-of> element to select the data in the First_Name_VC element of our XML data. The <xsl:value-of> element will place the data contained in the element that it selects in the table cell. Then we close the table cell using the closing tag of the <TD> element.

 

We end the row of data in our table by specifying the closing tag of the table row and the closing tag of the XSL <xsl:for-each> element, which defines the end of the code within the loop:

<TD><xsl:value-of select="@First_Name_VC"/></TD>

<TD><xsl:value-of select="@Last_Name_VC"/></TD>

</TR>

</xsl:for-each>

 

Next, we end the table and the body of our HTML document and then the HTML document itself. We have done this by specifying the appropriate closing tags:

 

</TABLE>

</BODY>

</HTML>

 

Finally, we end our XSL stylesheet by specifying the closing tags for the XSL </xsl:template> element and the </xsl:stylesheet> element. It should be noted that the <?xml> element is the only element that does not have a corresponding closing tag.

</xsl:template>

</xsl:stylesheet>

 

Let's take a look at the URL that we entered to produce the results shown earlier. The first part of this URL should look familiar as it is the same data that we that we entered before, except that we have not included the Employee_ID column in the SELECT statement:

 

 

http://localhost/htData?SQL=SELECT+First_Name_VC,+Last_Name_VC+FROM+Employee_T+FOR+XML+AUTO

 

The last part of this URL is new, as we have specified the XSL keyword and the XSL stylesheet that we created. We have also specified the ContentType keyword and specified that our results should be displayed as Text/HTML. The Root keyword is the same that we used in the last URL.

 

&XSL=Employee.xsl&ContentType=Text/HTML&Root=Employees

 

If you are curious, you can right-click in the browser window and choose View Source from the context menu to view the HTML that was generated by the XSL stylesheet.

Sorting Data Using XSL

The results that were displayed in the last example were not sorted. They were displayed in the same order as they were entered in the Employee_T table. We have a choice when sorting data; either use the ORDER BY clause in our SELECT statement, or use the order-by attribute of the <xsl:for-each> element.

 

Since we are already familiar with the ORDER BY clause in SQL Server let's examine the order-by attribute of the XSL <xsl:for-each> element. Using this attribute allows us to sort the XML data that has been returned by SQL Server in our XSL stylesheet.

 

The order-by attribute allows us to specify the sort criteria using one or more XSL patterns, in other words nodes in our XML data. An XSL pattern provides a mechanism to identify nodes in our XML document based on their type, name or values. The sort criterion is a string value enclosed by quotes and each XSL pattern to be sorted is separated by a semicolon. To indicate the direction of the sort, ascending or descending, you must include a plus sign (+) or a minus sign (-) respectively. Like most sorts that you have dealt with, ascending is the default and need not be specified if this is the sort order required.

 

Suppose we want to sort our data by ascending order of first names, and then by descending order of last names. We could specify the order-by attribute as shown in the code fragment below. The first names would be sorted first in ascending order and then, if there were two identical first names, the last names for the identical first name would be sorted in descending order:

 

<xsl:for-each select="Employees/Employee_T"

order-by="+@First_Name_VC; -@Last_Name_VC">

 

It should be noted that the order-by attribute is set to become an obsolete standard, although it will still be supported. Future releases of XSL by the W3C (World Wide Web Consortium) will supply the <xsl:sort> element in its place. Until the next release of XSL we should continue to use the order-by attribute of the <xsl:for-each> element.

Using XSL Templates

We used a template in the last section, and we are going to look at templates in more detail here. XSL templates provide a convenient method that allows us to provide any special formatting of the data that is returned by an XML node. That is, we can select the data for a specific node and apply any special formatting or manipulation of the data before we display it.

 

We define templates in XSL using the <xsl:template> element. If you are going to use scripting functions in the template to manipulate the data you can specify the language attribute and the scripting language (JScript or VBScript). Using the match attribute we specify the node in the XML data to be matched. Let's look at the following example:

 

<xsl:template match="@Last_Name_VC">

<TD><B><xsl:value-of/></B></TD>

</xsl:template>

 

In this example we have specified that the template should match the Last_Name_VC node in the XML data. When a match has been found and applied, the data in that node will be placed inside a table cell as specified by the <TD> HTML element and the XSL <xsl:value-of/> element. We have also specified that the data should be rendered in bold text as indicated by the <B> HTML element. The <xsl:value-of/> element inserts the value of the selected node as text.

 

Just because we have specified a template to format our data doesn't mean that the formatting will be applied to our document. In order to apply the formatting supplied by the template we must use the XSL <xsl:apply-templates> element. This element will apply the template that matches the node in the select attribute. The following example demonstrates this:

 

<xsl:apply-templates select="@Last_Name_VC"/>

 

What happens here is that we select the data in the Last_Name_VC node of our XML data and the <xsl:apply-templates> element will apply the template that we have defined for this node. The text that is produced by the template will be inserted at this point.

 

Assuming the Last_Name_VC node in our XML data contains a value of Willis, the template, when applied, would produce the following line of data:

 

<TD><B>Willis</B></TD>

Try It Out XSL Sorting and Templates

Let's put all of this new knowledge to use in an XSL stylesheet that will sort our data and use templates to format it. We want to format the first name by changing the font color to navy, and we want to change the font for the last name to a bold font. We will sort the data in our XML document in ascending order by last name and then by first name.

 

1.       The complete text for the XSL stylesheet is listed below. After you enter the text for this XSL stylesheet, using any text editor, save the file as EmployeeMatch.xsl in the htData directory:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

<xsl:template match="/">

<HTML>

<HEAD>

<STYLE>

TH

{

background-color: #CCCCCC;

}

</STYLE>

 

</HEAD>

<BODY>

<TABLE Border="1">

<TR>

<TH ColSpan="2">Hardware Tracking Employees</TH>

</TR>

<TR>

<TH>First Name</TH>

<TH>Last Name</TH>

</TR>

<xsl:for-each select="Employees/Employee_T"

order-by="@Last_Name_VC; @First_Name_VC">

<TR>

<xsl:apply-templates select="@First_Name_VC"/>

<xsl:apply-templates select="@Last_Name_VC"/>

</TR>

</xsl:for-each>

</TABLE>

</BODY>

</HTML>

</xsl:template>

<xsl:template match="@First_Name_VC">

<TD><FONT Color="#000080"><xsl:value-of/></FONT></TD>

</xsl:template>

 

<xsl:template match="@Last_Name_VC">

<TD><B><xsl:value-of/></B></TD>

</xsl:template>

</xsl:stylesheet>

 

2.       To test this XSL stylesheet enter the following URL in your browser. This is the same URL that you entered last time, except that we have specified the new XSL stylesheet:

http://localhost/htData?SQL=SELECT+First_Name_VC,+Last_Name_VC+FROM+Employee_T+FOR+XML+AUTO&XSL=EmployeeMatch.xsl&ContentType=Text/HTML&Root=Employees

 

After executing the URL above you should see results similar to those shown below. The text in the First Name column is navy in color and the text in the Last Name column is bold. All data has been sorted by the last name first and then by first name:

 

 

How It Works XSL Sorting and Templates

The first three lines of our XSL stylesheet are the standard lines of code defining this document as an XSL stylesheet.

 

Next, using the same code as we did in our last XSL stylesheet, we specify the HTML elements that define an HTML document. This includes the <HEAD> and <STYLE> elements:

 

<HTML>

<HEAD>

<STYLE>

TH

{

background-color: #CCCCCC;

}

</STYLE>

</HEAD>

 

The body of our HTML document starts out the same; we define the same column headers as before:

<BODY>

<TABLE Border="1">

<TR>

<TH ColSpan="2">Hardware Tracking Employees</TH>

</TR>

<TR>

<TH>First Name</TH>

<TH>Last Name</TH>

</TR>

 

We specify the same XSL <xsl:for-each> element as in the last example and have included one additional attribute, order-by. We are specifying that this element should iterate through the Employees/Employee_T nodes in our XML data and that it should also sort the data by the Last_Name_VC attribute first and then by the First_Name_VC attribute, which is different from the sort we performed earlier:

 

<xsl:for-each select="Employees/Employee_T"

order-by="@Last_Name_VC; @First_Name_VC">

 

Now, when we build a row of data in our table we apply the <xsl:apply-templates> elements, defined via the matching XSL templates at the end of the stylesheet, to the data which is returned by the <xsl:for-each> element:

 

<TR>

<xsl:apply-templates select="@First_Name_VC"/>

<xsl:apply-templates select="@Last_Name_VC"/>

</TR>

 

We end our loop by specifying the closing tag </xsl:for-each>. We end the table in our HTML code and the HTML code itself by specifying the appropriate HTML closing tags. The last thing we do is close the template that applies to the root node of our XML data:

 

 

</xsl:for-each>

</TABLE>

</BODY>

</HTML>

</xsl:template>

Using the XSL <xsl:template> element we define a template to format the data contained in the First_Name_VC element of our XML data. The match attribute specifies the element to be matched in the XML data.

 

This template will build the HTML to display a cell in our table as specified by the HTML <TD> element. We change the color of the text that will be displayed by specifying the HTML <FONT> element. The Color attribute listed here is using the RGB value of #000080, which represents the color navy. Then we specify the XSL <xsl:value-of/> element to insert the value of the selected node as text. Lastly, we specify the appropriate closing HTML tags and close this template element:

 

<xsl:template match="@First_Name_VC">

<TD><FONT Color="#000080"><xsl:value-of/></FONT></TD>

</xsl:template>

 

The template that formats the data from the Last_Name_VC elements of our XML data uses the HTML <B> element to render the text in a bold font:

 

<xsl:template match="@Last_Name_VC">

<TD><B><xsl:value-of/></B></TD>

</xsl:template>

 

We then end our XSL stylesheet by specifying the </xsl:stylesheet> closing tag.

Try It Out Hardware XSL Stylesheet

Now that we have worked with some employee data from the Employee_T table and created a couple of XSL stylesheets for employee data, let's recap and practice these skills again. In this exercise we want to create a simple XSL stylesheet for hardware data that will simply display all manufacturers and models listed in the Hardware_T table.

 

1.       The code for the XSL stylesheet is listed below. Once you have entered the code save it in the htData directory as Hardware.xsl.

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

<xsl:template match = "/">

<HTML>

<HEAD>

<STYLE>

TH

{

background-color: #CCCCCC;

}

</STYLE>

</HEAD>

 

<BODY>

<TABLE border="1">

<TR>

<TH ColSpan="2">Hardware</TH>

</TR>

<TR>

<TH>Manufacturer</TH>

<TH>Model</TH>

</TR>

<xsl:for-each select="Hardware/Hardware_T">

<TR>

<TD><xsl:value-of

select="@Manufacturer_VC"/></TD>

<TD><xsl:value-of select="@Model_VC"/></TD>

</TR>

</xsl:for-each>

</TABLE>

</BODY>

</HTML>

</xsl:template>

</xsl:stylesheet>

 

2.       To test this XSL stylesheet you need to enter the following URL in your browser. Notice that our SELECT statement in the URL specifies the Manufacturer_VC and Model_VC columns from the Hardware_T table. We have also specified the Hardware.xsl stylesheet and a root element of Hardware:

http: //localhost/htData?SQL=SELECT+Manufacturer_VC,+Model_VC+FROM+Hardware_T+FOR+XML+AUTO&XSL=Hardware.xsl&ContentType=Text/HTML&Root=Hardware

 

The results of your execution should look similar to this:

How It Works Hardware XSL Stylesheet

This XSL stylesheet looks very similar to the Employee.xsl stylesheet that you created. In fact, it works in the same fashion, but it uses XML data from the Hardware_T table.

 

The first three lines of our stylesheet are the standard lines of code that define this as an XSL stylesheet.

 

Next, we start defining the HTML elements that define our HTML document. Notice that we are using the same style for our column headers:

<HTML>

<HEAD>

<STYLE>

TH

{

background-color: #CCCCCC;

}

</STYLE>

</HEAD>

 

We start the body of our HTML document by specifying the HTML <BODY> tag. Then we start the table definition and define the column headers in the table:

<BODY>

<TABLE border="1">

<TR>

<TH ColSpan="2">Hardware</TH>

</TR>

<TR>

<TH>Manufacturer</TH>

<TH>Model</TH>

</TR>

 

Using the XSL <xsl:for-each> element we iterate through all of the XML data in the Hardware_T elements under the root element of Hardware.

 

For each row of data in our table we use the <xsl:value-of> element to select the Manufacturer_VC and Model_VC attributes from our XML data. We display these values in our table cells.

 

We end our loop using the closing tag for the <xsl:for-each> element:

 

<xsl:for-each select="Hardware/Hardware_T">

<TR>

<TD><xsl:value-of

select="@Manufacturer_VC"/></TD>

<TD><xsl:value-of select="@Model_VC"/></TD>

</TR>

</xsl:for-each>

 

We then close our table and end the HTML document. Next we end the template and stylesheet by specifying the appropriate XSL elements:

</TABLE>

</BODY>

</HTML>

</xsl:template>

</xsl:stylesheet>


BackContentsNext
©1999 Wrox Press Limited, US and UK.