The Web Sock: Building Simple Web Sites

Trevor Nash

Melvaig Software Engineering Limited

Table of Contents

1. The Web Site Sock
Getting Started
Test Mode
Style
Organisation
Page Level Things

Chapter 1. The Web Site Sock

Getting Started

To produce a Web site using this kit you write an XML document which specifies a few pieces of administrative information and overall style parameters followed by individual page contents structured as a tree. Look in examples/simple_website for an example of such a document and the resulting HTML. You should read three things:

  • website.sck, the input specification in XML: this contains XML comments describing what to write.

  • website.html, which documents what the site is for and how it is constructed. The Web kit is designed not to reproduce the entire site within this document: you just get a summary.

  • index.html, the entry point to the site. The site is produced in test mode (see below) so there are edit icons to give you easy access to the corresponding part of the input specification.

A word to newcomers to Sock: the program has an 'HTML' option. This option produces an HTML rendition of the input document, which is not the same thing as the Web site. To get the HTML files which make up the Web site you use the 'process' option, as you would for any other kind of output.

You may want to write the specification in the form of a DocBook document in order to produce documentation about how the site is structured.

Test Mode

During development it is useful to have an 'edit' icon on each page which allows the corresponding source code to be edited. To do this place the following declaration in the site specification:


<sk:object name="w:mode">
<sk:replace>
<sk:declare>
   <xsl:param name="dev-mode" select="true()" />
</sk:declare>
</sk:replace>
</sk:object>

When the site is complete, change the value to false() - note the parentheses, which are necessary because in XSLT the boolean 'constants' are function calls, not literal values. If you do not use the edit icons, put the declaration in with the value false(). If you omit the declaration altogether you will get a complaint about an undeclared variable.

To support editing in development mode, this kit imports the Sock Interface Kit.

Style

To set the page colours, instantiate either w:colors or w:colours, depending on which side of the Atlantic you live. @body gives the main background colour, @navigation gives the background colour used for the navigation pane.

For Object w:colours replacement:
<sk:replace>
<sk:source sink.id="body-color">
  <sk:attribute name="bgcolor">
     <xsl:value-of select="@body"/>
  </sk:attribute>
</sk:source>
<sk:source sink.id="nav-color">
  <sk:attribute name="bgcolor">
     <xsl:value-of select="@navigation"/>
  </sk:attribute>
</sk:source>
</sk:replace>
For Object w:colours presentation:
<sk:presentation>
<xsl:text>The background color is </xsl:text>
<xsl:value-of select="@body"/>
<xsl:text> with </xsl:text>
<xsl:value-of select="@navigation"/>
<xsl:text> for the navigation pane.  </xsl:text>
</sk:presentation>
For Object w:colors replacement:
<sk:replace>
The background color is  with  for the navigation pane.  
</sk:replace>
For Object w:colors presentation:
<sk:presentation>
<xsl:text>The body colour is </xsl:text>
<xsl:value-of select="@body"/>
<xsl:text> with </xsl:text>
<xsl:value-of select="@navigation"/>
<xsl:text> for the navigation pane.  </xsl:text>
</sk:presentation>

In the 'Tabular' version of the output we draw a tree of links to form a navigation pane on the left hand side. To allow the current page to be marked in some way we provide two objects, one to provide the mark for the current page and one for all the others. There are two objects rather than just one because a typical use is to insert a graphic: to keep everything lined up the two markers should be the same size. By default we supply no marker.

For Object w:current-marker replacement:
<sk:replace/>
For Object w:other-marker replacement:
<sk:replace/>

Header and footer areas should contain things like company logo, copyrights and so on. These will probably be different for each format of site. To define these, give a replacement for w:header and w:footer. These have two attributes:

  • class: this is copied from the w:page element, allowing arbitrary variation between pages.

  • style: the name of the style, for example 'tabular' or 'plain', allowing different replacements in different styles.

By default we supply empty headers and footers.
For Object w:header replacement:
<sk:replace/>
For Object w:header presentation:
<sk:presentation/>
For Object w:footer replacement:
<sk:replace/>
For Object w:footer presentation:
<sk:presentation/>

Organisation

The main index page is free format: the main purpose is to let the user select the preferred style of site.

For Object w:index-page replacement:
<sk:replace>
<sk:file id="index" name="docs/index.html">
   <html>
      <head>
         <title><xsl:copy-of select="db:title"/></title>
      </head>
      <body sk:sink="body-color">
         <sk:instantiate select="w:body/node()"/>
      </body>
   </html>
</sk:file>
</sk:replace>
For Object w:index-page presentation:
<sk:presentation>
<db:section>
<db:title>The Index Page</db:title>
<xsl:value-of select="w:title"/>
</db:section>
</sk:presentation>

Any other page. The w:page element has an optional attribute class which may be used in the replacement for w:header and w:footer, allowing the page layout to be varied.

For Object w:page replacement:
<sk:replace>
<sk:declare>
   <xsl:key name="navbar" match="w:page" use="parent::*/descendant-or-self::w:page/@name | @name"/>
</sk:declare>
<xsl:variable name="name" select="@name"/>
<sk:source sink.id="body-text" file.id="{$name}-tabular">
   <sk:instantiate select="w:body/node()"/>
</sk:source>
<sk:instantiate select="w:page"/>
<sk:file id="{$name}-tabular" name="docs/tabular/{$name}.html">
   <html>
      <head>
         <title><xsl:value-of select="w:title"/></title>
	 <xsl:if test="$dev-mode">
	    <ski:edit-script/>
	 </xsl:if>
      </head>
      <body sk:sink="body-color">
         
         <table cellpadding="5">
	    <tr>
	       <td width="150" valign="top" sk:sink="nav-color">
	          <xsl:for-each select="key('navbar', @name)">
		     <xsl:for-each select="ancestor::w:page">  </xsl:for-each>
		     <xsl:choose>
		        <xsl:when test="@name=$name">
			   <w:current-marker style="tabular"/>
			</xsl:when>
			<xsl:otherwise>
			   <w:other-marker style="tabular"/>
			</xsl:otherwise>
	             </xsl:choose>
		     <xsl:choose>
		        <xsl:when test="@nav='no'">
		           <xsl:value-of select="@link"/>
                           <br/>
			</xsl:when>
		        <xsl:when test="@nav='hide'">
			   <xsl:if test="$dev-mode">
		              <a href="{@name}.html">(<xsl:value-of select="@link"/>)</a>
                              <br/>
			   </xsl:if>
			</xsl:when>
			<xsl:otherwise>
		           <a href="{@name}.html"><xsl:value-of select="@link"/></a>
                           <br/>
			</xsl:otherwise>
	              </xsl:choose>
		  </xsl:for-each>
		  <xsl:if test="$dev-mode">
		      <ski:edit-drag-source m21.dir=".." file="{substring-after (saxon:systemId(), '/')}" line="{saxon:lineNumber()}"/> Navigation<br/>
		      <xsl:for-each select="w:body">
		         <ski:edit-drag-source m21.dir=".." file="{substring-after (saxon:systemId(), '/')}" line="{saxon:lineNumber()}"/> Page
		      </xsl:for-each>
                  </xsl:if>
	       </td>
	       <td valign="top">
	       <sk:sink id="body-text"/>
	       </td>
	    </tr>
	 </table>
         
      </body>
   </html>
</sk:file>
</sk:replace>
For Object w:page replacement:
<sk:replace>
<sk:source sink.id="body-text" file.id="{$name}-plain">
   <sk:instantiate select="w:body/node()"/>
</sk:source>
<sk:file id="{$name}-plain" name="docs/plain/{$name}.html">
   <html>
      <head>
         <title><xsl:value-of select="w:title"/></title>
	 <xsl:if test="$dev-mode">
	    <ski:edit-script/>
	 </xsl:if>
      </head>
      <body sk:sink="body-color">
         
	 <xsl:for-each select="ancestor::w:page">
	    <a href="{@name}.html"><xsl:value-of select="@link"/></a><xsl:text>-></xsl:text>
	 </xsl:for-each>
	 <xsl:value-of select="@link"/>
	 <hr/>
	 <sk:sink id="body-text"/>
	 <hr/>
	 <xsl:for-each select="parent::w:page/w:page">
            <xsl:choose>
	       <xsl:when test="@name=$name">
	          <w:current-marker style="plain"/>
		  <xsl:value-of select="@link"/>  
	       </xsl:when>
	       <xsl:otherwise>
	          <w:other-marker style="plain"/>
		  <xsl:choose>
		     <xsl:when test="@nav='no'">
		        <xsl:value-of select="@link"/>  
                     </xsl:when>
		     <xsl:when test="@nav='hide'">
		        <xsl:if test="$dev-mode">
			   <a href="{@name}.html">(<xsl:value-of select="@link"/>)</a>  
                        </xsl:if>
		     </xsl:when>
                     <xsl:otherwise>
		        <a href="{@name}.html"><xsl:value-of select="@link"/></a>  
                     </xsl:otherwise>
	          </xsl:choose>
	       </xsl:otherwise>
	    </xsl:choose>
         </xsl:for-each>
	 <br/>
	 <xsl:for-each select="w:page">
		  <xsl:choose>
		     <xsl:when test="@nav='no'">
		        <xsl:value-of select="@link"/>  
                     </xsl:when>
		     <xsl:when test="@nav='hide'">
		        <xsl:if test="$dev-mode">
		           <a href="{@name}.html">(<xsl:value-of select="@link"/>)</a>  
                        </xsl:if>
		     </xsl:when>
                     <xsl:otherwise>
		        <a href="{@name}.html"><xsl:value-of select="@link"/></a>  
                     </xsl:otherwise>
	          </xsl:choose>
         </xsl:for-each>
	 <xsl:if test="$dev-mode">
	    <hr/>
	    <ski:edit-drag-source m21.dir=".." file="{substring-after (saxon:systemId(), '/')}" line="{saxon:lineNumber()}"/> Navigation     
	       <xsl:for-each select="w:body">
		   <ski:edit-drag-source m21.dir=".." file="{substring-after (saxon:systemId(), '/')}" line="{saxon:lineNumber()}"/> Page
	       </xsl:for-each>
	    <hr/>
         </xsl:if>
         
      </body>
   </html>
</sk:file>
</sk:replace>
For Object w:page presentation:
<sk:presentation>
<!-- use a template to process all the w:page nodes recursively,
     writing out the titles to show the site structure -->
   <sk:declare>
      <xsl:template match="w:page" mode="summary">
         <xsl:apply-templates select="w:title" mode="summary"/>
	 <xsl:if test="w:page">
	    <itemizedlist>
	       <xsl:for-each select="w:page">
	          <listitem>
	             <xsl:apply-templates select="." mode="summary"/>
	          </listitem>
	       </xsl:for-each>
	    </itemizedlist>
	 </xsl:if>
      </xsl:template>
   </sk:declare>
   <section>
   <title>Site Structure</title>
   <xsl:apply-templates select="." mode="summary"/>
   </section>
</sk:presentation>

Page Level Things

For Object w:title generate:
<sk:generate><h2><sk:instantiate/></h2></sk:generate>

An external link.

For Object w:link[@href] write:
<sk:write><a href="{@href}">
<xsl:choose>
<xsl:when test=".=''"><xsl:value-of select="@href"/></xsl:when>
<xsl:otherwise><xsl:value-of select="."/></xsl:otherwise>
</xsl:choose>
</a>
</sk:write>

An internal link.

For Object w:link[@id] generate:
<sk:generate>
<sk:declare>
    <xsl:key name="pages" match="w:page" use="@name"/>
</sk:declare>
<xsl:variable name="target" select="key('pages', @id)"/>
<a>
<xsl:choose>
  <xsl:when test="@anchor">
    <xsl:attribute name="href">
       <xsl:value-of select="$target/@name"/>
       <xsl:text>.html#</xsl:text>
       <xsl:value-of select="@anchor"/>
    </xsl:attribute>
  </xsl:when>
  <xsl:otherwise>
    <xsl:attribute name="href">
       <xsl:value-of select="$target/@name"/>
       <xsl:text>.html</xsl:text>
    </xsl:attribute>
  </xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test=".=''"><xsl:value-of select="$target/@link"/></xsl:when>
<xsl:otherwise><xsl:value-of select="."/></xsl:otherwise>
</xsl:choose>
</a>
</sk:generate>

An internal link to the next page in sequence.

For Object w:link-next replacement:
<sk:replace>
<xsl:variable name="target" select="following::w:page[1]"/>
<a href="{$target/@name}.html">
<xsl:choose>
<xsl:when test=".=''">Next</xsl:when>
<xsl:otherwise><xsl:value-of select="."/></xsl:otherwise>
</xsl:choose>
</a>
</sk:replace>