Some people complain than XML and XSL are too verbose, that it takes too may keystrokes to achieve the simplest of things. To me this is irrelevant - it is much more important that software be readable and understandable to other humans than be quick to type. I would rather take a minute to type something that can be understood in a second than take a second to type something that takes a minute to understand.

Another way to overcome the verbosity of any language, not just XSL, is not to find yourself writing the same code over and over again. Instead you should find a way to put that code into a reusable library so that when you want to run that code you call a library routine instead of writing the same piece of code all over again in long hand. XSL has the ability to create reusable routines in the form of XSL templates which can be called from any number of different places. There is also the ability to maintain this template code in a single location and to make the contents of the files in this location available in any XSL stylesheet by means of the <xsl:include> statement. Having identified that XSL contains the tools to build and execute reusable code the only remaining difficulty is to decide what code can be put into a reusable template. The purpose of this article is to explain the steps that I have taken which make my library of XSL stylesheets and templates much more reusable than most.

When constructing an XSL stylesheet it is usual to start with minimum reusability and to work up in stages to maximum reusability, such as in the following:

Here all field names are hard-coded, and for each of those fields the HTML control is constructed manually, as in:

These means that such attributes do not need to be hard-coded in the XSL stylesheet. It is good practice to have data passed in as XML elements, but to have meta-data (which is "data about data") passed in as XML attributes. An element can have only one value but any number of attributes.

Instead of building each HTML control manually the next step is put all that code into a template which can be called, as in:

A lot of people may reach step (2), a few people may reach step (3), but most people fail to realise that there is another step that will eliminate the need to have a separate XSL stylesheet for each screen in which all the field names are hard-coded. If you think about it, the list of field names to be displayed is just a simple list, and it is possible to have this list passed in as data within the XML file, as in the following:

The main element is an internal stylesheet (zone) name while the id attribute identifies the database table name within the XML file. All subordinate row and cell elements belong to this table. The following XSL statement will extract all the cell elements which have a label attribute:

<xsl:for-each select="//structure/main/row/cell[@label]">

If a stylesheet contains more than one zone then the zone name can be passed in as a parameter and processed with the following statement:

<xsl:for-each select="//structure/*[name()=$zone]/row/cell[@label]">

Similarly all the field names and their corresponding values can be extracted with the following statements:

I reached as far as step (3) in 2003 as documented in Generating dynamic web pages using XSL and XML. Since that time I have been able to implement step (4) which means that instead of having a customised XSL stylesheet for each "detail" screen I can now use a generic XSL stylesheet instead. This means that the time I need to spend in building individual screens is far less than it used to be, and this boost in productivity produces significant savings which I can pass on to my customers.

You may think that it is impossible to build an entire application from 1 or 2 XSL stylesheets, and you would be right. The same stylesheet can only be used in transactions which have the same structure, and my long experience has allowed me to identify just a dozen or so structures that can be used in an application of over 500 components. I have organised these different screen structures into what I call transaction patterns which are a combination of structure and behaviour. Each individual transaction is an implementation of a particular pattern (structure and behaviour) with content (application data). It is possible for the same structure to be combined with different behaviours to form different patterns. This can be demonstrated with the INSERT, UPDATE, DELETE, ENQUIRE and SEARCH forms which all share the same DETAIL stylesheet.

Each controller communicates with one or more models in order to generate a response to a request, then the data is extracted from each model and written to an XML document by the view. The contents of a screen structure file are then appended to the XML document before the XSL transformation process which creates the HTML output.

The following screen shots show sample screens with the different areas (zones) which are built into each pattern. Each of these zones is constructed from a central library of common XSL templates which means that it is a simple process to construct a new XSL stylesheet to deal with a different screen structure.

This layout can be used for any number of database tables - all that changes is the title, the column headings and the data area. The contents of the pagination area, menu, navigation and action bars are supplied in the XML file, therefore common templates can be used in the XSL file without any modification.

This layout can be used for any number of database tables - all that changes is the title and the data area. The contents of the scrolling area, menu, navigation and action bars are supplied in the XML file, therefore common templates can be used in the XSL file without any modification.

Within these two different layouts there are common zones - the menu bar, breadcrumb area, title, navigation bar, message area and action bar - which can be dealt with by common templates and thus do not require separate copies of the same code.

The XML document can be broken down into the following constituent parts:

<?xml version="1.0" encoding="UTF-8"?>
<root>
......
</root>

The first line contains the XML declaration and the encoding. The second and last lines identify the root node within the document. Every XML document must contain a root node to encompass all the other nodes. In this example the name of the root node is "root" (how original!), but it could be anything.

Everything between <person>...</person> belongs to the same occurrence (row) from the "person" table. Each element in between belongs to a different field (column) of that table. Note that an element can contain a value and any number of attributes each of which can have its own value. For example, the "person_id" element contains the value "PA" but also attributes for "size" and "pkey".

It is possible for an XML file to contain multiple occurrences, either from the same table or even from different tables. To indicate a relationship between two tables it is also possible for the occurrences of a child table to be held within the related occurrence of the parent table.

The next section identifies the options for dropdown lists or radio groups. These are all contained within the node called "lookup".

Here there is a single zone called "main" which will be populated using entries from the "person" table. This contains a group of column specifications which is then followed by specifications for each HTML table row and cell which is to appear in that zone. Note that each cell may contain either a field label (which is supplied as a literal string) or the name of the field in the XML document which will supply the value.

It is possible for an XSL stylesheet to contain multiple data zones, so each zone will have its own specifications in the XML document.

For LIST screens (with a horizontal layout) all "label" entries will appear as a single line of column headings at the top of the display while the "field" entries will be grouped into a single data line, one line for each database occurrence.

For DETAIL screens (with a vertical layout) each row will be an actual HTML table row, with the "label" entry on the left and the contents of the "field" entry on the right. Note that it is also possible to have more than one label/field combination appearing in the same row. The "colspan" attribute will allow an entry to span multiple columns, and the "rowspan" attribute will allow an entry to span multiple rows.

The optional "size" attribute is used to reduce the size of the field to something which is smaller than its actual size in the database.

The last area holds values that were originally passed in as parameters during the XSL transformation process which was performed on the server. These were later switched to being ordinary entries with the XML document so that they could be made available for client-side transformations.

Under the <params> node: this contains general values which may be used in various places during the transformation process.

Under the <params><text> node: this contains pieces of text which will appear in various places in the output document. These values used to be hard-coded within the XSL stylesheet, but they are now supplied from within the XML document as they need to be in different languages.

The first line contains the XML declaration. The second line and last lines identify the contents as an XSL stylesheet. The <xsl:output> line specifies the output format required by the transformation process.

The next set of lines perform various functions before the main template is executed.

<!-- include common templates -->
<xsl:include href="......"/>
<!-- get the name of the MAIN table -->
<xsl:variable name="main" select="//structure/main/@id"/>
<xsl:variable name="numrows" select="//pagination/page[@id='main']/@numrows"/>

The <xsl:include> statements make the contents of those files available to the transformation process. Each of these files may contain any number of XSL templates.

The <xsl:variable> statements extract values from the current XML file.

$main will contain the value of the id attribute from the main element which is a child of the structure element. So <structure><main id="person"> will provide the value person.

$numrows will contain the value of the numrows attribute from the page element with the id attribute of 'main' which is a child of the pagination element. So <pagination><page id="main" numrows="32"> will provide the value 32.

Note here that every XSL transformation requires a template which matches "/" - this path expression includes everything which is subordinate to the root node of the XML document. The lines within this template are then scanned and processed sequentially. Anything beginning with <xsl: is treated as an XSL instruction. Everything else, such as ordinary HTML tags, is output as is.

Individual parts of the XML document are then processed using different named XSL templates, as shown in the following section.

All programming languages allow common code to be defined once in a subroutine which can then be referenced from multiple places instead of having to be duplicated in each of those places. In XSL these "subroutines" are called "templates". They can either be hard-coded into individual stylesheets or held in central files which can be incorporated into any number of stylesheets by means of the <xsl:include> statement.

A template can be called using code similar to the following if no parameters are required:

<xsl:call-template name="head"/>

If parameter values are to be passed they must be specified by name, as in the following example:

Item (1) will loop through each structure/zone/row/cell node which has a label attribute and where the zone name is the same as the $zone input parameter. Each entry is put inside a <th> (table header) tag.

Item (2) tests for a non-blank label.

Columns are defined in label+field pairs, so item (3) will extract the value of the field attribute in the following sibling node and pass it to the column_hdg template.

Item (4) will cause this template to be repeated until the value in $count has been reduced to 1.

This template is used to create the HTML control for each field. The type of control to be used is passed as an attribute in the XML file, and this value is then used to activate the relevant sub-template. This allows the HTML control type to be decided at runtime instead of being hard-coded within the component stylesheet. Any other values required by individual templates for their control types must be supplied as additional attributes within the XML file.

This is responsible for outputting the data for a single database occurrence in a vertical arrangement, as can be found on DETAIL screens. Note that this allows a row to contain more than one field, and for a field to span more than one row.

Using the techniques described above has allowed me to achieve a significant amount of reusability with my XSL code. By maintaining the contents of standard templates in separate files which can be referenced by the <xsl:include> statement I have effectively created a library of standard subroutines.

Another area of reusability I have incorporated into my design revolves around the use of form families where a typical database table requires 6 forms to handle its maintenance - a LIST/BROWSE form, a SEARCH form, an INSERT form, an UPDATE form, an ENQUIRY form and a DELETE form. The LIST/BROWSE form deals with multiple rows displayed horizontally whereas all the others deal with a single row which is displayed vertically. Because this last set of forms all use the same layout I am able to satisfy them all with a single detail stylesheet. By passing a $mode parameter at runtime (containing the value "search", "insert" "update", "read" or "delete") I am able to determine at runtime whether the fields are to be amendable or read-only and therefore create the relevant HTML code.

Unlike stage (1) where each XSL stylesheet contains hard-code field names and hard-coded HTML controls, and stage (2) where each HTML control is built using a single standard template, it is possible, as shown in stage (3), to call a higher-level template which works out which HTML control is required based on the contents of the field's control attribute in the XML document. This makes it possible for the XSL stylesheet not to know until run time which control is needed for any field, and for the application to switch any field from one HTML control to another during the execution of any business rules which are processed before the control attribute is actually added to the XML document. Other attributes which affect the way each HTML control is built may also be specified:

size

Determines the size of the text box.

pkey

Identifies the field as part of the primary key.

noedit

Makes the field read-only.

nodisplay

Excludes the field from the HTML output.

control

Identifies the control type. The default is "text", but can be "dropdown", "boolean", "radiogroup", "popup" or "multiline".

If you think that the previous 3 stages provide sufficient reusability in your XSL stylesheets then stage (4) shows you how to reach a whole new level. By having the list of field names to be processed passed in as parameters via the XML document instead of being hard-coded into each and every XSL stylesheet means that one single stylesheet can be used with many different screens of the same structure. This means less work and less time for the developers, and shorter timescales and lower costs for the customers. All you need is a way for the application to define what screen structure it needs, and to pass this structure to the XML document for processing by the XSL stylesheet.

The first step was to include in my XML file the necessary elements to identify which tables and fields were to be processed, and in what order. Here is a sample of the screen structure information which appears in the XML file for detail screens:

This information is supplied to my application in the form of a PHP "include" file, as shown in the following sample. I have a standard PHP function which reads this in and adds the details to the current XML file.

I have heard some people complain that XSL is too verbose, and that it takes an enormous amount of code to do even the most simple things. These people obviously do not know how to structure their code into reusable modules. As I (hope) I have demonstrated in this article, the steps to creating reusable XSL code are not that much different from creating reusable code in any other programming language:

Divide the HTML page layout into separate zones.

Create a separate XSL template to process each zone.

Put the code for each template into a separate file. You may use a separate file for each template, or you may group several similar templates into a single file.

Incorporate the required templates into individual stylesheets by using the <xsl:include> statement. This makes the template available to the stylesheet at runtime, and has the same effect as calling a routine from an external library.

Use the same DETAIL stylesheet for multiple modes - search, input, update, enquiry and delete.

Use a common template to deal with all fields. In this way the XML file determines which HTML control is to be used, not the XSL stylesheet.

Get the XML file to identify the table and field names that need to be processed. In this way each screen can use a generic stylesheet instead of having its own customised version.

By using these techniques I have created a web application of over 500 screens using a dozen or so generic XSL stylesheets and a collection of standard XSL templates. This means that the speed at which I can create a new component which can use an existing stylesheet is greatly increased. Because each stylesheet is merely a collection of calls to standard templates then even the creation of a new stylesheet is now a minor matter. Just imagine how much extra effort would be required if each of those 500 screens had to be hand crafted!

Updated the description of the XML file structure so that it reflects the ability for detail screens to have more than one field on the same line, and for screen text to be available in different languages following the introduction of internationalisation facilities.