If you are learning XSL (eXtensible Stylesheet Language), you’ll want to understand how to build modular and reusable components as you would in any other language. The XSL include and import elements provide an excellent capability in this regard.
In this article, we will develop a reusable page template to demonstrate how to build modular stylesheet components. The following outline is a roadmap for how we’ll cover this topic:
- First, we’ll design a page layout structure for a typical Web site.
- Then, we’ll design the stylesheet structure of modular components to support the page layout.
- We’ll build the header and footer components to demonstrate building named templates.
- We’ll build the page template component and demonstrate including stylesheets and calling named and parameterized templates.
- We’ll build a typical page using our page template component, and demonstrate inheriting and overriding variables and templates from imported stylesheets.
- Finally, we’ll summarize what we’ve learned.
Page Layout Structure
First, let’s define the structure of our reusable page template.
As is common to many sites, our pages will all have a standard header and footer. In addition, we’ll define the “frame” in which the header, body, and footer will appear.
Now, let’s look at how we’ll construct reusable stylesheet components to implement this design.
The boxes with a dotted line represent the reusable components we will be building:
- Header.xsl and Footer.xsl contain the common header and footer in our layout.
- PageTemplate.xsl defines the frame in which the header, body, and footer reside.
Main.xsl is a sample page that uses these components.
Notice that the page template includes the header and footer stylesheets. The <xsl:include/> element will be used to implement this in our example. It provides the capability to include the specified stylesheet at compile time.
Notice that the main stylesheet imports the page template stylesheet. The <xsl:import/> element will be used to implement this in our example. This element works very much like inheritance does in an object-oriented language. As a matter of fact, we’ll even override one of the templates in our main stylesheet.
Sample XML Document
Before we go any further, let’s define a simple source document that we’ll use for our transformation.
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet href="Main.xsl" type="text/xsl"?> <ScreenDefinition> <Title>Building Modular Stylesheets</Title> </ScreenDefinition>
As you can see, we’re not going to transform much data via <xsl:apply-templates/> in this example. We’ll use the Title element in the header section of our page. This will also be used in our example to show how variables in XSL can be overridden.
Header and Footer
Now, let’s build our first reusable component, the header stylesheet.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns_xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template name="doHeader"> <xsl:param name="title"/> <table> <tr> <td style="font-family:arial; font-size: 15px; color:#d60000; font-weight: bold; filter: dropShadow(offx=1,offy=1, color=#C0C0C0) blur(strength=2);"> <xsl:value-of select="$title"/> </td> </tr> </table> </xsl:template> </xsl:stylesheet>
Notice that our template doesn’t have a match attribute, but only a name of doHeader. This name will be used to call the template later from our page template.
The doHeader template may also be passed a parameter to it called title. The passed title is displayed in the table cell. You probably noticed that an inline CSS style is used to apply some rather fancy formatting to the title in our HTML output. This way a custom graphic won’t need to be built for each page title.
Now, lets build the footer. Unlike the header, it doesn’t have any passed parameters to its named template.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns_xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template name="doFooter"> This site is best viewed with <a href="http://www.microsoft.com" target="_blank"> Microsoft Internet Explorer 5.x </a> </xsl:template> </xsl:stylesheet>
With the modular approach, we’ll be able to change page headers and footers for our entire site by modifying code in these components.
Now, we’ll build our page template stylesheet.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns_xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:include href="Header.xsl"/> <xsl:include href="Footer.xsl"/> <xsl:variable name="title" select="'Default Title'"/> <xsl:template name="doPage"> <html> <body> <table width="100%" height="100%"> <tr valign="top"> <td> <xsl:call-template name="doHeader"> <xsl:with-param name="title" select="$title"/> </xsl:call-template> </td> </tr> <tr> <td><xsl:call-template name="doBody"/></td> </tr> <tr align="center" valign="bottom"> <td><xsl:call-template name="doFooter"/></td> </tr> </table> </body> </html> </xsl:template> <xsl:template name="doBody"> Default body - will be overridden </xsl:template> </xsl:stylesheet>
The Header.xsl and Footer.xsl stylesheet components are included into this stylesheet at compile time. This means that it is just as if the doHeader and doFooter templates were part of this stylesheet.
The doPage template defines the structure for the page. It uses <xsl:call-template/> to call the doHeader, doBody, and doFooter templates in the appropriate part of the layout. If we ever want to change the “frame” structure for our pages, we’ll be able to make a global change to the site by changing this single component.
The title variable defined for the stylesheet is passed to doHeader via the <xsl:with-param/> element. We’ll be overriding this variable and the doBody template in our main page.
Now that we’ve built our reusable components, our main page is going to seem trivial. This is how it should be. We’ve invested some time in building reusable components. Now we can leverage this investment over and over again.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns_xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:import href="PageTemplate.xsl"/> <xsl:output method="html" indent="yes"/> <xsl:variable name="title" select="//Title"/> <xsl:template match="/"> <xsl:call-template name="doPage"/> </xsl:template> <xsl:template name="doBody"> <p align="center"> Apply templates to your Source document here... </p> </xsl:template> </xsl:stylesheet>
First, we import the page template stylesheet. Then, we override the title variable by selecting the Title element from our XML document.
The root template simply calls the doPage template in the imported stylesheet. Remember that the inherited doPage template creates our standard layout and calls doHeader, doBody, and doFooter at the appropriate time.
When doHeader is called, it will be passed our overridden title variable.
Because we overrode the doBody template, our specialized version of the template will be invoked by doPage. Object-oriented programmers will recognize this as polymorphism. It is also an implementation of the template method design pattern.
The resulting HTML from our transformation will look something like this when rendered in a browser:
Not much of a page, but the frame, header, body, and footer structure provides a nice foundation to build upon. The idea here is that any given page on our site will share a common page layout, but can override the header title and the body. Speed of development and maintenance of the site will be greatly enhanced through the use of common components.
XSL provides excellent facilities for building modular and reusable components. We covered examples of the following features of the language:
- Including stylesheets at compile time
- Calling named and parameterized templates
- Inheriting variables and templates from imported stylesheets
- Overriding variables and templates from imported stylesheets
We built reusable page template, header, and footer components to demonstrate how to build modular components using XSL. This could be the start of your library of reusable stylesheet components. But the rest is up to you.
To download the example stylesheets, click here.
About the Author
|Jeff Ryan is an architect for Hartford Financial Services. He has eighteen years of experience designing and developing automated solutions to business problems.
His current focus is on Java, XML, and Web Services technology. He may be reached at firstname.lastname@example.org.
|Other Articles Written by Jeff Ryan|