|
|
||||||
|
|
![]() |
|
![]() |
|
||
|
|
||||||
Processing Templates in XSL
The year is 2002. It may be just three years from now, but in terms of Web years it's at least a paradigm shift away. Your cell phone rings and you answer it. On the other end of the line is your Web site with details on a real-estate contract, and it requires your immediate attention. The message is relayed in a monotone voice, but already the phone's LCD screen is filling with data and a menu is appearing to guide you through the salient points of the contract. Ultimately, you authorize the transaction and attach your digital signature. You've just purchased that dream property, contingent upon the sale of your current home.
Now, back at the office, you jump onto the Net and log in to your home's LAN. A realtor is coming to show your home, so you select options to increase the temperature of the house, turn on the inside lights, and play some light classical music. You smile and say to yourself, "There, the house shows better that way."
This promise of Internet appliances is not new. However, pointing to the incompatibilities among browsers, some in the press are speculating that these wired devices will be accessible only to the few companies with enough cash and coders to support the various standards for individual appliances. Certainly, there are debates over how devices should communicate with the network. But for delivering data, the answer is simple: XSL transformations.
I've already talked about the benefits of transforming XML into HTML. In May I introduced a tool set that lets you map XSL style sheets to specific browser types. This lets you serve HTML that's optimized for the particular client making the request. Last month, I showed how you can access and format any part of an XML document using XSL patterns. This month, I'll look at XSL templates and how you can develop transformations for different output devices.
Template Rules
In working with patterns last month, I briefly described how XSL applications process an XML document. Recall that the XSL application employs an XML processor to load a document, parse it into objects, and place those objects into a tree structure, called a "source tree." The XSL processor then takes this tree and processes it according to the rules defined in a style sheet to produce a second tree, called a "result tree." These rules are called "template rules."
From an author's perspective, a template rule lets you select a portion of a source XML document and describe how that portion should be processed. The template rule consists of a pattern that locates objects in the source tree, a template describing how these objects should be represented in the result tree (and ultimately processed by the XSL processor), and an apply-templates statement, which instructs the processor to process one or more nodes in the tree. You already know how to select patterns from reading last month's column, so what's next?
When a pattern matches with an element from the source tree, that node becomes the current node, and the rule's template is instantiated. At this point, the XSL application processes the template and places the results in the result tree. The simplest thing we can do at this point is to process the current node and its child nodes using
apply-templates. You can select nodes other than the current node by adding a select pattern as shown in Example 1. Without other instructions, the processor will simply grab the appropriate nodes from the source tree and place them in the result tree.While at times you'll simply want to copy a node to the result tree, you'll likely spend the bulk of your efforts creating new elements. This portion of the template rule is called the template. One of the first element types you'll want to create in your templates is a text element. You do this using the XSL element
<xsl:text>. For example, you can create a new text element and add content to it as shown in Example 2(a). This template rule matches the current node, uses<xsl:text>to create a new text node, adds some text, and callsapply-templatesto process the node. In fact, text elements are so common that XSL lets you omit the<xsl:text>markup altogether and simply enter the text strings. For instance, Example 2(b) matches elements in an XML document marked up asbold. The template portion of the rule simply includes the HTML<B>tag, which the XSL processor treats as text. Next, the template issues anapply-templatesto process the element in the current node, and adds another text element with the closing</B>tag. Assuming the content from the source document was the string "Hello World," the result is shown in Example 2(c).In fact, this is how we transformed XML into HTML in last month's column. Consider the skeleton code from that style sheet -- see Listing One. (All the code discussed this month is available online. See "Source-Code Availability," page 3.) The template immediately follows the
<xsl:templatematch="/index.html">tag. Notice that we simply write the HTML code we want included in the result tree. There's one final point regarding text elements: Eliminating the<xsl:text>element markup may have a minor influence on the way the processor strips white space. I'll cover the effects of white space another time.By the way, as we go to press, the W3C is releasing a new XSL Working Draft Specification complete with guidelines for formatting objects. The portions of the XSL specification describing transformations (including the material described here) has been moved to a new working-draft specification called XSLT. The new specification includes additional features and there has been a move to incorporate XPointers into the spec. I'll share more details with you next month.
Creating Other Elements
You can also create elements other than text elements. XSL provides markup that lets you generate comments, processing instructions, new elements, and their associated attributes. For example, you can create new elements with
<xsl:element>. The content of the element is a template for the attributes and children of your element. You must include anameattribute to identify your element. However, the name may be either a computed name, or one that you specify. If you want to generate a name, simply use the XSL namespace followed by the pound sign (#) and a name expression to compute a qualified name. I'll look at element and attribute creation in detail in a future column.You can also add comments to your documents using
<xsl:comment>. Usage is similar to<xsl:text>; simply include your comment text within opening and closing tags (see Example 3). The XSL processor will generate the appropriate comment delimiters. Keep in mind that the content can contain only characters.XML provides "processing instructions" that let you include information within a document that can be used by an application. The most recognizable processing instruction is the
xmldeclaration found in the prolog of most XML documents. Processing instructions might also be useful in defining a file format to a word processor, or in describing a properties file for a Java applet. XSL provides<xsl:pi>for this purpose. The<xsl:pi>element requires a name attribute to identify the processing instruction, and sends the instruction untouched to the result tree. The instruction must contain characters -- anything other than characters generates an error.Processing Templates
As a Web developer, you'll probably transform most of your XML documents into HTML. Last month, I provided some basic methods for generating HTML from your source document, so I won't cover that ground again here. The important steps to remember are that you want to use patterns to select specific nodes in your document tree, and then apply a template to the nodes that match your pattern. The templates will contain lots of HTML. However, XSL lets you process nodes directly. For example, you can iterate through elements, such as those representing database records. You can also sort nodes in ascending or descending order, process the same node multiple times in different modes, assign numbering to elements based on their position in the document tree, create counters, convert numbers to strings, and copy elements. XSL also supplies
<xsl:if>and<xsl:choose>to perform conditional processing.Space doesn't permit a thorough discussion of each of these features, so I thought I'd present a real-world example that demonstrates some of these features, and point them out as we go. In particular, we'll create a listings page for a real-estate office Web site. The site contains listings for about 30 agents. Each agent has a personal page where viewers can find out more about the realtor, and a link to his or her listings of homes. We'll assume that the agents and their listings are stored in a database, and that a query will return a string of XML data. At this point, we don't care how the query is made -- all we know is that we have a stream of XML data. The raw data comes from the Multiple Listing Service (MLS) and contains far more information than the agent wants to present, or than the perspective client needs to see. However, we may want to create different reports depending on the status of the listing. For example, an active home listing would call for a different report from a listing that has been sold.
Our example takes that string and formats a report summarizing residential listings that meet the conditions of a query, such as: all of the homes in a particular area that fall within a given price range. The XML document string is shown in Listing Two. For brevity's sake, the XML document represents only one record, which has been retrieved from the database. However, our style sheet will be able to process any number of records. The element names in the listing correspond to the field names in the database table. Other than serving as the input data, the only thing to note about this listing is the structure of the elements. Basically, there are seven categories for each real estate listing:
GENERAL,REMARKS,OCCUPANT-INFO,BROKERAGE-INFO,PROPERTY-INFO,FINANCIAL, andOTHER. Each listing is wrapped in aLISTINGelement to distinguish it from other listings. If this were a real application, we might add anIDattribute to further identify the listing. Finally, the entire collection of listings is wrapped in aRESIDENTIAL-LISTINGSelement. We might also provide elements for other types of listings such asCOMMERCIAL,TOWNHOME,CONDO,APARTMENT, and so on.The XSL style sheet to process our listings is shown in Listing Three. The first thing I do is create the
<xsl:stylesheet>element, and establish the XSL and HTML namespaces for the output. Next, I create a template to handle the root node. This is where we create the opening and closing HTML for the output document. To process the rest of the XML document, the<xsl:apply-templates/>element is placed within the HTML<BODY>tag.The rest of the style sheet contains a template rule to process portions of the input document. This rule uses a pattern to match the
RESIDENTIAL-LISTINGSelement. When the rule is matched,RESIDENTIAL-LISTINGSbecomes the current node, so any other patterns we create will be based on this position in the document tree. You see this immediately in the pattern referenced in<xsl:for-each>. Here I simply refer directly toLISTING. The<xsl:for-each>element lets us iterate through each node that matches our selected pattern. In this case, a database search could yield, say, 20LISTINGrecords, and<xsl:for-each>lets us process all of them.Next, our template rule creates an HTML table to place our data and begins to process the fields for our report. I do this by calling
<xsl:apply-templates>and specifying patterns to locate the individual fields from the record. Note that we moved down the document tree when thefor-eachelement was instantiated, so Listing Three again refers directly to child nodesGENERAL,PROPERTY-INFO,REMARKS, and so on. Once we output the data in a suitable format, we add the closing HTML tags and the closing XSL tags.Conclusion
In working with databases you'll likely do at least some of your processing on the server. This is particularly useful if you want to generate HTML optimized for a specific browser. However, with an XML-aware browser such as Internet Explorer, you can offload some processing to the client. In fact, you can use style sheets on the client side to format XML streams to be sent back to the server. This would make it possible to update the database through an HTTP connection. Of course, there will be gray areas, and you'll have to decide where it's most efficient to process your documents.
Finally, there's a long list of things we can do to improve our listing report. The first feature we might add is a calculated field that tells us how many hits our query returned and which record in the hit list is currently being viewed. XSL provides a collection of "counter" elements that will serve this purpose nicely. We might also want to sort our records by price, area, or some other value. We may want to add security and privileges so that agents can access sensitive information without compromising their clients. But that's the subject for next month.
(Get the source code for this article here.)
Michael publishes BeyondHTML.com, speaks on XML in the Ken North Expert Seminars, and serves as Web Techniques' editor at large. His upcoming book for XML Web developers should be available this fall. He can be reached at mfloyd@lifestylesSantaCruz.com.
|
|