Rule-Based Stylesheets


A rule-based stylesheet consists primarily of rules describing how different features of the source document should be processed , such as "if you find a <species> element, display it in italic."

Some would say that this rule-based approach is the essence of the XSLT language, the principal way that it is intended to be used. I would say that it's one way of writing stylesheets, often the best way, but not the only way, and not necessarily the best answer in every situation. It's often strongly recommended in books for beginners, but I think that the main reason for this is that for many beginners the navigational pattern is what comes naturally, because it has a very similar feel to programs written in procedural languages. It's important that every XSLT programmer be comfortable with writing rule-based stylesheets, so it makes sense to teach this approach early on.

Unlike navigational stylesheets, a rule-based stylesheet is not structured according to the desired output layout. In fact, it makes minimal assumptions about the structure of either the source document or the result document. Rather, the structure reads like an inventory of components that might be encountered in the source document, arranged in arbitrary order.

Rule-based stylesheets are therefore most useful when processing source documents whose structure is flexible or unpredictable, or which may change a lot in the future. It is very useful when the same repertoire of elements can appear in many different document structures, so a rule like "display dates in the format 23 March 2004" can be reused in many different contexts.

Rule-based stylesheets are a natural evolution of CSS and CSS2. In CSS, you can define rules of the form "for this set of elements, use this display rendition ." In XSLT, the rules become much more flexible, in two directions: the pattern language for defining which elements you are talking about is much richer; and the actions you can define when the rule is fired are vastly more wide- ranging .

A simple rule-based stylesheet consists of one rule for each element name. The typical rule matches a particular element name , outputs an HTML tag to define the rendition of that element, and calls <xsl:apply-templates> to process the child nodes of the element. This causes text nodes within the element to be copied to the output, and nested child elements to be processed each according to its own template rule. In its simplest form, a rule-based stylesheet often contains many rules of the form:

  <xsl:template match="para">   <p><xsl:apply-templates/></p>   </xsl:template>  

This simple rule does a direct replacement of <para> tags by <p> tags. Most real stylesheets do something a bit more elaborate with some of the tags, but they may still contain many rules that are as simple as this one.

XSLT 2.0 introduces the ability to define rules that match elements and attributes by their type, as defined in a schema, rather than simply by their name or context. This makes the technique even more powerful when handling document structures that are highly complex or extensible. For example, you can match all the elements in a particular substitution group with a single template rule, which means that the stylesheet doesn't need to change when new elements are added to the substitution group later. Similarly, you can define a template rule that formats all elements containing part numbers or dates, irrespective of the element or attribute name.

A Rule-Based Stylesheet
start example

Rule-based stylesheets are often used to process narrative documents, where most of the processing consists in replacing XML tags by HTML tags. This example illustrates this by showing how a Shakespeare play can be rendered in HTML.

Input

The input scene2.xml is a scene from a play; Act I, Scene 2 of Shakespeare's Othello. It starts like this:

  <?xml version="1.0" encoding="iso-8859-1" ?>   <SCENE>   <TITLE>SCENE II. Another street,</TITLE>   <STAGEDIR>Enter OTHELLO, IAGO, and Attendants with   torches</STAGEDIR>   <SPEECH>   <SPEAKER>IAGO</SPEAKER>   <LINE>Though in the trade of war I have slain men,</LINE>   <LINE>Yet do I hold it very stuff o' the conscience</LINE>   <LINE>To do no contrived murder: I lack iniquity</LINE>   <LINE>Sometimes to do me service: nine or ten times</LINE>   <LINE>I had thought to have yerk'd him here under the   ribs.</LINE>   </SPEECH>   <SPEECH>   <SPEAKER>OTHELLO</SPEAKER>   <LINE>'Tis better as it is.</LINE>   </SPEECH>   </SCENE>  

There are some complications that aren't shown in this sample, but which the stylesheet needs to take account of.

The top-level element is not always a <SCENE>; it might also be a <PROLOGUE> or <EPILOGUE>. The <STAGEDIR> element (representing a stage direction) can appear at any level of nesting: for example, a stage directive can appear between two speeches, between two lines of a speech, or in the middle of a line.

Several people can speak at the same time. In this case a single <SPEECH> element has more than one <SPEAKER> . In general, a <SPEECH> consists of one or more <SPEAKER> elements followed by any number of <LINE> and <STAGEDIR> elements in any order.

Stylesheet

The stylesheet scene.xsl consists of a number of template rules. It starts by declaring a global variable (used simply as a constant) and a rule for the document element.

  <xsl:stylesheet   xmlns:xsl="http://www.w3.org/1999/XSL/Transform   " version="1.0"    >    <xsl:variable name="backcolor" select="'#FFFFCC'" />   <xsl:template match= "SCENE PROLOGUE EPILOGUE" >   <HTML>   <HEAD>   <TITLE><xsl:value-of select="TITLE"/></TITLE>   </HEAD>   <BODY BGCOLOR='($backcolor}'>   <xsl:apply-templates/>   </BODY>   </HTML>   </xsl:template>  

The appearance of <xsl:value-of > is a rare departure from the purely rule-based pattern, just to prove that none of the patterns has to be used to the exclusion of the others.

The template rule for the <SPEECH> element outputs a table containing one row and two columns : it puts the names of the speakers in the first column, and the lines of the speech, plus any stage directives, in the second, as follows :

  <xsl:template match="SPEECH">   <table><tr>   <td width="160" valign="top">   <xsl:apply-templates select="SPEAKER"/>   </td>   <td valign="top">   <xsl:apply-templates select="STAGEDIRLINE"/>   </td>   </tr></table>   </xsl:template>  

The remaining template rules are straightforward. Each of them simply outputs the text of the element, using an appropriate HTML rendition. The only complication, which doesn't actually occur in this particular scene, is that for some elements ( <STAGEDIR> and <SUBHEAD> ) the HTML rendition is different, depending on the element's context, and so there is more than one rule defined for these elements.

  <xsl:template match="TITLE">   <h1><center>   <xsl:apply-templates/>   </center></h1><hr/>   </xsl:template>   <xsl:template match="SPEAKER">   <b>   <xsl:apply-templates/>   <xsl:if test="not(position()=last())"><br/></xsl:if>   </b>   </xsl:template>   <xsl:template match="SCENE/STAGEDTR">   <center><h3>   <xsl:apply-templates/>   </h3></center>   </xsl:template>   <xsl:template match="SCENE/STAGEDIR">   <p><i>   <xsl:apply-templates/>   </i></p>   </xsl:template>   <xsl:template match="LINE/STAGEDIR">   [ <i>   <xsl:apply-templates/>   </i> ]   </xsl:template>   <xsl:template match="SCENE/SUBHEAD">   <center><h3>   <xsl:apply-templates/>   </h3></center>   </xsl:template>   <xsl:template match="SPEECH/SUBHEAD">   <p><b>.   <xsl:apply-templates/>   </b></p>   </xsl:template>   <xsl:template match="LINE">   <xsl:apply-templates/>   <br/>   </xsl:template>   </xsl:stylesheet>  

This particular stylesheet doesn't use any XSLT 2.0 features, so I left the version number as 1.0 ‰« .

Output

The output obtained is shown in Figure 9-2.

click to expand
Figure 9-2
end example
 

Most of the time, a rule-based stylesheet creates a result tree with a structure similar to the source tree-with most of the source text appearing in the same order in the result document, usually with different tags. The closer this describes the transformation you want to do, the closer your stylesheet will be to the example shown above. However, this doesn't mean that the processing has to be purely sequential. You can process chunks of the tree more than once using modes, you can reorder the nodes of the tree, and you can grab data from ancestor nodes, all without deviating from the rule-based design pattern.

The characteristic feature of a rule-based stylesheet is that there is generally one template rule for each class of object found in the source document. I use the term class very loosely here: the "classes of object" might correspond to types in a schema, or to element names, or perhaps to element names qualified by their context or content.

Of course it's possible to mix design patterns, particularly if your source document contains a mixture of " data-oriented " and "text-oriented" structures (an example might be a job application form). Then it's quite appropriate to use a navigational pattern for the regular structures and a rule-based pattern for the less regular. For example, I created a Web site that provides information about concert soloists. This contains a mixture of structured data (their name, instrument or voice, photo, and contact details), semistructured data about the performances they have taken part in, and unstructured text. The stylesheet to display the data contains a corresponding mixture of coding styles. The larger and more complex your stylesheet, the more likely it is to contain examples of each of the design patterns.




XSLT 2.0 Programmer's Reference
NetBeansв„ў IDE Field Guide: Developing Desktop, Web, Enterprise, and Mobile Applications (2nd Edition)
ISBN: 764569090
EAN: 2147483647
Year: 2003
Pages: 324

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