Adding New Template Rules
The style sheets presented thus far have used <value-of> to retrieve the content of top-level elements and attributes. However, the XML document instance in Listing 2.1 also contains subelements, namely, the address element:
<invoice num="2317" invoiceDate="07-09-01"> ... <address> <streetAddress>123 Fourth Street</streetAddress> <city>Sometown</city> <state>CA</state> <zip>12345</zip> <province /> <country>USA</country> </address> ... </invoice>
To retrieve the content from, say, <streetAddress>, you could assign a step pattern in the select attribute of a <value-of> element. That might look something like:
<xsl:value-of select="invoice/address/streetAddress" />
This approach works fine for this example because the <invoice> element has a well-defined structure. That is, you know that there's one and only one occurrence of <streetAddress> and that it is a subelement of <address>. However, not all documents are so well structured.
The XML document in Listing 2.6, which represents a magazine article, is an example where the order and number of occurrences of elements is unknown.
Listing 2.6 This Magazine Article Is an Example of a Document with an Unpredictable Structure Where Both the Ordering of Elements and Number of Occurrences for a Given Element Are Unpredictable
<?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="article1.xsl"?> <article> <logo href="/rocket/images/logo.gif" /> <headline> Blowing XML Bubbles</headline> <deck>When will the bubble burst?</deck> <byline href="http://www.beyondhtml.com/default.asp?/rocket/bio.xml"> Michael Floyd</byline> <pubDate>March 2000</pubDate> <aBody> <para> <dropCap>A</dropCap>t one time or another, everyone from marketing professors to analyst companies has proposed various models to describe the cycle of high-flying technologies. Most picture a seed point followed by a phase of tremendous hyping, typically followed by a period of depression usually caused by the overhyping. </para> <para>Such a model prompted me to predict, on the <bold>editorial page</bold> of the <bold>June 1996 issue of <italic>Web Techniques </italic></bold>, a cooling period for the Web. Well, so much for forecasting. In fact, I've applied this model to technologies including <bullet>Artificial Intelligence (AI)</bullet>, <bullet>object-oriented programming</bullet>, and <bullet>Java</bullet>. </para> <para>The point of such an exercise is really to determine if a technology is just the <ital>"tech de jour"</ital> or whether it will be around long enough to have a lasting impact on the industry. Unfortunately, these models more often than not fail miserably in making such predictions. </para> <para>Thus, I would like to propose something I call <italic>Floyd's Bubble</italic>. It works much like blowing a very large soap bubble. You start with a technology, and huff and puff until you get a sizable bubble. Soon, others notice your bubble, and join in the huff and puff. You lose ownership of the bubble-perhaps retaining 20 percent of the bubble's equity if you're lucky-but the bubble grows far bigger than any bubble you could have blown on your own. Eventually, though, your bubble reaches its elastic limit and it pops. Whatever is left is the true value of your bubble. It's this true value that determines whether a technology will succeed or whether everyone will walk over to the next bubble wand. </para> <para>... </para> <para>Michael is the publisher of BeyondHTML.com and <italic>Web Techniques'</italic> editor at large. </para> </aBody> <copyright>Copyright Michael Floyd. 1998-2000. All Rights Reserved. </copyright> </article>
In this document, you'll notice that the article element contains several <para> elements. A <para> element may contain a drop cap, bold, italics, and bullet elements. The problem is, you don't know exactly when these elements will occur, or how many times they may occur. In one instance, an italic is embedded within an bold. In other cases, bold elements just contain text. You don't even know how many paragraph elements will occur from one document to the next.
Using the <value-of> element to retrieve text in a situation like this is all but impossible. The solution is to create additional template rules that describe the handling of these individual elements. For instance, you can create a template rule to handle all bold elements.
<xsl:template match="bold"> <B> <xsl:apply-templates/> </B> </xsl:template>
This rule would be placed after the root template rule in the style sheet. The template rule says, whenever the rule matches with a <bold> element, add an HTML <B> tag. The <xsl:apply-templates/> element instructs the XSL processor to apply any other matching template rules that may be in the style sheet. One such template rule is built into to XSL, and it says whenever a text node is found, retrieve its content. This built-in template rule is the equivalent of writing
<xsl:value-of select="text()" />
So, when the <apply-templates> element is invoked, it will return any text in the current node, then look in the style sheet for any other template rules to process.
If you are using an older version of Microsoft's XML parser (before version 3.0) or you are experiencing problems displaying text from your style sheet, see "Displaying Text with MSXML" in the "Troubleshooting" section at the end of this chapter.
By including <apply-templates> in this template rule, you're also able to process the content for subelements of the element being processed. For example, the XML document instance includes the following markup:
<bold>June 1996 issue of <italic>Web Techniques</italic></bold>
Notice that the <bold> element contains <italic> as a subelement. When <apply-templates /> is invoked from the <xsl:template match="bold"> rule, it looks for additional template rules. If there's a template rule to process the <italic> element, it will be instantiated. Here's a template rule to process the <italic> element:
<xsl:template match="italic"> <I> <xsl:apply-templates/> </I> </xsl:template>
Likewise, you will add template rules to transform any element type you want. Each template rule should usually include its own <apply-templates> element. If you don't include it, no more rules will be searched and processing will end.
So, how does processing get started in the first place? When a style sheet is loaded, the root template rule is processed automatically. To search additional template rules, you must place an <apply-templates/> element somewhere near the bottom of the root template rule. This instance is what starts the process.
Finally, Listing 2.7 presents a complete style sheet demonstrating these concepts.
Listing 2.7 Using Additional Template Rules, You Can Handle Elements as They Occur in Your Document
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" /> <!-- Root template --> <xsl:template match="/"> <HTML> <HEAD> <TITLE> <xsl:value-of select="article/headline"/> </TITLE> </HEAD> <BODY> <P><H1> <xsl:value-of select="article/headline"/> </H1></P><BR></BR> <P><H2> <xsl:value-of select="article/deck"/> </H2></P> <BR></BR> <P> <xsl:apply-templates select="article/byline"/> </P> <BR></BR> <P> <P><xsl:apply-templates select="article/aBody"/></P> </P> <HR></HR> <P ALIGN="CENTER"><FONT SIZE="-1"> <xsl:value-of select="article/copyright"/> </FONT> </P> </BODY> </HTML> </xsl:template> <xsl:template match="byline"> <P> <I>By <xsl:apply-templates/> </I> </P> </xsl:template> <xsl:template match="aBody"> <P> <xsl:apply-templates/> </P> </xsl:template> <xsl:template match="para"> <P> <xsl:apply-templates/> </P> </xsl:template> <xsl:template match="dropCap"> <FONT Size="+4" COLOR="Navy"><B> <xsl:apply-templates /> </B></FONT> </xsl:template> <xsl:template match="bullet"> <LI> <xsl:apply-templates /> </LI> </xsl:template> <xsl:template match="bold"> <B> <xsl:apply-templates/> </B> </xsl:template> <xsl:template match="italic"> <I> <xsl:apply-templates/> </I> </xsl:template> </xsl:stylesheet>
The resulting transformation as rendered in Internet Explorer is shown in Figure 2.4.
Figure 2.4 The result of the transformation in Listing 2.7, as rendered in Internet Explorer.