A template is analogous to a method in an object-oriented programming language. It allows a single XSLT stylesheet to be broken into multiple logical units, each of which performs a specific transformation.
There are two types of templates, distinguished by having either a 'match' attribute or a 'name' attribute. If a template has a 'match' attribute, it will be invoked when the pattern specified as the value of the attribute is matched against one or more nodes in the input document. If a template has a 'name' attribute, it may be invoked by calling the template explicitly by name.
In the following xsl:template instruction, we find classes in our model by matching the tag for a class:
<!-- Class --> <xsl:template match="Foundation.Core.Class">
In the following xsl:template instruction, we name the template as 'supertypes' to describe the transformation we want to perform for the supertypes of a class:
<!-- Supertypes (inheritance) --> <xsl:template name="supertypes">
References: [XSLT Programmer's Reference, xsl:template pp. 288-298]
There are two ways to invoke a template, which correspond to the two types of templates just described.
The xsl:apply-templates instruction is used to tell the XSLT processor to search for nodes which match an XPath expression and then invoke templates whose 'match' pattern is satisfied.
The xsl:call-template instruction is used to invoke a template with a specified name.
In the following xsl:apply-templates example we instruct the XSLT processor to search for all class definitions (distinguished from class references by possessing an 'xmi.id' attribute instead of an 'xmi.idref' attribute) and then apply any matching templates:
<!-- Classes --> <xsl:apply-templates select="//Foundation.Core.Class[@xmi.id]">
In contrast, when we want to format a list of supertypes for a class we employ xsl:call-template to invoke the template with the name "supertypes":
The choice of which type of template to employ is largely a matter of preference although the criteria we have used is based on where to put the complexity. By using a sequence of xsl:call-template instructions to perform the transformation of the class details (supertypes, subtypes, associations, attributes, operations), we have pushed all the complexity out of the class template and into the respective detail templates. Look at the actual stylesheet code to get a better idea how this works.
References: [XSLT Programmer's Reference, xsl:apply-templates pp. 145-155, xsl:call-template pp. 167-175]
Whenever a list of similar items is produced, it is helpful to the reader if the items in the list are sorted. A sorted list allows the reader to quickly locate an item of interest. The structure of our example is largely built around a sorted list of interfaces and classes in an object model.
XSLT supplies a sorting facility which may be applied to the node-set matched by a 'select' expression in an xsl:apply-templates instruction. The sort is performed using one or more sort keys as specified in an xsl:sort instruction, as seen in the following code taken from our document root template:
<!-- Classes --> <xsl:apply-templates select="//Foundation.Core.Class[@xmi.id]"> <xsl:sort select="Foundation.Core.ModelElement.name"/> </xsl:apply-templates>
Here we are sorting the classes found in the model using the name of a class as the sorting key, as specified in the 'select' attribute of the xsl:sort instruction. By default the sort order is ascending although this could be altered using an optional 'order' attribute. The ability to sort numbers is also provided through an optional 'data-type' attribute.
References: [XSLT Programmer's Reference, xsl:sort pp. 272-276]
When invoking a template for processing, it is often a requirement to pass some piece of information to the template, similar to a parameter in a method invocation for an object-oriented language. XSLT does provide a mechanism for this feature, however inelegant it may appear to an object-oriented programmer. The following is an example which may be found frequently in our stylesheet:
<xsl:call-template name="classify"> <xsl:with-param name="target" select="$target" /> </xsl:call-template>
This code is used to call the named template "classify", which is responsible for formating the name of a type in our model, whether a class, interface or a datatype. The parameter which is passed to the classify template is the 'xmi.id' for the type so that the template may locate the definition for the type and extract information used to produce the output. Here the 'xmi.id' has been assigned to the variable "target". The xsl:with-param instruction is used to pass the variable by name, with the value determined by the 'select' attribute.
The called template must also declare the parameter in order to provide a way to reference the parameter within the template. This is done with the xsl:param instruction which must immediately follow the xsl:template instruction:
<!-- Classification --> <xsl:template name="classify"> <xsl:param name="target"/>
The parameter may be used within the template in the same way that XSLT variables are used.
References: [XSLT Programmer's Reference, xsl:with-param pp. 318-320]
An XSLT processor will by default look for the best match expression when looking for a template to apply to a node. If you want to transform one element in more than one way, however, then you will need to apply additional options. One option is to employ the 'mode' attribute of xsl:apply-templates.
An example of where we found modes to be helpful is during processing of a model's name. We want the model name to appear both in the window title of the browser and as a heading for the page. Web page titles are used by browsers for creating bookmarks. Both page titles and page headings are used by search engines for ranking and creating content links. A model's name, if descriptive, can be quite useful for these purposes.
The following code appears in the document root template of our stylesheet:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <!-- Model Name in window title --> <xsl:apply-templates select="//Model_Management.Model[@xmi.id]" mode="head"/> </head> <body> <!-- Model Name in document heading --> <xsl:apply-templates select="//Model_Management.Model[@xmi.id]" mode="body"/>
Here we see the model name being selected first in the <head> section of the document where the document title appears and second in the <body> section of the document where the level one heading appears. Since the 'select' attribute of both xsl:apply-templates instructions contains an identical XPath expression, we need to differentiate the two instructions. This is accomplished through the 'mode' attribute. Let's see what the actual templates look like:
<!-- Window Title --> <xsl:template match="Model_Management.Model" mode="head"> <title> <!-- Name of the model --> <xsl:value-of select="Foundation.Core.ModelElement.name"/> </title> </xsl:template> <!-- Document Heading --> <xsl:template match="Model_Management.Model" mode="body"> <div align="center"> <h1> <!-- Name of the model --> <xsl:value-of select="Foundation.Core.ModelElement.name"/> </h1> </div> </xsl:template>
In both templates the 'mode' attribute in the xsl:template instruction plays a role analogous to a method signature, differentiating the templates so that the XSLT processor can select the right one. For the window title we use the model name as the text for a <title> element. For the document heading we use the model name as the text for an <h1> heading element, nicely centered. Search engines love to use these tags for indexing and displaying results, especially in the absence of any <meta> tags.
References: [XSLT Programmer's Reference, xsl:template pp. 288-298]