| XML, XSL, two of a family of extensible languages | ||
|---|---|---|
![]() | ![]() ![]() | |
XSLT transforms an XML input document into a hierarchical result tree, which often is serialised as an XML instance (see figure).
You can also serialise the output as XSL formatting objects, which can be further transformed into a printable or viewable output format (see figure)
Finally, you can also generate non-XML output, that can be interpreted by a dedicated parser (I shall give an example of direct transformation into LaTeX).
The XSLT processor ignored the DTD and any comments and processing instructions present in the input XML document.
The output result tree can be constructed by pulling the data (mainly by the instructions <xsl:value-of> and <xsl:for-each>. This approach worked all right if the structure of the input source is quite static and known.
Alternatively, when the source structure is only partly known it might be better to push the input data, i.e., let the construction of the result tree be driven by the data themselves. Here one can use the <apply-templates> instruction.
In most practical situations a combination of both these approaches is probably a winning strategy.
Let us start with the simplest possible stylesheet, an empty one.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0"> </xsl:stylesheet> |
When we run this stylesheet with one of the XSL processors (xt or lotusxsl), we get the following
> lotusxsl.sh welcome.xml empty.xsl ========= Parsing and preparing empty.xsl ========== Parsing and init of empty.xsl took 1516 milliseconds ========= Parsing welcome.xml ========== Parse of welcome.xml took 244 milliseconds ============================= Transforming welcome.xml via Input XSL... transform took 127 milliseconds Total time took 482 milliseconds XSLProcessor: done Welcome to the world of XML! |
We now construct a stylesheet which is a little more complicated for our example:
<?xml version='1.0'?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0"> <xsl:output method="html"/> <xsl:template match="/"> <html> <em><b><xsl:apply-templates/></b></em> </html> </xsl:template> </xsl:stylesheet> |
> xt welcome.xml welcome.xsl <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <em><b>Welcome to the world of XML!</b></em> </html> |
In the above example the data were pushed through to the output, but we could also pull them ourselves (although this example is too trivial to make the point clearly).
<?xml version='1.0'?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0"> <xsl:output method="html"/> <xsl:template match="/"> <html> <em><b><xsl:value-of select="."/></b></em> </html> </xsl:template> </xsl:stylesheet> |
As it is so common that XML files will be transformed into HTML, a special simplified syntax, without explicit templates, is provided (in fact the template for the root node is implicit).
<html xmlns:xsl="http://www.w3.org/XSL/Transform/1.0"
xmlns="http://www.w3.org/TR/xhtml1">
<em><b><xsl:value-of select="."/></b></em>
</html>
|
> xt welcome.xml welcome1.xsl <html xmlns="http://www.w3.org/TR/xhtml1"> <em><b>Welcome to the world of XML!</b></em> </html> |
The various elements that are possible at the top level of a stylesheet are listed below.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0"> <xsl:import href="..."/> <xsl:include href="..."/> <xsl:strip-space elements="..."/> <xsl:preserve-space elements="..."/> <xsl:output method="..."/> <xsl:key name="..." match="..." use="..."/> <xsl:locale name="..."> ... </xsl:locale> <xsl:attribute-set name="..."> ... </xsl:attribute-set> <xsl:variable name="...">...</xsl:variable> <xsl:param name="...">...</xsl:param> <xsl:template match="..."> ... </xsl:template> <xsl:template name="..."> ... </xsl:template> </xsl:stylesheet> |
The figure shows graphically how a single instruction in the stylesheet obtains information about a particular point in the source tree. Part of the input tree and then copied or transformed and copied to the result tree.
A few examples of patterns follow.
[1] Pattern ::= LocationPathPattern
| Pattern '|' LocationPathPattern
[2] LocationPathPattern ::= '/' RelativePathPattern?
| IdKeyPattern (('/' | '//')
RelativePathPattern)?
| '//'? RelativePathPattern
[3] IdKeyPattern ::= 'id' '(' Literal ')'
| 'key' '(' Literal ',' Literal ')'
[4] RelativePathPattern ::= StepPattern
| RelativePathPattern '/' StepPattern
| RelativePathPattern '//'
StepPattern
[5] StepPattern ::= AbbreviatedAxisSpecifier NodeTest
Predicate*
|
A template rule is specified with the xsl:template element. The match attribute is a Pattern that identifies the source node or nodes to which the rule applies.
The following template rule matches hi elements and has a template, which produces a fo:inline-sequence formatting object with a font-weight property of italic.
<xsl:template match="hi">
<fo:inline-sequence font-style="italic">
<xsl:apply-templates/>
</fo:inline-sequence>
</xsl:template>
|
The <xsl:apply-templates/> instruction processes all of the children of the current node, including text nodes.
Conflict resolution is handled explicitly (with a priority attribute, or implicitly via a set of rules (which behave as one would expect in most cases). When in doubt, use the priority attribute.
Modes allow an element to be processed multiple times, each time producing a different result. Such a mode can be specified on both xsl:template and xsl:apply-templates instruction via an optional mode attribute.
There is a built-in template rule to allow recursive processing to continue in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node.
<xsl:template match="*|/"> <xsl:apply-templates/> </xsl:template> |
There is a built-in template rule for each mode, which allows recursive processing to continue in the same mode in the absence of a successful pattern match by an explicit template rule in the stylesheet.
<xsl:template match="*|/" mode="m"> <xsl:apply-templates mode="m"/> </xsl:template> |
Similarly, the built-in template rule for text and attribute nodes just copies text through:
<xsl:template match="text()|@*"> <xsl:value-of select="."/> </xsl:template> |
The built-in template rule for processing instructions and comments is to do nothing.
<xsl:template match="processing-instruction()|comment()"/> |
These built-in template rules have have a lower import precedence than all other template rules. Thus, the author can override a built-in template rule by including an explicit template rule.
The list of XSLT functions, with their type, argument(s), and the section where they are defined in the (August 1999) XSLT WD is given.
Suppose you have the following input fragment:
<chapter id="H1Introduction"> <stitle>Introduction</stitle> <section> <stitle>What is XML?</stitle> |
<xsl:template match="chapter/stitle">
<xsl:call-template name="sectionhead">
<xsl:with-param name="level">1</xsl:param>
</xsl:call-template>
</xsl:template>
<xsl:template match="section/stitle">
<xsl:call-template name="sectionhead">
<xsl:with-param name="level" select="2"/>
</xsl:call-template>
</xsl:template>
|
<xsl:template name="makeheading">
<xsl:choose>
<xsl:when test="ancestor::appendix">
<xsl:number count="chapter" format="A."/>
</xsl:when>
<xsl:otherwise>
<xsl:number format="1." count="chapter"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="ancestor::section">
<xsl:number level="multiple"
count="section|subsection"
format="1.1. "/>
</xsl:when>
<xsl:otherwise>
<xsl:text> </xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</xsl:template>
<xsl:template name="sectionhead">
<xsl:param name="level" select="1"/>
<xsl:element name="H{$level}">
<xsl:choose>
<xsl:when test="../@id">
<A NAME="{../@id}">
<xsl:call-template name="makeheading"/>
</A>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="makeheading"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
|


