Component-Based Page Layouts
February 16, 2000
Resources |
•James Clark's XT
XSLT processor |
Printed newspapers and magazines are created by a team of content authors, editors, and people whose task it is to aggregate and lay out the content in a coherent and pleasing way.
Let's take the example of a magazine and simplify the workflow a little: authors deliver their content to the editor, who (obviously) edits the content. Subsequently, the content is ready to be positioned in the magazine's page layout. Content is not necessarily limited to text, but may also contain illustrations.
An electronic magazine is also an assemblage of text and image content. Moreover, other kinds of components can be included in a web page, including interactive components like applets, plug-ins, or ActiveX objects. Each component may be produced by a different author.
Let's examine how the assembly of such a site can be done with XHTML. XHTML is part of the next generation of publishing languages for the Web. One main advantage of XHTML is that, in contrast to its predecessor HTML, it can be extended with new elements. This article will demonstrate how, by using new elements and XSLT transformation sheets, you can aggregate content coming from external documents into a single XHTML document.
A Basic XHTML Page Layout
Well-structured web sites have an integrated look and feel. If each individual component author created his or her own vision of the site, it would end up very disorganized and visually confusing.
Looking at the structure of most web sites, we notice that they have a similar visual layout. At the top, a header; at the bottom, a footer; at the left, a navigation area or table of contents; and, at the right, the content. This visual structure is illustrated in figure 1.
Figure 1: Typical site layout |
In the XHTML world, one way to create a layout like that shown in Figure 1 is to use
either
a frameset or a table. (In order to support the widest range of browsers, we must
use both
in the same page.) In XHTML, as well as in HTML 4.01, the <frameset>
element should be used in tandem with the <noframe>
element. The
<noframe>
element's content is used by browsers that do not support
frames. This element can contain a table, and the table's cells can contain the components
of the frameset. "But wait a minute," you ask, "How can I still use the components
as
separate documents in the <noframe>
section?" Indeed, a good
question.
Expand XHTML with a component Element
We know it is possible to include components as separate documents in a
<frameset>
element, but not in the <noframe>
section. Let's then include in the <noframe>
section elements of our
own invention named <xscript:component>
, and use a bit of XSLT
magic to obtain the same effect we get with the <frameset>
construct.
The key to XHTML is the letter X, which indicates that it is eXtensible. This means
we can add our own elements when we need to. So, to obtain the same layout in the
<noframe>
section that we get in the <frameset>
section, we add to our XHTML a new element that is used to include external document
content
in cells of the table.
Inheriting Attributes From xlink:simple
The new element, component
, is basically a link to a resource. The latest
XLink working draft makes it possible for an element to inherit the linking behavior
from
one of the XLink elements. XLink proposes two kind of links:
- a one-to-one link
- a one-to-many link
Since we need our <xstyle:component>
element to link to a single
resource, we then use the xlink:type="simple"
attribute that will transform our
element into a link. Several other attributes from the XLink language (like
xlink:href, xlink:title, xlink:show
) are also useful, so let's integrate them
into our element's list of attributes.
Using XSLT as an XLink Interpreter
An important thing to mention here is that we are using the XSLT engine as an XLink
interpreter. More specifically, it interprets the link behavior indicated by the
xlink:show
attribute. When this is set to the "embed" value, the content of
the linked resource is included in a table cell. Otherwise an error message is included.
To the xlink
attributes we add xstyle
attributes to indicate the
component's MIME type, its height, its width, and the role it plays in the layout.
The
xstyle
prefix denotes that the attributes are of our invention; we will
associate the prefix xstyle
with the namespace URI of our choice (in this case
http://www.talva.com/2000/xstyle). We do not use the xlink:role
attribute because we want to indicate the semantic meaning of the element in a layout
context, not in a linkage context. So, our element is a link to an external resource,
and
its basic properties are described by the following attributes:
xlink:type = "simple"
xlink:href = "URI"
xlink:title = "string"
xlink:show = "embed"
xstyle:type = "MIME type, e.g., image/svg or
text/xhtml"
xstyle:height = "numerical value or percentage"
xstyle:width =
"numerical value or percentage"
xstyle:role =
"header|footer|table-of-content|content"
For instance, the <xstyle:component>
, which links our web site template
to the header component (in this case, a vector graphics SVG document), looks like
this:
<xstyle:component xlink:type="simple" xlink:href="header.svg" xlink:title="Header Layout Object" xlink:show="embed" xstyle:type="image/svg" xstyle:height="100%" xstyle:width="100%" xstyle:role="header"/>
Our XSLT transformation sheet must interpret the <xstyle:component>
element by first looking for the xlink:show
attribute. If this is set to the
embed
value, then the xstyle:type
attribute is used as a switch
to select the appropriate behavior.
For instance, in our example XSLT transformation sheet, every component of type "image/svg"
is converted into an <embed>
element, which can then be displayed in a
web browser using the Adobe SVG
plug-in (now freely available from Adobe's site).
In cases where the xstyle:type
attribute is set to "text/xhtm", the referred
document's content is inserted in the table cell.
Examining the XSLT Transformation Sheet
The template performing the XLink interpretation is the one that matches the
<xstyle:component>
elements:
<xsl:template match="xstyle:component"> <xsl:choose> <!-- we embed the component's content only if the xlink:show attribute is set to 'embed' --> <xsl:when test="contains(@xlink:show,'embed')"> <xsl:choose> <xsl:when test="contains(@xstyle:type,'image/svg')"> <embed type="image/svg"> <xsl:attribute name="src"> <xsl:value-of select="./@xlink:href"/> </xsl:attribute> <xsl:attribute name="height"> <xsl:value-of select="./@xstyle:height"/> </xsl:attribute> <xsl:attribute name="width"> <xsl:value-of select="./@xstyle:width"/> </xsl:attribute> </embed> </xsl:when> <xsl:when test="contains(@xstyle:type,'text/xhtm')"> <xsl:apply-templates select="document(@xlink:href)/html:html/html:body/*"/> </xsl:when> <!-- put here other xstyle formats identified by the xstyle:type attribute. the attribute's value is the component MIME type. For example, if the component is an SVG document, then its MIME type is "image/svg". --> </xsl:choose> </xsl:when> <xsl:otherwise> <!-- We include an error message in the output document if the intended behavior is not to embed the content --> <p>Error: the <xstyle:component> elements only support the xlink:show attribute set to the value "embed".</p> </xsl:otherwise> </xsl:choose> </xsl:template>
When an <xstyle:component>
is matched by the template and the
xstyle:type
is equal to "text/xhtm", then the external document's content is
loaded, parsed, and the resultant node set included in the current node set. In our
case,
the external document content replaces the <xstyle:component>
element.
Thus, each time an <xstyle:component>
element is encountered by the XSLT
engine, it is replaced by the external document's content. This magic is accomplished
with
the document()
function.
However, we do not want to include the entire external document's content in each
table cell. For example, the XHTML <head>
element has no place in a
table! We only want to include the content of each external document
<body>
element. This is accomplished by the following expression.
<xsl:apply-templates select="document(@xlink:href)/html:html/html:body/*"/>
(Note that html
prefix is associated with the namespace URI for XHTML,
http://www.w3.org/1999/xhtml).
Now that we have extracted the right node set, we simply want to copy its content
as a
replacement for the <xstyle:component>
node. The following template does
just that:
<xsl:template match="*|@*|text()"> <xsl:copy> <xsl:apply-templates select="*|@*|text()"/> </xsl:copy> </xsl:template>
Now, Let's Go to the Lab....
If you are tempted to do some exploration of your own, here is my proposal for this week's lab experiment.But first, to do this experiment, you'll need an XSLT engine that is as compliant as possible with the 1999 W3C XSLT Recommendation. I used James Clark's XT processor.
- Place the following documents in the same directory: toc.htm, content.htm, footer.htm, header.svg, template.htm, template.xsl.
- Go get the Adobe SVG Viewer; you'll need it to view the SVG drawing (and also for a future lab experiment...).
- Process the template.htm document with the
template.xsl transformation sheet in order
to replace all
<xstyle:component>
elements with the appropriate content extracted from the external components (i.e., documents). - Try it with your own components.
You can also simply look at the template document, the transformation sheet, and the resultant document. Because the template.htm document is an XHTML document, your browser should immediately interpret and render it. Use the "View Source" option to examine its source.