The navigation Module
- Introduction
- The Site Fragment Generator
- Using Fragment Selectors
- Declaring and Calling the Site Fragment Generator
- Applying an XSL Transformation
Introduction
The navigation module allows to create navigation widgets like menus, breadcrumb paths, and language selectors, based on the site structure. It has some advantages over the old navigation framework which is provided by the sitetree module. Since it uses Java instead of XSLT to build the navigation structure and generates only the necessary nodes instead of filtering the whole sitetree, the performance is generally better and the code is easier to read.
The Site Fragment Generator
Each widget is generated using a separate pipeline.
The starting point of the pipeline is the SiteFragmentGenerator
. Like the name
suggests, it generates a fragment of the website structure. More specifically, it generates
an XML structure consisting of <node>
and <link>
elements, corresponding to the SiteNode
and Link
objects of the site
structure object model. Here's an example output of the SiteFragmentGenerator
:
<site:fragment pub="mypub" area="live" xmlns:site="http://apache.org/lenya/site/1.0" <site:node name="company" uuid="b92e48e0-e986-11dc-b04f-af2277a493d7"> <site:link xml:lang="en" label="Company" href="lenya-document:b92e48e0-…"/> </site:node> <site:node name="products" uuid="af57d250-…" ancestorOfCurrent="true"> <site:link xml:lang="en" label="Products" href="lenya-document:…"/> <site:node name="bicycles" uuid="c027de40-e986-11dc-b04f-af2277a493d7"> <site:link xml:lang="en" label="Bicycles" href="…" current="true"/> </site:node> </site:node> </site:fragment>
The SiteFragmentGenerator
uses the namespace
http://apache.org/lenya/site/1.0
and produces the following elements and attributes:
- <site:fragment>
-
- pub - The publication ID.
- area - The area.
- <site:node>
-
- name - The node name, which is the URL snippet identifying the node. Some CMSs use the term slug.
- uuid - The UUID of the node.
- ancestorOfCurrent - If this attribute has the value true, the currently selected link belongs to a sub-node (child, grand-child, …) of this node. The value won't be true if the selected link belongs to the node itself!
- <site:link>
-
- xml:lang - The language code.
- label - The label of the node, i.e. the string to be displayed as the title of the navigation item.
-
href - The URI of the node, using the syntax
lenya-document:…,lang=…,area=…,pub=…
. Since the link is fully qualified (i.e., all relevant parameters are provided), it can be resolved safely outside the publication. - current - If this attribute has the value true, the link is currently selected (i.e., the corresponding document is displayed).
Using Fragment Selectors
To simplify the implementation of custom navigation widgets and to ensure
the separation of concerns, the SiteFragmentGenerator
delegates
the decision which nodes and links to render to a FragmentSelector
.
The FragmentSelector
class has to implement a single method:
public interface FragmentSelector { void selectFragment(NodeGenerator generator, SiteStructure site, String path, String language) throws SAXException, SiteException; }
Parameters:
- generator - This is a reference to the generator itself. It allows the fragment selector to invoke the callback functions which actually generate the node and link XML elements.
- site - The site structure which the widget shall be based on.
- path - A reference path. This path is passed from the sitemap to the generator. It can be an arbitrary path, but usually it is the path of the node of the currently selected document. It doesn't necessarily have to exist in the site structure.
- language - The language of the currently selected document.
Exceptions:
-
A SAXException is thrown if an error occurs
during the invocation of the
NodeGenerator
callback functions. - A SiteException is thrown if an error occurs while the site structure is accessed.
The following fragment selectors are included in the module:
- BreadcrumbSelector
- Selects the nodes from the top-level node down to the currently selected node. Only the links for the currently selected language are included.
- ChildrenSelector
- Selects the child nodes of the node identified by the path parameter non-recursively. If the path is "" or "/", the top-level nodes are generated. Only the links for the currently selected language are included.
- LanguagesSelector
- Selects the node which is identified by the path parameter and its links for all languages. The link for the currently selected language will have the attribute current="true".
- SubtreeAndSiblingsSelector
- Selects the node identified by the path parameter, its siblings, and its children recursively. If the path is "" or "/", the nodes of the whole site are generated. Only the links for the currently selected language are included.
- SubtreeSelector
- Selects the node identified by the path parameter and its children recursively. If the path is "" or "/", the nodes of the whole site are generated. Only the links for the currently selected language are included.
Declaring and Calling the Site Fragment Generator
For each type of navigation widget, a separate generator is declared. To tell the generator which fragment selector to use, specify the fragment selector class in the declaration:
<map:generator name="tabs" logger="lenya.generators.tabs" src="org.apache.lenya.modules.navigation.SiteFragmentGenerator"> <map:parameter name="selector" value="org.apache.lenya.modules.navigation.ChildrenSelector"/> </map:generator>
The following listing shows how the site fragment generator is called:
<map:match pattern="tabs"> <map:generate type="tabs"> <map:parameter name="pub" value="{page-envelope:publication-id}"/> <map:parameter name="area" value="{page-envelope:area}"/> <map:parameter name="lang" value="{page-envelope:language}"/> <map:parameter name="path" value="{page-envelope:document-path}"/> <map:parameter name="selectorPath" value="/"/> </map:generate> <map:transform src="xslt/navigation/tabs.xsl"/> <map:serialize/> </map:match>
The generator expects the following parameters:
- pub - The current publication ID.
- area - The current area.
- lang - The language of the currently selected document.
- path - The path of the currently selected document.
- selectorPath - The reference path to be passed to the fragment selector. In the example above this is the root of the site tree, so the top-level nodes are rendered as tabs. The path parameter is used to determine which link should get the current="true" attribute.
Applying an XSL Transformation
The site fragment generator uses a custom output format to support arbitrary formatting options.
The formatting is usually done using XSLT. The stylesheet tabs.xsl
from the sitemap snippet
above could for instance look like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:site="http://apache.org/lenya/site/1.0" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="site" > <xsl:template match="site:fragment"> <ul id="tabs"> <xsl:apply-templates select="site:node/site:link"/> </ul> </xsl:template> <xsl:template match="site:link[@current = 'true' or ../@ancestorOfCurrent = 'true']"> <li><a href="{@href}"><xsl:value-of select="@label"/></a></li> </xsl:template> <xsl:template match="site:link[not(@current = 'true' or ../@ancestorOfCurrent = 'true')]"> <li><xsl:value-of select="@label"/></li> </xsl:template> </xsl:stylesheet>
The output XHTML could looke like this:
<ul id="tabs" xmlns="http://www.w3.org/1999/xhtml"> <li>Company</li> <li><a href="lenya-document:…">Products</a></li> <li>Services</li> </ul>