| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Copyright 2002-2004 The Apache Software Foundation |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN" "http://forrest.apache.org/dtd/document-v20.dtd"> |
| <document> |
| <header> |
| <title>Publication Templating</title> |
| </header> |
| <body> |
| |
| <section> |
| <title>What is Publication Templating?</title> |
| <p> |
| Imagine you are a company or organisation with some departments which want to edit |
| their content using a Lenya-based CMS. All departments use similar publications, |
| sharing lots of functionality. The layout is based on a common corporate identity, |
| but some departments want to use their own logo or tweak the navigation menu style. |
| </p> |
| <p> |
| If all departments develop their own publications, it will be very hard to keep them |
| consistent, to add changes to all publications or to update them to a newer Lenya version. |
| This can be simplified using publication templates. You define a base (template) publication |
| which all others are derived from. |
| </p> |
| |
| <source xml:space="preserve"> |
| +----------------------+ |
| | Template Publication | |
| +----------------------+ |
| | |
| +-----------------+------+---------------------+ |
| | | | |
| +--------------+ +--------------+ +--------------+ |
| | Department A | | Department B | ... | Department X | |
| +--------------+ +--------------+ +--------------+ |
| </source> |
| |
| <p>Multiple layers of templates are supported.</p> |
| |
| <source xml:space="preserve"> |
| +--------------------------------+ |
| | University Website Publication | |
| +--------------------------------+ |
| | |
| +-----------------+------+------------------------+ |
| | | | |
| +------------+ +--------------------+ +-------------+ |
| | Uni Zurich | | Harvard University | ... | UC Berkeley | |
| +------------+ +--------------------+ +-------------+ |
| | |
| +----------+---+-----------+ |
| | | | |
| +----------+ +-----+ +---------+ |
| | Business | | Law | ... | Medical | |
| +----------+ +-----+ +---------+ |
| </source> |
| |
| </section> |
| |
| <section> |
| <title>The Concept of Publication Templating</title> |
| |
| <ul> |
| <li>There is a publication <em>my-pub</em>.</li> |
| <li>It depends on a template which is called <em>template(my-pub)</em>.</li> |
| <li>When a file is requested using the templating mechanism (<code>fallback://xslt/page2xhtml.xsl</code>), |
| it is searched in a certain traversing order: |
| <ol> |
| <li><code>context://lenya/pubs/my-pub/xslt/page2xhtml.xsl</code></li> |
| <li><code>context://lenya/pubs/template(my-pub)/xslt/page2xhtml.xsl</code></li> |
| <li><code>context://lenya/pubs/template(template(my-pub))/xslt/page2xhtml.xsl</code></li> |
| <li>...</li> |
| <li><code>context://xslt/page2xhtml.xsl</code></li> |
| </ol> |
| </li> |
| </ul> |
| |
| <p> |
| The publication <em>my-pub</em> is called an <strong>instance</strong> of the publication <em>template(my-pub)</em>. |
| Note that, in contrast to the fallback mechanism in Lenya 1.2, the prefix <code>lenya</code> is not used, |
| but the path is resolved relatively to the <code>context://</code> root. |
| </p> |
| |
| </section> |
| |
| <section> |
| <title>Declaration of a Template</title> |
| <p>The template of a publication is declared in <code>my-pub/config/publication.xml</code>:</p> |
| |
| <source xml:space="preserve"><![CDATA[<publication> |
| ... |
| <templates> |
| <template id="my-template"/> |
| </templates> |
| ... |
| </publication>]]></source> |
| </section> |
| |
| <section> |
| <title>Usage</title> |
| <p>To invoke publication templating, it is necessary to use the <code>fallback://</code> |
| protocol for all relevant files. For an XSLT stylesheet, the according pipeline looks as follows:</p> |
| |
| <source xml:space="preserve"><![CDATA[<map:transform src="fallback://xslt/doctypes/doctype2xhtml.xsl">]]></source> |
| </section> |
| |
| <section> |
| <title>XSLT Include and Import</title> |
| <p> |
| To leverage the publication templating concept, it is necessary to apply it to included |
| or imported stylesheets as well. Fortunately, we can make use of the <code>fallback://</code> |
| protocol in XSLT stylesheets. At the moment, this only works with Xalan which means you |
| have to use this one as the default transformer. |
| </p> |
| <source xml:space="preserve"><![CDATA[<xsl:include href="fallback://header.xsl"/>]]></source> |
| <p> |
| To simplify overriding of XSLT stylesheets, it is very useful to import the template |
| stylesheet. The template-fallback source factory skips the current publication when |
| resolving the file, i.e. it resolves the first existing ancestor file: |
| </p> |
| <source xml:space="preserve"><![CDATA[<xsl:import href="template-fallback:mypub://template/xslt/common/header.xsl"/>]]></source> |
| <p> |
| It is necessary to pass the ID of the publication which contains the importing file |
| after the protocol string because otherwise the template-fallback resolving mechanism |
| will fail. For more information, see |
| <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=40564">bug 40564</a>. |
| </p> |
| </section> |
| |
| <section> |
| <title>Sitemaps</title> |
| <p> |
| If a sitemap is loaded from a template publication, it is very important that the sitemap |
| is completely fallback-enabled. Otherwise, the source resolver will resolve sources relatively |
| to the template sitemap instead of using the overridden ones. |
| </p> |
| <p> |
| In <code>lenya/global-sitemap.xmap</code>, all publication sitemaps are mounted |
| using the fallback module, for instance |
| </p> |
| <source xml:space="preserve"><![CDATA[<!-- Enter the actual publication --> |
| <map:match pattern="*/**"> |
| <map:mount uri-prefix="{1}" src="{fallback:sitemap.xmap}"/> |
| </map:match>]]></source> |
| </section> |
| |
| <section> |
| <title>Usecases</title> |
| <p> |
| The <a href="site:usecase-framework-overview">usecase framework</a> |
| supports publication templating by default. |
| </p> |
| <p> |
| If you can't (or don't want to) use the usecase framework, you have to implement |
| your own usecase sitemap. The traversing order for usecase sitemaps is |
| </p> |
| <ol> |
| <li><code>context://lenya/pubs/my-pub/usecase.xmap</code></li> |
| <li><code>context://lenya/pubs/template(my-pub)/usecase.xmap</code></li> |
| <li><code>context://lenya/pubs/template(template(my-pub))/usecase.xmap</code></li> |
| <li>...</li> |
| <li><code>context://lenya/usecase.xmap</code></li> |
| </ol> |
| <p> |
| This behaviour is achieved by the usecase fallback module which is called in <code>global-sitemap.xmap</code>: |
| </p> |
| <source xml:space="preserve"><![CDATA[<map:match type="usecase" pattern="*"> |
| <map:mount src="{usecase-fallback:{1}}" uri-prefix=""/> |
| </map:match>]]></source> |
| <p> |
| The decision which <code>usecase.xmap</code> to choose is based on the usecase configuration |
| in <code>publication.xml</code>. To declare a usecase to be implemented by a publication, |
| add the corresponding entry: |
| </p> |
| <source xml:space="preserve"><![CDATA[<publication> |
| ... |
| <usecases> |
| <usecase name="create"/> |
| </usecases> |
| ... |
| </publication>]]></source> |
| </section> |
| |
| <section> |
| <title>Setting Up a Publication To Support Templating</title> |
| |
| <p> |
| The service <code>org.apache.lenya.cms.publication.templating.Instantiator</code> is responsible for |
| creating instances of publications which support templating. If your publication shall support |
| templating, you have to follow these steps: |
| </p> |
| |
| <section> |
| <title>Implement an <code>Instantiator</code> Class</title> |
| |
| <source xml:space="preserve"><![CDATA[package org.myproject.lenya; |
| |
| public class MyInstantiator extends AbstractLogEnabled implements Instantiator { |
| |
| public void instantiate(Publication template, String newPublicationId, String name) |
| throws Exception { |
| ... |
| } |
| |
| }]]></source> |
| </section> |
| |
| <section> |
| <title>Add it to <code>cocoon.xconf</code> Using a Patch File</title> |
| |
| <p> |
| For instance <code>my-pub/config/cocoon-xconf/instantiator.xconf</code>: |
| </p> |
| |
| <source xml:space="preserve"><![CDATA[<xconf xpath="/cocoon/template-instantiators" |
| unless="/cocoon/template-instantiators/component-instance[@name = 'default']"> |
| |
| <component-instance name="mypub" |
| logger="myproject.publication" |
| class="org.myproject.lenya.MyInstantiator"/> |
| |
| </xconf>]]></source> |
| </section> |
| |
| <section> |
| <title>Declare the Instantiator in <code>publication.xml</code></title> |
| </section> |
| |
| <source xml:space="preserve"><![CDATA[<publication> |
| ... |
| <template-instantiator name="mypub"/> |
| ... |
| </publication>]]></source> |
| </section> |
| |
| </body> |
| </document> |