blob: ff56ad685b343b6ad71283786daf4a5edc8d3315 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta content="Apache Forrest" name="Generator">
<meta name="Forrest-version" content="0.8-dev">
<meta name="Forrest-skin-name" content="pelt">
<title>Forrest Sitemap Reference (v0.6)</title>
<link type="text/css" href="../skin/basic.css" rel="stylesheet">
<link media="screen" type="text/css" href="../skin/screen.css" rel="stylesheet">
<link media="print" type="text/css" href="../skin/print.css" rel="stylesheet">
<link type="text/css" href="../skin/profile.css" rel="stylesheet">
<script src="../skin/getBlank.js" language="javascript" type="text/javascript"></script><script src="../skin/getMenu.js" language="javascript" type="text/javascript"></script><script src="../skin/fontsize.js" language="javascript" type="text/javascript"></script>
<link rel="shortcut icon" href="../favicon.ico">
</head>
<body onload="init()">
<script type="text/javascript">ndeSetTextSize();</script>
<div id="top">
<!--+
|breadtrail
+-->
<div class="breadtrail">
<a href="http://www.apache.org/">apache</a> &gt; <a href="http://forrest.apache.org/">forrest</a><script src="../skin/breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
</div>
<!--+
|header
+-->
<div class="header">
<!--+
|start group logo
+-->
<div class="grouplogo">
<a href="http://www.apache.org/"><img class="logoImage" alt="Apache" src="../images/apache-forrest.png" title="The Apache Software Foundation"></a>
</div>
<!--+
|end group logo
+-->
<!--+
|start Project Logo
+-->
<div class="projectlogo">
<a href="http://forrest.apache.org/"><img class="logoImage" alt="Forrest" src="../images/project-logo.gif" title="Apache Forrest"></a>
</div>
<!--+
|end Project Logo
+-->
<!--+
|start Search
+-->
<div class="searchbox">
<form action="http://www.google.com/search" method="get" class="roundtopsmall">
<input value="forrest.apache.org" name="sitesearch" type="hidden"><input onFocus="getBlank (this, 'Search the site with google');" size="25" name="q" id="query" type="text" value="Search the site with google">&nbsp;
<input name="Search" value="Search" type="submit">
</form>
</div>
<!--+
|end search
+-->
<!--+
|start Tabs
+-->
<ul id="tabs">
<li>
<a class="unselected" href="../index.html">Welcome</a>
</li>
<li>
<a class="unselected" href="../contrib.html">Developers</a>
</li>
<li class="current">
<a class="selected" href="../versions/index.html">Versioned Docs</a>
</li>
<li>
<a class="unselected" href="../pluginDocs/index.html">Plugins</a>
</li>
<li>
<a class="unselected" href="../tools/index.html">Tools</a>
</li>
</ul>
<!--+
|end Tabs
+-->
</div>
</div>
<div id="main">
<div id="publishedStrip">
<!--+
|start Subtabs
+-->
<div id="level2tabs">
<a class="unselected" href="../docs_0_70/index.html">0.70 (current)</a><a class="unselected" href="../docs_0_80/index.html">0.80-dev (under development)</a><a class="selected" href="../docs_0_60/index.html">0.60 (past)</a>
</div>
<!--+
|end Endtabs
+-->
<script type="text/javascript"><!--
document.write("Last Published: " + document.lastModified);
// --></script>
</div>
<!--+
|breadtrail
+-->
<div class="breadtrail">
&nbsp;
</div>
<!--+
|start Menu, mainarea
+-->
<!--+
|start Menu
+-->
<div id="menu">
<div onclick="SwitchMenu('menu_selected_1.1', '../skin/')" id="menu_selected_1.1Title" class="menutitle" style="background-image: url('../skin/images/chapter_open.gif');">0.60</div>
<div id="menu_selected_1.1" class="selectedmenuitemgroup" style="display: block;">
<div class="menuitem">
<a href="../docs_0_60/index.html">Overview</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/faq.html">FAQs</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/changes.html">Changes</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/todo.html">Todo</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/your-project.html">Using Forrest</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/upgrading_06.html">Upgrading to 0.6</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/validation.html">XML Validation</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/linking.html">Menus and Linking</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/searching.html">Searching</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/skins.html">Default Skins</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/skin-package.html">Skin Packages</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/forrest-contract.html">Our Contract</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/compliance.html">Standards Compliance</a>
</div>
<div onclick="SwitchMenu('menu_1.1.14', '../skin/')" id="menu_1.1.14Title" class="menutitle">How-To</div>
<div id="menu_1.1.14" class="menuitemgroup">
<div class="menuitem">
<a href="../docs_0_60/howto/index.html">Overview</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/howto/howto-howto.html">Single Page</a>
</div>
<div onclick="SwitchMenu('menu_1.1.14.3', '../skin/')" id="menu_1.1.14.3Title" class="menutitle">Multi-Page</div>
<div id="menu_1.1.14.3" class="menuitemgroup">
<div class="menuitem">
<a href="../docs_0_60/howto/multi/howto-multi.html">Intro</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/howto/multi/step1.html">Step 1</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/howto/multi/step2.html">Step 2</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/howto/multi/step3.html">Step 3</a>
</div>
</div>
<div class="menuitem">
<a href="../docs_0_60/howto/bugzilla-patch/howto-bugzilla-patch.html">With Images</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/howto/howto-howto.html">Write a How-to</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/howto/howto-asf-mirror.html">Download mirror</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/howto/howto-pdf-tab.html">Create tab PDF</a>
</div>
</div>
<div onclick="SwitchMenu('menu_selected_1.1.15', '../skin/')" id="menu_selected_1.1.15Title" class="menutitle" style="background-image: url('../skin/images/chapter_open.gif');">Advanced Topics</div>
<div id="menu_selected_1.1.15" class="selectedmenuitemgroup" style="display: block;">
<div class="menuitem">
<a href="../docs_0_60/build.html">Building Forrest</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/catalog.html">Using DTD Catalogs</a>
</div>
<div class="menupage">
<div class="menupagetitle">Sitemap Reference</div>
</div>
<div class="menuitem">
<a href="../docs_0_60/project-sitemap.html">Project sitemap</a>
</div>
<div class="menuitem">
<a href="../docs_0_60/cap.html">Sourcetype Action</a>
</div>
</div>
<div onclick="SwitchMenu('menu_1.1.16', '../skin/')" id="menu_1.1.16Title" class="menutitle">Reference docs</div>
<div id="menu_1.1.16" class="menuitemgroup">
<div onclick="SwitchMenu('menu_1.1.16.1', '../skin/')" id="menu_1.1.16.1Title" class="menutitle">DTD documentation</div>
<div id="menu_1.1.16.1" class="menuitemgroup">
<div class="menuitem">
<a href="../dtdx/dtd-docs.html">Overview</a>
</div>
<div class="menuitem">
<a href="../dtdx/document-v20.dtdx.html">document-v20</a>
</div>
<div class="menuitem">
<a href="../dtdx/howto-v20.dtdx.html">howto-v20</a>
</div>
<div class="menuitem">
<a href="../dtdx/faq-v20.dtdx.html">faq-v20</a>
</div>
<div class="menuitem">
<a href="../dtdx/document-v13.dtdx.html">document-v13</a>
</div>
<div class="menuitem">
<a href="../dtdx/howto-v13.dtdx.html">howto-v13</a>
</div>
<div class="menuitem">
<a href="../dtdx/faq-v13.dtdx.html">faq-v13</a>
</div>
</div>
<div onclick="SwitchMenu('menu_1.1.16.2', '../skin/')" id="menu_1.1.16.2Title" class="menutitle">Doc samples</div>
<div id="menu_1.1.16.2" class="menuitemgroup">
<div class="menuitem">
<a href="../dtdx/document-v13.html">document-v13</a>
</div>
<div class="menuitem">
<a href="../dtdx/document-v20.html">document-v20</a>
</div>
</div>
</div>
</div>
<div id="credit">
<hr>
This is documentation for past version v0.6
(<a href="http://forrest.apache.org/versions/">More</a>)</div>
<div id="roundbottom">
<img style="display: none" class="corner" height="15" width="15" alt="" src="../skin/images/rc-b-l-15-1body-2menu-3menu.png"></div>
<!--+
|alternative credits
+-->
<div id="credit2">
<a href="http://apachecon.com/2007/EU/"><img border="0" title="ApacheCon Europe 2007" alt="ApacheCon Europe 2007 - logo" src="http://apache.org/ads/ApacheCon/2007-europe-125x125.png" style="width: 125px;height: 125px;"></a><a href="http://people.apache.org/calendar.html#200711"><img border="0" title="ApacheCon US 2007" alt="ApacheCon US 2007 - logo" src="http://apache.org/ads/ApacheCon/2007-usa-125x125.png" style="width: 125px;height: 125px;"></a>
</div>
</div>
<!--+
|end Menu
+-->
<!--+
|start content
+-->
<div id="content">
<div title="Portable Document Format" class="pdflink">
<a class="dida" href="sitemap-ref.pdf"><img alt="PDF -icon" src="../skin/images/pdfdoc.gif" class="skin"><br>
PDF</a>
</div>
<div class="trail">Font size:
&nbsp;<input value="Reset" class="resetfont" title="Reset text" onclick="ndeSetTextSize('reset'); return false;" type="button">
&nbsp;<input value="-a" class="smallerfont" title="Shrink text" onclick="ndeSetTextSize('decr'); return false;" type="button">
&nbsp;<input value="+a" class="biggerfont" title="Enlarge text" onclick="ndeSetTextSize('incr'); return false;" type="button">
</div>
<h1>Forrest Sitemap Reference</h1>
<div id="motd-area">
This is documentation for past version v0.6
(<a href="http://forrest.apache.org/versions/">More</a>)</div>
<div id="minitoc-area">
<ul class="minitoc">
<li>
<a href="#getting_started">Getting started</a>
</li>
<li>
<a href="#overview">Sitemap Overview</a>
</li>
<li>
<a href="#source_pipelines">Source pipelines (**.xml)</a>
<ul class="minitoc">
<li>
<a href="#forrest_xmap">forrest.xmap</a>
</li>
<li>
<a href="#other_source">Other source pipelines</a>
<ul class="minitoc">
<li>
<a href="#late_binding_pipelines">Late-binding pipelines</a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#output_pipelines">Output pipelines</a>
<ul class="minitoc">
<li>
<a href="#pdf">PDF output</a>
</li>
<li>
<a href="#html">HTML output</a>
</li>
</ul>
</li>
<li>
<a href="#intermediate_pipelines">Intermediate pipelines</a>
<ul class="minitoc">
<li>
<a href="#body_pipeline">Page body</a>
</li>
<li>
<a href="#menu_pipeline">Page menu</a>
</li>
<li>
<a href="#tab_pipeline">Page tabs</a>
</li>
</ul>
</li>
<li>
<a href="#menu_xml_generation">Menu XML generation</a>
</li>
<li>
<a href="#linkrewriting_impl">Link rewriting</a>
<ul class="minitoc">
<li>
<a href="#input_modules">Cocoon foundations: Input Modules</a>
</li>
<li>
<a href="#implement_rewriting">Implementing "site:" rewriting</a>
<ul class="minitoc">
<li>
<a href="#cocoon_xconf">cocoon.xconf</a>
</li>
<li>
<a href="#sitemap">sitemap.xmap</a>
</li>
<li>
<a href="#dynamic_linkmap">Dynamically generating a linkmap</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<p>
Technically, Forrest can be thought of as a
<a href="http://cocoon.apache.org/2.1/">Cocoon</a> distribution that has been stripped down
and optimized for people with simple site publishing needs. Central to
Cocoon, and hence Forrest, is the <strong>sitemap</strong>. The sitemap
defines the site's URI space (what pages are available), and how each page
is constructed. Understanding the sitemap is the key to understanding
Forrest.
</p>
<div class="note">
<div class="label">Note</div>
<div class="content">
We advise you to spend time to understand the Apache Cocoon sitemap.
See <a href="http://cocoon.apache.org/2.1/userdocs/concepts/sitemap.html">Cocoon sitemap</a>
and <a href="http://cocoon.apache.org/2.1/userdocs/concepts/">Cocoon concepts</a>
and related component documentation.
The Forrest sitemap is broken into multiple files. The main one is
<strong>sitemap.xmap</strong> which delegates to others.
</div>
</div>
<p>
This document provides an overview of the special sitemap which
is used at the core of Apache Forrest.
</p>
<a name="N10028"></a><a name="getting_started"></a>
<h2 class="underlined_10">Getting started</h2>
<div class="section">
<p>
Forrest's sitemap comprises the $FORREST_HOME/context/*.xmap files.
</p>
<p>
You can add pre-processing sitemaps to your project
<span class="codefrag">src/documentation</span> directory (or wherever
<span class="codefrag">${project.sitemap-dir}</span> points to). Any match that
is not handled, passes through to be handled by the default Forrest
sitemaps - obviously extremely powerful. The capability is described
in
"<a href="../docs_0_60/project-sitemap.html">Using project sitemaps</a>".
</p>
<p>
Another way to experiment with the sitemap is to do '<span class="codefrag">forrest
run</span>' on a Forrest-using site. Changes to the core
<span class="codefrag">*.xmap</span> files will now be immediately visible
at <span class="codefrag">&gt;http://localhost:8888/</span>
</p>
</div>
<a name="N1004B"></a><a name="overview"></a>
<h2 class="underlined_10">Sitemap Overview</h2>
<div class="section">
<p>
Forrest's sitemap is divided both physically and logically. The most
obvious is the physical separation. There are a number of separate
*.xmap files, each defining pipelines for a functional area. Each *.xmap
file has its purpose documented in comments at the top. Here is a brief
overview of the files, in order of importance.
</p>
<table class="ForrestTable" cellspacing="1" cellpadding="4">
<tr>
<th colspan="1" rowspan="1"><strong>sitemap.xmap</strong></th>
<td colspan="1" rowspan="1">Primary sitemap file, which delegates responsibility for serving
certain URIs to the others (technically called sub-sitemaps). More
about the structure of this file later.</td>
</tr>
<tr>
<th colspan="1" rowspan="1">forrest.xmap</th>
<td colspan="1" rowspan="1">Sitemap defining Source pipelines, which generate the body section
of Forrest pages. All pipelines here deliver XML in Forrest's
intermediate "document-v13" format, regardless of originating source
or format.</td>
</tr>
<tr>
<th colspan="1" rowspan="1">menu.xmap</th>
<td colspan="1" rowspan="1">Pipelines defining the XML that becomes the menu.</td>
</tr>
<tr>
<th colspan="1" rowspan="1">linkmap.xmap</th>
<td colspan="1" rowspan="1">Defines a mapping from abstract ("site:index") to physical
("../index.html") links for the current page. See
<a href="../docs_0_60/linking.html">Menus and Linking</a> for a conceptual
overview, and the <a href="#linkrewriting_impl">Link
rewriting</a> section for technical details.</td>
</tr>
<tr>
<th colspan="1" rowspan="1">resources.xmap</th>
<td colspan="1" rowspan="1">Serves "resource" files (images, CSS, Javascript).</td>
</tr>
<tr>
<th colspan="1" rowspan="1">raw.xmap</th>
<td colspan="1" rowspan="1">Serves files located in <span class="codefrag">src/documentation/content/</span>
that are not to be modified by Forrest.</td>
</tr>
<tr>
<th colspan="1" rowspan="1">aggregate.xmap</th>
<td colspan="1" rowspan="1">Generates a single page (HTML or PDF) containing all the content
for the site.</td>
</tr>
<tr>
<th colspan="1" rowspan="1">faq.xmap</th>
<td colspan="1" rowspan="1">Processes FAQ documents.</td>
</tr>
<tr>
<th colspan="1" rowspan="1">status.xmap</th>
<td colspan="1" rowspan="1">Generates <a href="../docs_0_60/changes.html">changes</a> and
<a href="../docs_0_60/todo.html">todo</a> pages from a single
<span class="codefrag">status.xml</span> in the project root.
</td>
</tr>
<tr>
<th colspan="1" rowspan="1">issues.xmap</th>
<td colspan="1" rowspan="1">Generates a page of content from an RSS feed. Used in Forrest to
generate a "current issues" list from JIRA.</td>
</tr>
<tr>
<th colspan="1" rowspan="1">revisions.xmap</th>
<td colspan="1" rowspan="1">
Support for HOWTO documents that want "revisions". Revisions are
XML snippets containing comments on the main XML file. The main
pipeline here automatically appends a page's revisions to the
bottom.
</td>
</tr>
<tr>
<th colspan="1" rowspan="1">dtd.xmap</th>
<td colspan="1" rowspan="1">A Source pipeline that generates XML from a DTD, using Andy
Clark's
<a href="http://www.apache.org/~andyc/neko/doc/dtd/index.html">DTD
Parser</a>. Useful for documenting DTD-based XML schemas, such
as <a href="../docs_0_80/../dtdx/dtd-docs.html">Forrest's own DTDs</a>.
</td>
</tr>
<tr>
<th colspan="1" rowspan="1">profiler.xmap</th>
<td colspan="1" rowspan="1">Defines the "profiler" pipeline. allowing pipelines to be benchmarked.</td>
</tr>
</table>
</div>
<!--
<section>
<title>Logical structure</title>
<p>There are a few major groups of sitemap pipelines</p>
<dl>
<dt>Content pipelines</dt>
<dd>These define the body (without menu and header) for HTML pages, and all the content of PDFs.</dd>
<dt>Menu pileines.
</dl>
</section>
-->
<a name="N10122"></a><a name="source_pipelines"></a>
<h2 class="underlined_10">Source pipelines (**.xml)</h2>
<div class="section">
<p>
Most *.xmap files (forrest, aggregate, faq, status, issues, revisions,
dtd) define Source pipelines. Source pipelines define the content
(body) XML for site pages. The input XML format can be any format
(document-v13, Docbook, RSS, FAQ, Howto) and from any source (local or
remote). The output format is always Forrest's intermediate "document-v13"
format.
</p>
<p>
Source pipelines always have a "<span class="codefrag">.xml</span>" extension. Thus,
<a href="../index.xml">index.xml</a> gives you the XML source for the
index page. Likewise, <a href="../docs_0_60/faq.html">faq.xml</a> gives you XML
for the FAQ (transformed from FAQ syntax), and
<a href="../changes.xml">changes.xml</a> returns XML from the status.xml file.
Take any page, and replace its extension (<span class="codefrag">.html</span> or
<span class="codefrag">.pdf</span>) with <span class="codefrag">.xml</span> and you'll have the Source
XML.
</p>
<p>
This is quite powerful, because we now have an abstraction layer, or
"virtual filesystem", on which the rest of Forrest's sitemap can build.
Subsequent layers don't need to care whether the XML was obtained
locally or remotely, or from what format. Wikis, RSS, FAQs and Docbook
files are all processed identically from here on.
</p>
<pre class="code">
(subsequent Forrest pipelines)
|
--------+------------------------^------------------------------------------
| STANDARD FORREST FORMAT (current document-v13)
+-----^-------^--------^------------^------^-----^-----^------^-----
SOURCE | | | | | | | |
FORMATS doc-v11 doc-v13 doc-v20 ... Docbook FAQ Howto Wiki RSS ??
(*.xml)
(in forrest.xmap, faq.xmap, etc)
</pre>
<a name="N1014D"></a><a name="forrest_xmap"></a>
<h3 class="underlined_5">forrest.xmap</h3>
<p>
Most of the usual Source pipelines are defined in
<span class="codefrag">forrest.xmap</span> which is the default (fallback) handler for
<span class="codefrag">**.xml</span> pages. The forrest.xmap uses the
<a href="../docs_0_60/cap.html">SourceTypeAction</a> to determine the type of XML
it is processing, and converts it to document-v13 if necessary.
</p>
<p>For instance, say we are rendering <a href="../docs_0_60/howto/howto-howto.html">a
Howto document</a> called "howto-howto.xml". It contains this DOCTYPE
declaration:</p>
<pre class="code">
&lt;!DOCTYPE howto PUBLIC "-//APACHE//DTD How-to V1.3//EN"
"http://forrest.apache.org/dtd/howto-v13.dtd"&gt;</pre>
<p>The SourceTypeAction sees this, and applies this transform to get it
to document-v13:</p>
<pre class="code">
&lt;map:when test="howto-v13"&gt;
&lt;map:transform src="{forrest:forrest.stylesheets}/howto2document.xsl" /&gt;
&lt;/map:when&gt;
</pre>
<a name="N10175"></a><a name="other_source"></a>
<h3 class="underlined_5">Other source pipelines</h3>
<p>As mentioned above, all non-core Source pipelines are distributed in
independent <span class="codefrag">*.xmap</span> files. There is a block of
<span class="codefrag">sitemap.xmap</span> which simply delegates certain requests to
these subsitemaps:</p>
<pre class="code">
&lt;!-- Body content --&gt;
&lt;map:match pattern="**.xml"&gt;
&lt;map:match pattern="changes.xml"&gt;
&lt;map:mount uri-prefix="" src="status.xmap" check-reload="yes" /&gt;
&lt;/map:match&gt;
&lt;map:match pattern="todo.xml"&gt;
&lt;map:mount uri-prefix="" src="status.xmap" check-reload="yes" /&gt;
&lt;/map:match&gt;
&lt;map:match pattern="**dtdx.xml"&gt;
&lt;map:mount uri-prefix="" src="dtd.xmap" check-reload="yes" /&gt;
&lt;/map:match&gt;
&lt;map:match pattern="forrest-issues.xml"&gt;
&lt;map:mount uri-prefix="" src="issues.xmap" check-reload="yes" /&gt;
&lt;/map:match&gt;
&lt;map:match pattern="**faq.xml"&gt;
&lt;map:mount uri-prefix="" src="faq.xmap" check-reload="yes" /&gt;
&lt;/map:match&gt;
&lt;map:match pattern="site.xml"&gt;
&lt;map:mount uri-prefix="" src="aggregate.xmap" check-reload="yes" /&gt;
&lt;/map:match&gt;
....
....</pre>
<a name="N10188"></a><a name="late_binding_pipelines"></a>
<h4>Late-binding pipelines</h4>
<p>
One point of interest here is that the sub-sitemap is often not
specific about which URLs it handles, and relies on the caller (the
section listed above) to only pass relevant requests to it. We term
this "binding a URL" to a pipeline.</p>
<p>For instance, the main pipeline in <span class="codefrag">faq.xmap</span> matches
<span class="codefrag">**.xml</span>, but only <span class="codefrag">**faq.xml</span> requests are
sent to it.</p>
<p>This "late binding" is useful, because the whole URL space is
managed in <span class="codefrag">sitemap.xmap</span> and not spread over lots of
*.xmap files. For instance, say you wish all <span class="codefrag">*.xml</span>
inside a "<span class="codefrag">faq/</span>" directory to be processed as FAQs. Just
override <span class="codefrag">sitemap.xmap</span> and redefine the relevant source
matcher:</p>
<pre class="code">
&lt;map:match pattern="**faq.xml"&gt;
&lt;map:mount uri-prefix="" src="faq.xmap" check-reload="yes" /&gt;
&lt;/map:match&gt;</pre>
</div>
<a name="N101B3"></a><a name="output_pipelines"></a>
<h2 class="underlined_10">Output pipelines</h2>
<div class="section">
<p>
To recap, we now have a <span class="codefrag">*.xml</span> pipeline defined for each
page in the site, emitting standardized XML. These pipeline definitions
are located in various *.xmap files, notably forrest.xmap
</p>
<p>
We now wish to render the XML from these pipelines to output formats
like HTML and PDF.
</p>
<a name="N101C2"></a><a name="pdf"></a>
<h3 class="underlined_5">PDF output</h3>
<p>
Easiest case first; PDFs don't require menus or headers, so we can
simply transform our intermediate format into XSL:FO, and from there
to PDF. This is done by the following matcher in
<span class="codefrag">sitemap.xmap</span> ...
</p>
<pre class="code">
1 &lt;map:match type="regexp" pattern="^(.*?)([^/]*).pdf$"&gt;
2 &lt;map:generate src="cocoon:/{1}{2}.xml"/&gt;
3 &lt;map:transform type="xinclude"/&gt;
4 &lt;map:transform type="<a href="#linkrewriting_impl">linkrewriter</a>" src="cocoon://{1}linkmap-{2}.pdf"/&gt;
5 &lt;map:transform src="skins/{forrest:forrest.skin}/xslt/fo/document2fo.xsl"&gt;
6 &lt;map:parameter name="ctxbasedir" value="{realpath:.}/"/&gt;
7 &lt;map:parameter name="xmlbasedir" value="content/xdocs/{1}"/&gt;
8 &lt;/map:transform&gt;
9 &lt;map:serialize type="fo2pdf"/&gt;
10 &lt;/map:match&gt;
</pre>
<ol>
<li>The first line uses a matching regexp to break the URL into
directory <span class="codefrag">(.*?)</span> and filename
<span class="codefrag">([^/]*)</span> parts.</li>
<li>We then generate XML from a <a href="#source_pipelines">Source
pipeline</a>, with the URL <span class="codefrag">cocoon:/{1}{2}.xml</span>
</li>
<li>We then expand any XInclude statements..</li>
<li>and <a href="#linkrewriting_impl">rewrite links</a>..</li>
<li>and finally apply the document2fo.xsl stylesheet, to generate
XSL:FO XML.</li>
</ol>
<p>Lastly, we generate a PDF using the fo2pdf serializer.</p>
<a name="N101FC"></a><a name="html"></a>
<h3 class="underlined_5">HTML output</h3>
<p>Generating HTML pages is more complicated, because we have to merge
the page body with a menu and tabs, and then add a header and footer.
Here is the <span class="codefrag">*.html</span> matcher in
<span class="codefrag">sitemap.xmap</span> ...</p>
<pre class="code">
&lt;map:match pattern="*.html"&gt;
&lt;map:aggregate element="site"&gt;
&lt;map:part src="<a href="#tab_pipeline">cocoon:/tab-{0}</a>"/&gt;
&lt;map:part src="<a href="#menu_pipeline">cocoon:/menu-{0}</a>"/&gt;
&lt;map:part src="<a href="#body_pipeline">cocoon:/body-{0}</a>"/&gt;
&lt;/map:aggregate&gt;
&lt;map:call resource="skinit"&gt;
&lt;map:parameter name="type" value="site2xhtml"/&gt;
&lt;map:parameter name="path" value="{0}"/&gt;
&lt;/map:call&gt;
&lt;/map:match&gt;
</pre>
<p>
So <a href="../index.html">index.html</a> is formed from
aggregating <a href="body-index.html">body-index.html</a> and
<a href="menu-index.html">menu-index.html</a> and
<a href="tab-index.html">tab-index.html</a> and then applying the
<span class="codefrag">site2xhtml.xsl</span> stylesheet to the result.
</p>
<p>
There is a nearly identical matcher for HTML files in subdirectories:
</p>
<pre class="code">
&lt;map:match pattern="**/*.html"&gt;
&lt;map:aggregate element="site"&gt;
&lt;map:part src="<a href="#tab_pipeline">cocoon:/{1}/tab-{2}.html</a>"/&gt;
&lt;map:part src="<a href="#menu_pipeline">cocoon:/{1}/menu-{2}.html</a>"/&gt;
&lt;map:part src="<a href="#body_pipeline">cocoon:/{1}/body-{2}.html</a>"/&gt;
&lt;/map:aggregate&gt;
&lt;map:call resource="skinit"&gt;
&lt;map:parameter name="type"
value="site2xhtml"/&gt;
&lt;map:parameter name="path"
value="{0}"/&gt;
&lt;/map:call&gt;
&lt;/map:match&gt;
</pre>
</div>
<a name="N10246"></a><a name="intermediate_pipelines"></a>
<h2 class="underlined_10">Intermediate pipelines</h2>
<div class="section">
<a name="N1024C"></a><a name="body_pipeline"></a>
<h3 class="underlined_5">Page body</h3>
<p>Here is the matcher which generates the page body:</p>
<pre class="code">
1 &lt;map:match pattern="**body-*.html"&gt;
2 &lt;map:generate src="cocoon:/{1}{2}.xml"/&gt;
3 &lt;map:transform type="idgen"/&gt;
4 &lt;map:transform type="xinclude"/&gt;
5 &lt;map:transform type="<a href="#linkrewriting_impl">linkrewriter</a>" src="cocoon:/{1}linkmap-{2}.html"/&gt;
6 &lt;map:call resource="skinit"&gt;
7 &lt;map:parameter name="type" value="document2html"/&gt;
8 &lt;map:parameter name="path" value="{1}{2}.html"/&gt;
9 &lt;map:parameter name="notoc" value="false"/&gt;
10 &lt;/map:call&gt;
11 &lt;/map:match&gt;
</pre>
<ol>
<li>In our matcher pattern, {1} will be the directory (if any) and {2}
will be the filename.</li>
<li>First, we obtain XML content from a source pipeline</li>
<li>
<p>We then apply a custom-written
<span class="codefrag">IdGeneratorTransformer</span>, which ensures that every
&lt;section&gt; has an "id" attribute if one is not supplied, by generating one from the
&lt;title&gt; if necessary. For example, &lt;idgen&gt; will
transform:</p>
<pre class="code">
&lt;section&gt;
&lt;title&gt;How to boil eggs&lt;/title&gt;
...
</pre>
<p>into:</p>
<pre class="code">
&lt;section id="How+to+boil+eggs"&gt;
&lt;title&gt;How to boil eggs&lt;/title&gt;
...
</pre>
<p>Later, the <span class="codefrag">document2html.xsl</span> stylesheet will create
an &lt;a name&gt; element for every section, allowing this section to
be referred to as <span class="codefrag">index.html#How+to+boil+eggs</span>.</p>
</li>
<li>We then expand XInclude elements.</li>
<li>and <a href="#linkrewriting_impl">rewrite links</a>..</li>
<li>and then finally apply the stylesheet that generates a fragment of
HTML (minus the outer elements like
&lt;html&gt; and &lt;body&gt;) suitable for merging with the menu and tabs.</li>
</ol>
<a name="N10291"></a><a name="menu_pipeline"></a>
<h3 class="underlined_5">Page menu</h3>
<p>In the <span class="codefrag">sitemap.xmap</span> file, the matcher generating HTML for the menu is:</p>
<pre class="code">
&lt;map:match pattern="**menu-*.html"&gt;
&lt;map:generate src="cocoon:/{1}book-{2}.html"/&gt;
&lt;map:transform type="<a href="#linkrewriting_impl">linkrewriter</a>" src="cocoon:/{1}linkmap-{2}.html"/&gt;
&lt;map:call resource="skinit"&gt;
&lt;map:parameter name="type" value="book2menu"/&gt;
&lt;map:parameter name="path" value="{1}{2}.html"/&gt;
&lt;/map:call&gt;
&lt;/map:match&gt;
</pre>
<p>We get XML from a "book" pipeline,
<a href="#linkrewriting_impl">rewrite links</a>, and apply the
<span class="codefrag">book2menu.xsl</span> stylesheet to generate HTML.</p>
<p>How the menu XML is actually generated (the *book-*.html pipeline) is
sufficiently complex to require a
<a href="#menu_xml_generation">section of its own</a>.</p>
<a name="N102B7"></a><a name="tab_pipeline"></a>
<h3 class="underlined_5">Page tabs</h3>
<p>Tab generation is quite tame compared to menus:</p>
<pre class="code">
&lt;map:match pattern="**tab-*.html"&gt;
&lt;map:generate src="content/xdocs/tabs.xml" /&gt;
&lt;map:transform type="<a href="#linkrewriting_impl">linkrewriter</a>" src="cocoon:/{1}linkmap-{2}.html"/&gt;
&lt;map:call resource="skinit"&gt;
&lt;map:parameter name="type" value="tab2menu"/&gt;
&lt;map:parameter name="path" value="{1}{2}.html"/&gt;
&lt;/map:call&gt;
&lt;/map:match&gt;
</pre>
<p>All the smarts are in the <span class="codefrag">tab2menu.xsl</span> stylesheet, which
needs to choose the correct tab based on the current path. Currently,
a "longest matching path" algorithm is implemented. See the
<span class="codefrag">tab2menu.xsl</span> stylesheet for details.</p>
</div>
<a name="N102D3"></a><a name="menu_xml_generation"></a>
<h2 class="underlined_10">Menu XML generation</h2>
<div class="section">
<p>The "book" pipeline is defined in <span class="codefrag">sitemap.xmap</span>as:</p>
<pre class="code">
&lt;map:match pattern="**book-*.html"&gt;
&lt;map:mount uri-prefix="" src="menu.xmap" check-reload="yes" /&gt;
&lt;/map:match&gt;
</pre>
<p>Meaning that it is defined in the <span class="codefrag">menu.xmap</span> file. In there we find
the real definition, which is quite complicated, because there are three
supported menu systems (see <a href="../docs_0_60/linking.html">menus and
linking</a>). We will not go through the sitemap itself
(menu.xmap), but will instead describe the logical steps involved:</p>
<ol>
<li>Take site.xml and expand hrefs so that they are all
root-relative.</li>
<li>
<p>Depending on the <span class="codefrag">forrest.menu-scheme</span> property, we
now apply one of the two algorithms for choosing a set of menu links
(described in <a href="../docs_0_60/linking.html#menu_generation">menu
generation</a>):</p>
<ul>
<li>
<p>
For "@tab" menu generation, we first ensure each site.xml node
has a tab attribute (inherited from a parent if necessary), and
then pass through nodes whose tab attribute matches that of the
"current" node.
</p>
<p>
For example, say our current page's path is
<span class="codefrag">community/howto/index.html</span>. In
<span class="codefrag">site.xml</span> we look for the node with this
"<span class="codefrag">href</span>" and discover its "<span class="codefrag">tab</span>" attribute
value is "<span class="codefrag">howtos</span>". We then prune the
<span class="codefrag">site.xml</span>-derived content to contain only nodes with
<span class="codefrag">tab="howtos"</span>.
</p>
<p>
All this is done with XSLT, so the sitemap snippet does not
reveal this complexity:
</p>
<pre class="code">
&lt;map:transform src="resources/stylesheets/site2site-normalizetabs.xsl" /&gt;
&lt;map:transform src="resources/stylesheets/site2site-selectnode.xsl"&gt;
&lt;map:parameter name="path" value="{1}{2}"/&gt;
&lt;/map:transform&gt;
</pre>
</li>
<li>
<p>For "directory" menu generation, we simply use an
<span class="codefrag">XPathTransformer</span> to include only pages in the
current page's directory, or below:</p>
<pre class="code">
&lt;map:transform type="xpath"&gt;
&lt;map:parameter name="include" value="//*[@href='{1}']" /&gt;
&lt;/map:transform&gt;
</pre>
<p>
Here, the "<span class="codefrag">{1}</span>" is the directory part of the current
page. So if our current page is
<span class="codefrag">community/howto/index.html</span> then "<span class="codefrag">{1}</span>" will
be <span class="codefrag">community/howto/</span> and the transformer will
include all nodes in that directory.
</p>
</li>
</ul>
<p>We now have a <span class="codefrag">site.xml</span> subset relevant to our current
page.</p>
</li>
<li>The "<span class="codefrag">href</span>" nodes in this are then made relative to the
current page.</li>
<li>The XML is then transformed into a legacy "<span class="codefrag">book.xml</span>"
format, for compatibility with existing stylesheets, and this XML
format is returned (hence the name of the matcher:
<span class="codefrag">**book-*.html</span>).</li>
</ol>
</div>
<a name="N10359"></a><a name="linkrewriting_impl"></a>
<h2 class="underlined_10">Link rewriting</h2>
<div class="section">
<p>In numerous places in <span class="codefrag">sitemap.xmap</span> you will see the
"linkrewriter" transformer in action. For example:</p>
<pre class="code">&lt;map:transform type="linkrewriter" src="cocoon:/{1}linkmap-{2}.html"/&gt;</pre>
<p>This statement is Cocoon's linking system in action. A full
description is provided in <a href="../docs_0_60/linking.html">Menus and
Linking</a>. Here we describe the implementation of linking.</p>
<a name="N10370"></a><a name="input_modules"></a>
<h3 class="underlined_5">Cocoon foundations: Input Modules</h3>
<p>
The implementation of <span class="codefrag">site:</span> linking is heavily based on
Cocoon <a href="http://cocoon.apache.org/2.1/userdocs/concepts/modules.html">Input Modules</a>, a
little-known but quite powerful aspect of Cocoon. Input Modules are
generic Components which simply allow you to look up a value with a
key. The value is generally dynamically generated, or obtained by
querying an underlying data source.
</p>
<p>
In particular, Cocoon contains an <span class="codefrag">XMLFileModule</span>, which
lets one look up the value of an XML node, by interpreting the key as
an XPath expression. Cocoon also has a
<span class="codefrag">SimpleMappingMetaModule</span>, which allows the key to be
rewritten before it is used to look up a value.
</p>
<p>
The idea for putting these together to rewrite "<span class="codefrag">site:</span>"
links was described in <a href="http://marc.theaimsgroup.com/?t=103992708800001&r=1&w=2">this
thread</a>. The idea is to write a Cocoon Transformer that
triggers on encountering &lt;link
href="<span class="codefrag">scheme:address</span>"&gt;, and interprets the
<span class="codefrag">scheme:address</span> internal URI as
<span class="codefrag">inputmodule:key</span>. The transformer then uses the named
InputModule to look up the key value. The <span class="codefrag">scheme:address</span>
URI is then rewritten with the found value. This transformer was
implemented as
<a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=15611">LinkRewriterTransformer</a>,
currently distributed as a "block" in Cocoon 2.1
</p>
<a name="N103A4"></a><a name="implement_rewriting"></a>
<h3 class="underlined_5">Implementing "site:" rewriting</h3>
<p>
Using the above components, "<span class="codefrag">site:</span>" URI rewriting is
accomplished as follows.
</p>
<a name="N103B3"></a><a name="cocoon_xconf"></a>
<h4>cocoon.xconf</h4>
<p>First, we declare all the input modules we will be needing:</p>
<pre class="code">
&lt;!-- For the site: scheme --&gt;
&lt;component-instance
class="org.apache.cocoon.components.modules.input.XMLFileModule"
logger="core.modules.xml" name="linkmap"/&gt;
&lt;!-- Links to URIs within the site --&gt;
&lt;component-instance
class="org.apache.cocoon.components.modules.input.SimpleMappingMetaModule"
logger="core.modules.mapper" name="site"/&gt;
&lt;!-- Links to external URIs, as distinct from 'site' URIs --&gt;
&lt;component-instance
class="org.apache.cocoon.components.modules.input.SimpleMappingMetaModule"
logger="core.modules.mapper" name="ext"/&gt;
</pre>
<ul>
<li>
<strong>linkmap</strong> will provide access to the contents of
<span class="codefrag">site.xml</span>; for example, <span class="codefrag">linkmap:/site/about/index/@href</span>
would return the value "index.html".</li>
<li>
<strong>site</strong> provides a "mask" over
<strong>linkmap</strong> such that <span class="codefrag">site:index</span> expands
to <span class="codefrag">linkmap:/site//index/@href</span>
</li>
<li>
<strong>ext</strong> provides another "mask" over
<strong>linkmap</strong>, such that <span class="codefrag">ext:ant</span> would
expand to <span class="codefrag">linkmap:/site/external-refs//ant/@href</span>
</li>
</ul>
<p>However at the moment, we have only declared the input modules.
They will be configured in <span class="codefrag">sitemap.xmap</span> as described in
the next section.</p>
<a name="N103F1"></a><a name="sitemap"></a>
<h4>sitemap.xmap</h4>
<p>
Now in the sitemap, we define the LinkRewriterTransformer, and
insert it into any pipelines which deal with user-editable XML
content:
</p>
<pre class="code">
....
&lt;!-- Rewrites links, e.g. transforming
href="site:index" to href="../index.html"
--&gt;
&lt;map:transformer name="linkrewriter"
logger="sitemap.transformer.linkrewriter"
src="org.apache.cocoon.transformation.LinkRewriterTransformer"&gt;
&lt;link-attrs&gt;href src&lt;/link-attrs&gt;
&lt;schemes&gt;site ext&lt;/schemes&gt;
&lt;input-module name="site"&gt;
&lt;input-module name="linkmap"&gt;
&lt;file src="{src}" reloadable="false" /&gt;
&lt;/input-module&gt;
&lt;prefix&gt;/site//&lt;/prefix&gt;
&lt;suffix&gt;/@href&lt;/suffix&gt;
&lt;/input-module&gt;
&lt;input-module name="ext"&gt;
&lt;input-module name="linkmap"&gt;
&lt;file src="{src}" reloadable="false" /&gt;
&lt;/input-module&gt;
&lt;prefix&gt;/site/external-refs//&lt;/prefix&gt;
&lt;suffix&gt;/@href&lt;/suffix&gt;
&lt;/input-module&gt;
&lt;/map:transformer&gt;
....
....
&lt;map:match pattern="**body-*.html"&gt;
&lt;map:generate src="cocoon:/{1}{2}.xml"/&gt;
&lt;map:transform type="idgen"/&gt;
&lt;map:transform type="xinclude"/&gt;
&lt;map:transform type="linkrewriter" src="cocoon:/{1}linkmap-{2}.html"/&gt;
...
&lt;/map:match&gt;</pre>
<p>As you can see, our three input modules are configured as part of
the LinkRewriterTransformer's configuration.</p>
<ul>
<li>
<p>Most deeply nested, we have:</p>
<pre class="code">
&lt;input-module name="linkmap"&gt;
&lt;file src="{src}" reloadable="false" /&gt;
&lt;/input-module&gt;</pre>
<p>The "<span class="codefrag">{src}</span>" text is expanded to the value of the
"<span class="codefrag">src</span>" attribute in the "<span class="codefrag">linkrewriter</span>"
instance, namely "<span class="codefrag">cocoon:/{1}linkmap-{2}.html</span>"
Thus the <span class="codefrag">linkmap</span> module reads dynamically
generated XML specific to the current request.</p>
</li>
<li>
<p>One level out, we configure the "<span class="codefrag">site</span>" and
"<span class="codefrag">ext</span>" input modules, to map onto our dynamically
configured "<span class="codefrag">linkmap</span>" module.</p>
</li>
<li>
<p>Then at the outermost level, we configure the
"<span class="codefrag">linkrewriter</span>" transformer. First we tell it which
attributes to consider rewriting:</p>
<pre class="code">
&lt;link-attrs&gt;href src&lt;/link-attrs&gt;
&lt;schemes&gt;site ext&lt;/schemes&gt;</pre>
<p>So, "<span class="codefrag">href</span>" and "<span class="codefrag">src</span>" attributes starting
with "<span class="codefrag">site:</span>" or "<span class="codefrag">ext:</span>" are rewritten.</p>
<p>By nesting the "<span class="codefrag">site</span>" and "<span class="codefrag">ext</span>" input
modules in the "<span class="codefrag">linkrewriter</span>" configuration, we tell
"<span class="codefrag">linkrewriter</span>" to use these two input modules when
rewriting links.</p>
</li>
</ul>
<p>
The end result is that, for example, the source XML for the
<span class="codefrag">community/body-index.html</span> page has its links rewritten
by an XMLFileModule reading XML from
<span class="codefrag">cocoon:/community/linkmap-index.html</span>
</p>
<a name="N10464"></a><a name="dynamic_linkmap"></a>
<h4>Dynamically generating a linkmap</h4>
<p>
Why do we need this "linkmap" pipeline generating dynamic XML from
<span class="codefrag">site.xml</span>, instead of just using <span class="codefrag">site.xml</span> directly? The reasons are described
in <a href="http://marc.theaimsgroup.com/?l=forrest-dev&m=103444028129281&w=2">the linkmap RT</a>: we need to
concatenate @hrefs and add dot-dots to the paths, depending on which
directory the linkee is in. This is done with the following
pipelines in <span class="codefrag">linkmap.xmap</span> ...
</p>
<pre class="code">
&lt;!-- site.xml with @href's appended to be context-relative. --&gt;
&lt;map:match pattern="abs-linkmap"&gt;
&lt;map:generate src="content/xdocs/site.xml" /&gt;
&lt;map:transform src="resources/stylesheets/absolutize-linkmap.xsl" /&gt;
&lt;map:serialize type="xml" /&gt;
&lt;/map:match&gt;
&lt;!-- Linkmap for regular pages --&gt;
&lt;map:match pattern="**linkmap-*"&gt;
&lt;map:generate src="cocoon://abs-linkmap" /&gt;
&lt;map:transform src="resources/stylesheets/relativize-linkmap.xsl"&gt;
&lt;map:parameter name="path" value="{1}{2}" /&gt;
&lt;map:parameter name="site-root" value="{conf:project-url}" /&gt;
&lt;/map:transform&gt;
&lt;map:serialize type="xml" /&gt;
&lt;/map:match&gt;
</pre>
<p>You can try these URIs out directly on a live Forrest to see what
is going on (for example, Forrest's own
<a href="../abs-linkmap">abs-linkmap</a>).
</p>
</div>
</div>
<!--+
|end content
+-->
<div class="clearboth">&nbsp;</div>
</div>
<div id="footer">
<!--+
|start bottomstrip
+-->
<div class="lastmodified">
<script type="text/javascript"><!--
document.write("Last Published: " + document.lastModified);
// --></script>
</div>
<div class="copyright">
Copyright &copy;
2002-2007 <a href="http://www.apache.org/licenses/">The Apache Software Foundation.</a>
</div>
<!--+
|end bottomstrip
+-->
</div>
</body>
</html>