SDK - Your second WCM XSLT stylesheet

  • KM507252
  • 20-Sep-2008
  • 20-Sep-2008

Archived Content: This information is no longer maintained and is provided "as is" for your convenience.

Reference

Your second WCM XSLT stylesheet

Overview

Using the techniques displayed in the first sample XSLT style sheet it is possible to create a static HTML page. Our second sample will show how to expose some of the content stored in WCM in a HTML page.

Prerequisites

The sample XSLT requires a page template with at least two custom fields:

  • an HTML field named “content”, and
  • a site map field named “menu”.

Of course different field names may be used as long as the XSLT is modified appropriately.

Sample XSLT

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:wcm="http://www.towersoft.com/ns/wcm/1.0"
exclude-result-prefixes="wcm">

<xsl:output 
	method="html" 
	doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" 
	doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" />

<xsl:template match="/wcm:wcm">
	<html>
		<head>
		<!-- CSS borrowed from http://alistapart.com/articles/flexiblelayouts/	-->
			<style type="text/css" media="all">
				body {
					margin: 0;
				}

				#hd {
					position:relative;
					left:0;
					top:0;
					background-color:#C3D9FF;
				}

				#bd {
					position:relative;
					left:0;
					top:0;
					min-height:400px; /* min-height does not work in IE 6 or below */
				}

				#ft {
					position:relative;
					left:0;
					top:0;
					background-color:#C3D9FF;
				}

				#sidebar {
					position:absolute;
					top:0;
					left:0;
					width:20%;
				}

				#content {
					position:relative;
					top:0;
					left:25%;
					width:60%;
				}
		
				#sidebar li {
					list-style-type: none;
				}

			</style>

		<!-- This is just some IE 6 (and below) specific code to make sure the footer does not overwrite 	-->
		<!-- the menu when there is not enough content in the body to push the footer down.		-->
			<!--[if lte IE 6]>
			<style type="text/css" media="all">
				#bd {
					height:400px;
				}
			</style>
			<![endif]-->
		</head>
		<body>
			<div id="hd">This is the heading</div>
			<div id="bd">
				<div id="sidebar">
					<xsl:apply-templates select="customFields/customField[@name='menu']/sections" />
				</div>
				<div id="content">
					<xsl:apply-templates select="customFields/customField[@name='content']" />
				</div>
			</div>
			<div id="ft">This is the footer</div>				
		</body>
	</html>
</xsl:template>

<!-- *** The following two templates insert the contents of an HTML type custom field	*** -->
<!-- *** without the annoying XML namespace information that xsl:copy inserts	*** -->
<!-- Code taken from http://www.stylusstudio.com/xsllist/200301/post40330.html	*** -->
<xsl:template match="customField[@type='Html']">
<xsl:choose>
	<xsl:when test="html">
		<xsl:apply-templates select="html/* | html/text()" mode="copy-no-ns" />
	</xsl:when>
	<xsl:otherwise>
		<xsl:value-of disable-output-escaping="yes" select="./text()"/>
	</xsl:otherwise>
</xsl:choose>

</xsl:template>

<xsl:template mode="copy-no-ns" match="*">
<xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
	<xsl:copy-of select="@*"/>
	<xsl:apply-templates mode="copy-no-ns"/>
</xsl:element>
</xsl:template>


<!-- *** XSLT to build menu						*** -->
<!-- *** Wrap the top level items in a UL *** -->
<xsl:template match="customField/sections">
<ul>
	<xsl:apply-templates select="listItem[not(@isHidden='true')]" />
</ul>
</xsl:template>

<!-- *** Handle each listItem.  If it the listItem links to the current page (or one of its parents) then	*** -->
<!-- *** check to see if there are any child links to display.				*** -->
<xsl:template match="listItem">
<!-- Don't show link to a page that is the default for a section as the section link does this.		-->
<xsl:if test="not(@isDefault)"> 
<li>
	<a>
		<xsl:attribute name="href">
			<xsl:value-of select="url" />
		</xsl:attribute>
		<xsl:value-of select="menuText" />
	</a>

	<!-- Show children if the current list item is the item for the page section, 			-->
	<!-- or if the current list item is in the path (i.e. it is the current page or one of its parents. 	-->
	<xsl:if test="sectionId = /wcm:wcm/docDetails/path/listItem/id 
		or id = /wcm:wcm/docDetails/path/listItem/id">

		<!-- only create the next level UL if there is at least one page or section.  The sections 	-->
		<!-- and/or pages elements will only exist if there are sections or pages.		-->
		<xsl:if test="pages | sections">
			<ul>
				<xsl:apply-templates select="*/listItem[not(@isHidden='true')]" />
			</ul>
		</xsl:if>
	</xsl:if>
</li>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

Sample XML

The XML (generated by WCM) used by the above XSLT looks like this.

Examination of Sample XSLT

The various components of this XSLT, while included as a single XSLT template for this sample, would probably best be implemented as at least two XSLT style sheets and one CSS style sheet. The xsl:include element would be used to include a ‘library’ style sheet containing the menu and body XSLT and an HTML link element would be used to link to the CSS style sheet.

CSS Layout

The XSLT includes some basic CSS to display the content in three rows and two columns. There are a multitude of web sites devoted to providing more sophisticated layouts than this sample, including:

Body

Given that the HTML content is a block of XHTML stored in a single custom field it is possible to include it using the xsl:copy element (e.g. <xsl:copy select=”customFields/customField[@name=’HTMLBody’]/html/*” />). This method will, however, result in unwanted xml namespace information being included in the output HTML. To avoid this xsl:apply-templates is used to write the content HTML out element by element, avoiding the extra namespace information.

Menu

The menu XSLT is designed to read all the entries from the underlying sitemap XML and create a set of nested lists (HTML, UL and LI elements). Because the sitemap XML is arranged hierarchically the XSLT can read from the top level through the child elements to build the nested lists.

The key logic to be aware of is that which chooses whether, or not, to write the child elements of the current menu element. Because the site map is based on the hierarchy of sections the XSLT can rely on the docDetails/path information, which lists the current page and all of its parents, to decide whether to display an item’s children.

As the XSLT iterates through the menu XML it asks whether the current item is either:

  • the item for the parent section of the current page, or
  • an item which is an ancestor of the current item.

If either is true the children of the current item are written, thus displaying a full hierarchical menu.

Note: To include pages as well as sections in the menu check the “Include pages in a site map” checkbox when editing the page with the menu custom field.