Page Templates

Version: 1.0.0
Date: 2005-11-03
Changes:Initial version.

Abstract

Overview of the design and implementation of ePublisher page templates.

1   Introduction

The structured presentation of information fuses design with logic. One approach, traditional web CGI applications, force design (HTML) to exist inside logic (program source code). Another approach, ASP and PHP, invert this relationship and force logic (program source code) to exist inside the design (HTML). Neither approach is ideal. In one case, designers lack creative freedom. In the other, programmers complain that designers keep breaking their code.

The page template model is a new approach with the goal of satisfying both designers and programmers. It has been successfully used in projects like Zope, Plone, Woven, and Nevow. ePublisher uses a page template model based on priciples outlined in Woven and Nevow.

1.1   Changes

Initial version.

2   Design with Structure

Traditional design/logic methods require design tool support to be effective. Products such as DreamWeaver, FrontPage, and GoLive went through many iterations before HTML code changes would not remove ASP/PHP code:

...
<h2>
 <% date.current() %>
</h2>
...

Still further iterations were required before environments like ColdFusion could have their custom tags preserved:

...
<h2>
 <DataConnection table="random" ... />
</h2>
...

Woven and Nevow side-step the issue by using custom attributes rather than using custom elements or comments.

<h2 nevow:render="greet" />

The resulting markup can be previewed in 4.x series browers and edited with first generation design tools.

3   Structuring Design

ePublisher implements page templates using a custom namespace, four attributes, and one XSL transform.

The page template XSL transform is presently located at:

ePublisher Pro/Transforms/html/pagetemplate.xsl

In the future, it will be move out of the "html" directory. The page template XSL transform can be invoked on any valid XML source, not just XHTML.

For purposes of discussion, examples are taken from the WebWorks Help 5.0 page template, located at:

ePublisher Pro/Formats/WebWorks Help 5.0/Pages/Page.asp

Note

Forward slashes (/) are used because that's the way God, UNIX, and the Web intended them to be.

3.1   Namespace and Attributes

ePublisher defines the following namespace for page templates:

xmlns:wwpage="urn:WebWorks-Page-Template-Schema"

The page template attributes are as follows:

wwpage:condition
wwpage:content
wwpage:replace
wwpage:attribute-<name>

Additionally, the attribute "wwpage:attribute-<name>" supports two special values:

relative-to-output
copy-relative-to-output
absolute-to-output

These two values enable simplified page template design and maintenence.

3.2   Conditions

Conditions are used to control when elements should be preserved. For example:

<hr wwpage:condition="header-exists" align="left" />

If the "header-exists" condition exists, then the above "<hr>" will be preserved. Otherwise, it disappears from the output.

Conditions are hierarchial. All nested elements and text are removed regardless of nested condition states. So, if following conditions are defined:

company-phone-exists
lucky-you

then applying the page template XSL transform to the following:

<table wwpage:condition="company-info-top">
  <tr>
    <td>
     WebWorks
    </td>
  </tr>

  <tr wwpage:condition="company-phone-exists">
    <td>
      Phone: 512-555-1234
    </td>
  </tr>
</table>

<div wwpage:condition="lucky-you">
  Lotto: 2 - 32 - 25 - 23 - 34
</div>

results in:

<div>
  Lotto: 2 - 32 - 25 - 23 - 34
</div>

If only "company-info-top" is defined, then the result would be:

<table>
  <tr>
    <td>
     WebWorks
    </td>
  </tr>
</table>

3.3   Element Content

Elements may have either their "innerHTML/innerXML" or "outerHTML/outerXML" replaced. This is controlled via:

wwpage:content
wwpage:replace

In the future, alternate attributes will be defined; "wwpage:inner" for "wwpage:content" and "wwpage:outer" for "wwpage:replace".

For this example, assume that the replacement "intro" has been defined as:

<h2>Introduction</h2>
<div>I really like the beginning of things.</div>
<div>Ever so much better than the end or being stuck in the middle.</div>

When applied to the following page template:

<blockquote wwpage:content="intro">
  Page content with header/footer.
</blockquote>

<div wwpage:replace="intro">
  Page content with no header/footer.
</div>

the result is:

<blockquote wwpage:content="intro">
  <h2>Introduction</h2>
  <div>I really like the beginning of things.</div>
  <div>Ever so much better than the end or being stuck in the middle.</div>
</blockquote>

<h2>Introduction</h2>
<div>I really like the beginning of things.</div>
<div>Ever so much better than the end or being stuck in the middle.</div>

In the first case, a "wwpage:content" attribute was used. This preserves the original element and simply replaces its inner text/HTML/XML. In the second case, a "wwpage:replace" attribute was used. This instructs the page template XSL transform to insert the content in place of the element.

Note

Page templates allow designers to put dummy text or markup into their designs without concern for how it will affect rendered output.

3.4   Element Attributes

Element attributes are controlled by the "wwpage:attribute-<name>" attribute. For example:

<body style="text-align: left;" wwpage:attribute-style="body-style">
  ...
</body>

indicates that the "style" attribute of the "body" element should be replaced by whatever value is defined for "body-style". The match is made by finding all attributes that start with "wwpage:attribute-", trimming off the prefix, and taking the result. In this way, multiple attributes on an element can be updated:

<table cellpadding="1"
       cellspacing="2"
       wwpage:attribute-cellpadding="cell-padding"
       wwpage:attribute-cellspacing="cell-spacing">
  ...
</table>

Note

Again, designers still can insert real values that are preserved through multiple edits of the page template.

3.5   Special Attribute Replacements

When using the "wwpage:attribute-<name>" mechanism to replace attribute values, two special replacement values are available:

relative-to-output
copy-relative-to-output

These special replacement values allow nested output hierarchies, a feature that did not exist in Publisher 2003.

In Publisher 2003, a user could specify the following:

<link rel="StyleSheet" href="css/webworks.css" type="text/css" media="all" />

If things were laid out as follows:

GUI
  Files
    alpha.fm
    beta.fm

Support
  css
    webworks.css

then Publisher 2003 would generate:

Output
  alpha.html
    <link rel="StyleSheet" href="css/webworks.css" />
  beta.html
    <link rel="StyleSheet" href="css/webworks.css" />
  css
    webworks.css

ePublisher is much more flexible. A user can choose to create nested folders:

GUI
  Group
    alpha.fm
    Nest
      beta.fm

Pages
  Page.asp
  css
    webworks.css

which should be output as:

Group
  alpha.html
    <link rel="StyleSheet" href="css/webworks.css" />
  Nest
    beta.html
      <link rel="StyleSheet" href="../css/webworks.css" />
  css
    webworks.css

This is allowed via the "copy-relative-to-output" replacement value. The page template XSL transform knows to look for the file "css/webworks.css" relative to the "Page.asp" file, copies it to the output group folder, and then determines the correct relative path.

For cases where the file copy is handled elsewhere, the "relative-to-output" replacement value simply updates the relative path. So:

<script type="text/javascript" language="JavaScript1.2"
        src="wwhdata/common/wwhpagef.js"
        wwpage:attribute-src="relative-to-output">
</script>

becomes:

Group
  alpha.html
    <script type="text/javascript" language="JavaScript1.2"
            src="wwhdata/common/wwhpagef.js"
    </script>
  Nest
    beta.html
      <script type="text/javascript" language="JavaScript1.2"
              src="../wwhdata/common/wwhpagef.js"
      </script>

Note

The relative path replacement attributes can be used on any valid URI path attribute on any element.

4   Defining Conditions and Replacements

The page template XSL transform is applied to a loaded Page.asp (or other XML file) with two parameters, conditions and replacements. Specifying conditions and replacements boils down to creating an XML node set. In Microsoft's .Net XSL transform engine, that can be accomplished by:

<xsl:variable name="VarCondsAsXML">
 <wwpage:Condition name="company-info-exists" />
</xsl:variable>
<xsl:variable name="VarConditions" select="msxsl:node-set($VarCondsAsXML)" />

Standard XSL control structures can be used when defining a condition set:

<xsl:variable name="VarCondsAsXML">
 <wwpage:Condition name="company-info-exists" />

 <xsl:if test="$VarBreadcrumbsBottomGenerateOption = 'true'">
  <wwpage:Condition name="breadcrumbs-bottom" />
 </xsl:if>
</xsl:variable>
<xsl:variable name="VarConditions" select="msxsl:node-set($VarCondsAsXML)" />

Replacements work similarly:

<xsl:variable name="VarRpsAsXML">
 <wwpage:Replacement name="body-style" value="color: green;" />

 <wwpage:Replacement name="intro">
  <h2>Introduction</h2>
  <div>I really like the beginning of things.</div>
  <div>Ever so much better than the end or being stuck in the middle.</div>
 </wwpage:Replacement>
</xsl:variable>
<xsl:variable name="VarReplacements" select="msxsl:node-set($VarRpsAsXML)" />

Replacements can be defined either by an empty XML element with a value attribute or by a non-empty XML element containing text or an XML sub-tree.

At present, most formats define conditions and replacements in:

Formats/<Format Name>/Transforms/pages.xsl
Formats/<Format Name>/Transforms/popups.xsl
Formats/<Format Name>/Transforms/wrappers.xsl

"Dynamic HTML" and "Simple HTML" also define conditions and replacements in:

Formats/<Format Name>/Transforms/toc.xsl
Formats/<Format Name>/Transforms/index.xsl

5   Non-XML Templates

Non-XML files have the same need for replacing content that XML files do. The only difference is that they cannot perform any kind of "smart" replacements due to lack of structure. Further, conditions are not supported, again due to lack of structure.

To support generic text/binary files, the multiple search/replace XSL extension was defined. It is implemented in the following namespace:

urn:WebWorks-XSLT-Extension-MultiSearchReplace

Replacements are specified as follows:

<xsl:variable name="VarRsAsXML">
 <wwmultisere:Entry match="$BinaryIndex;" replacement="true" />
 <wwmultisere:Entry match="$CompiledFile;" replacement="help.chm" />
</xsl:variable>
<xsl:variable name="VarReplacements" select="msxsl:node-set($VarRsAsXML)/*" />

Unlike page template replacements, only empty XML elements with "match" and "replacement" attributes are supported.

When invoked on a file such as:

[OPTIONS]
Binary Index=$BinaryIndex;
Compatibility=1.1 or later
Compiled file=$CompiledFile;
...

will result in:

[OPTIONS]
Binary Index=true
Compatibility=1.1 or later
Compiled file=help.chm
...

Fans of Publisher 2003 will notice a similarity of syntax. This is purely for "that retro thrill" and is not required for operation. Match attributes can be any valid string. Keep in mind that they are not regular expressions, so do not expect "$Match.*;" to do anything beyond what Notepad might do with it. Additionally, "$" and ";" are used here for the same reason they existed in Publisher 2003; to identify variables in all usage contexts.

Consider:

<wwmultisere:Entry match="$Ben" replacement="Ben was here." />

applied to:

Email $BenAllums.

will output as:

Email Ben was here.Allums.

Likely not what you had in mind.

For an excellent example of the multiple search/replace XSL extension, look at:

Formats/Microsoft HTML Help 1.x/Pages/template.hhp
Formats/Microsoft HTML Help 1.x/Tranforms/htmlhelp_hhp.xsl

5.1   Encodings

Even non-XML files have encodings. And ePublisher does not magically know your file's encoding when it applies a search/replace operation to one. As a result, the very first parameter that must be supplied is the encoding of the non-XML template file:

<xsl:value-of select="wwmultisere:ReplaceAllInFile('UTF-8', $TemplatePath, $OutPath, $VarReplacements)" />

Since all XML node sets exist as Unicode in memory, the search/replace engine must know how to translate the replacement entry atrributes, "match" and "replacement", to the correct byte sequences before operating on the file.

Unlike XML templates that are transformed to different encodings by the XSL transform engine, the search/replace engine does no such thing. In the future, an XSL extension method will be made available to enable non-XML file encoding translations.

DevCenter/Documentation/PageTemplates (last edited 2016-03-28 16:38:39 by TonyMcDow)