Magazine |
| | Community |
| | Workshop |
| | Tools & Samples |
| | Training |
| | Site Info |
|
|
||||||||
|
November 4, 1998
One of the benefits of using XML is its ability to model complex data hierarchies such as:
XSL handles irregular and recursive structures through a mechanism similar to subroutines in programming languages. Fragments of a template can be extracted and invoked from another template. XSL can choose the appropriate fragment based on the structure of the XML data. A template can call itself, enabling it to handle recursive structures.
Documents generally have irregular and highly recursive data hierarchies. For example, consider the following document:
<document> <title>To the Pole and Back</title> <section> <title>The First Day</title> <p>It was the <emph>best</emph> of days, it was the <emph>worst</emph> of days.</p> <list> <li><emph>best</emph> in that the sun was out.</li> <li><emph>worst</emph> in that it was 39 degrees below zero.</li> </list> <section> <title>Lunch Menu</title> <list> <li>ice cream</li> <li>popsicles</li> </list> </section> </section> </document>
This XML grammar demonstrates the following features:
XSL provides a way to divide and conquer, to break down the overall document into several smaller templates. You can subdivide the larger problem of processing the entire document into several smaller problems that involve processing a specific part of the document, and solve each smaller problem independently.
At the topmost or highest level of the XSL stylesheet is the output template:
<HTML> <HEAD> <TITLE><xsl:value-of select="document/title"</TITLE> </HEAD> <BODY> <H1><xsl:value-of select="document/title"/></H1> <xsl:apply-templates select="document/section"/> </BODY> </HTML>
This template creates the rough structure of the output HTML document, and inserts the document title into this template in two places (showing how XSL can display an item in several places in the output). It also makes the "function call" (xsl:apply-templates) to process the top-level sections of the document.
The next "subroutine" to write is for section elements:
<xsl:template match="section"> <DIV> <H2><xsl:value-of select="title"/></H2> <xsl:apply-templates /> </DIV> </xsl:template>
The xsl:apply-templates command selects elements described by the XSL pattern -- sections within documents. In this case, the "The First Day" section is found. The XSL processor then takes this element and looks for a matching template. The above template is found (in this example, there are no other choices), the template fragment is evaluated, and its value is output at the point where the xsl:apply-templates appears.
Although this feature is somewhat like a function call in a programming language and serves a similar purpose, there is one big difference. Function calls use a specific function name to match the call with the definition, while XSL does not. Instead, XSL chooses the appropriate template based on the XML elements selected by the "select" attribute. It checks these nodes against the patterns in the xsl:template.
Note that the template itself calls xsl:apply-templates. Without a "select" attribute, all children are selected, and the XSL processor searches for an appropriate template for each. The next "subroutines" define templates to handle the p, list, and emph element types:
<xsl:template match="p"> <P><xsl:apply-templates /></DIV> </xsl:template> <xsl:template match="list"> <UL> <xsl:for-each select="item"> <LI><xsl:apply-templates /></LI> </xsl:for-each> </UL> </xsl:template> <xsl:template match="emph"> <I><xsl:apply-templates /></I> </xsl:template>
We use xsl:apply-templates in each case that may contain further structure. The p and list/item can contain emph elements; the emph element itself may contain some other structure.
Also notice that ther original template for sections will also be used for nested sections, so another is not needed.
Another template, or rule, is needed to catch all other input that does not match the templates already provided. (In this example, the only other output consists of text.) This default template is invoked for all other input:
<xsl:template> <xsl:value-of /> </xsl:template>
These templates produce the following output:
<HTML> <HEAD> <TITLE>To the Pole and Back</TITLE> </HEAD> <BODY> <H1>To the Pole and Back</H1> <DIV> <H2>The First Day</H2> <P>It was the <I>best</I> of days, it was the <I>worst</I> of days.</P> <UL> <LI><I>best</I> in that the sun was out.</LI> <LI><I>worst</I> in that it was 39 degrees below zero.</LI> </UL> <DIV> <H2>Lunch Menu</H2> <UL> <LI>ice cream</LI> <LI>popsicles</LI> </list> </DIV> </DIV> </BODY> </HTML>
To package all these templates in a single XSL file, place them in an xsl:stylesheet element. (Note that the XSL namespace must be declared on the xsl:stylesheet element.)
The main template (or root template) is marked by giving it the special pattern "/" to indicate that this is the template for the document root:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template> <xsl:value-of /> </xsl:template> <xsl:template match="/"> <HTML> <HEAD> <TITLE><xsl:value-of select="document/title"</TITLE> </HEAD> <BODY> <H1><xsl:value-of select="document/title"/></H1> <xsl:apply-templates select="document/section"/> </BODY> </HTML> </xsl:template> <xsl:template match="section"> <DIV> <H2><xsl:value-of select="title"/></H2> <xsl:apply-templates /> </DIV> </xsl:template> <xsl:template match="p"> <P><xsl:apply-templates /></DIV> </xsl:template> <xsl:template match="list"> <UL> <xsl:for-each select="item"> <LI><xsl:apply-templates /></LI> </xsl:for-each> </UL> </xsl:template> <xsl:template match="emph"> <I><xsl:apply-templates /></I> </xsl:template> </xsl:stylesheet>
The order that these templates appear in the stylesheet can be significant, when an element can match more than one of the defined templates. When more than one template can match, the template that appears later in the document takes precedence. For example, the first template does not have a "match" pattern defined and acts as a default template that matches any input. This template must appear first in the stylesheet or it will override all of the other templates.
When should you use a single template, and when should you use multiple templates within xsl:stylesheet? You can decide based on whether the data is regularly or irregularly structured. When you know the child elements that appear in the data, use xsl:for-each or xsl:value-of to simply describe the output results. For example, list elements always contain item elements only, so in the template for list elements, it makes sense to use xsl:for-each to handle the item elements. But elements with many different possible children are handled using xsl:apply-templates. (If lists were allowed to contain more than items or if item elements could appear elsewhere, the example would use xsl:apply-templates instead.)
Take a paragraph out of a book and mark it up in XML. Then try writing an XSL stylesheet to display that paragraph.
Did you find this article useful? Gripes? Compliments? Suggestions for other articles? Write us!
© 1998 Microsoft Corporation. All rights reserved. Terms of use.