Keep in mind that there's also a JX!TemplateTransformer with the same functionality.
Current namespace: xmlns:jx="http://apache.org/cocoon/templates/jx/1.0"
Sitemap Configuration: <map:generator name="jx" src="org.apache.cocoon.generation.JXTemplateGenerator" label="content" logger="sitemap.generator.jx"/>
Accessing data with the JXTemplateGenerator
JSTL and XPath
The JX!TemplateGenerator provides a generic page templating mechanism. You can embed either JSTL or XPath expressions to access data from several implicitly defined Cocoon objects (e.g. request, session etc.), or from objects you have passed to the JX!TemplateGenerator from your flow script. For example, this is how you would access the current contination id using each expression language:
Using JSTL(Apache Jexl): ${cocoon.continuation.id}
Using XPath(Apache JXPath): #{$cocoon/continuation/id}
Using Javascript: @{cocoon.get('continuation').getId()}
As one can see, you explicitly need knowledge about the object types and their methods when using the Javascript notation. The other to (JSTL and JXPath) are much easier, they simplify the access to Maps and getProperty() methods by using the "." notation.
Older Cocoon without cocoon. prefix (not sure when there was a change...):
Using JSTL(Apache Jexl): ${continuation.id}
Using XPath(Apache JXPath): #{$continuation/id}
Accessing data from implicitly defined Cocoon objects
You have access to some implicitly defined objects (available through both JSTL and XPath):
- cocoon - Base object, holding all the other ones to avoid conflicts with variables from a flowscript
- continuation - The current flow script continuation
request - The Cocoon current request (org.apache.cocoon.environment.Request)
session - The Cocoon session associated with the current request (org.apache.cocoon.environment.Session)
context - The Cocoon context associated with the current request (org.apache.cocoon.environment.Context)
parameters - A map of parameters passed to the generator in the pipeline (org.apache.avalon.framework.parameters.Parameters)
An access to the request uri for example would be (JSTL): ${cocoon.request.uri}
Accessing sitemap parameters
Cocoon sitemap parameters are accessed through the parameters object. For example, your sitemap might look like this: {{{<map:generate src="jxtemplate.xml" type="jx">
<map:parameter name="my-param" value="my-value"/>
</map:generate}}} To access the value of my-param in your jxtemplate.xml file (using JSTL in this case) your expression would look like this: ${cocoon.parameters['my-param']} (when you have simpler names without special characters like "-", you won't need the ['something'] notation but can still use ${cocoon.parameters.something} ).
Accessing data passed from your flow scripts
You may also pass Java Beans, DOM, JDOM, or JavaScript objects from your flow scripts. Once again, this will work in both JSTL and XPath. For example: {{{var greatlakes = Superior", "Michigan", "Huron", "Erie", "Ontario; sendPage(uri, {"greatlakes" : greatlakes});}}}
Those parameters can be accessed as top-level variables, eg. accessing "greatlakes" is as easy as (JSTL): ${greatlakes} .
Basic features
jx:choose, jx:when, jx:otherwise
The choose tag performs conditional block execution by the embedded when sub tags. It renders the body of the first when tag whose test condition evaluates to true. If none of the test conditions of nested when tags evaluate to true, then the body of an otherwise tag is evaluated, if present.
<jx:choose>
<jx:when test="Expression">
body
</jx:when>
<jx:otherwise>
body
</jx:otherwise>
</jx:choose>
jx:forEach
Iterate over a collection of objects.
<jx:forEach [var="Name"][items="Expression"][begin="Number"][end="Number"][step="Number"]>
body
</jx:forEach>- @var - Contains the current item
- @items - The list of items to iterate over
- @begin - Element to start with, defaults to 0
- @end - Element to end with, defaults to last element
- @step - Step to take to next Element, defaults to 1
jx:formatDate
The formatDate tag provides facilities to format Date values.
<jx:formatDate value="Expression"
[dateStyle="Style"]
[timeStyle="Style"]
[pattern="Expression"]
[type="Type"]
[var="Name"]
[locale="Expression"]>
jx:formatNumber
The formatNumber tag is used to display numeric data, including currencies and percentages, in a locale-specific manner. The formatNumber> action determines from the locale, for example, whether to use a period or a comma for delimiting the integer and decimal portions of a number.
<jx:formatNumber value="Expression"
[type="Type"]
[pattern="Expression"]
[currencyCode="Expression"]
[currencySymbol="Expression"]
[maxIntegerDigits="Expression"]
[minIntegerDigits="Expression"]
[maxFractionDigits="Expression"]
[minFractionDigits="Expression"]
[groupingUsed="Expression"]
[var="Name"]
[locale="Expression"]>
jx:if
Conditional logic based on evaluation of an expression in @test.
<jx:if test="Expression">
body
</jx:if>
jx:import
Import a JXTemplate, the uri will be resolved by cocoon (possible to use cocoon:/ etc.).
<jx:import uri="URI" [context="Expression"]/>
This tag is not for including XML, but just for other JXTemplates.
jx:macro, jx:parameter
Define a new custom tag. When calling a macro, the line will be substituted with the body of the macro.
<jx:macro name="customTagName" [targetNamespace="Namespace"]>
<jx:parameter name="paramA" [optional="Boolean"] [default="Value"]/>*
body
</jx:macro>Once defined, call your macro with:
<customTagName paramA="someValue"/>
If you pass the 'greatlakes' as in the example above, you may have a macro:
<jx:macro name="tablerows">
<jx:parameter name="list"/>
<jx:parameter name="color"/>
<jx:forEach var="item" items="${list}">
<tr><td bgcolor="${color}">${item}</td></tr>
</jx:forEach>
</jx:macro>
<table>
<tablerows list="${greatlakes}" color="blue"/>
</table>Your result would be:
<table> <tr><td bgcolor="blue">Superior</td></tr> <tr><td bgcolor="blue">Michigan</td></tr> <tr><td bgcolor="blue">Huron</td></tr> <tr><td bgcolor="blue">Erie</td></tr> <tr><td bgcolor="blue">Ontario</td></tr> </table>
In cocoon 2.2-dev you can call your macro like this:
<jx:call macro="customTagName"> <jx:withParam name="paramA" value="someValue"/> </jx:call>
You are allowed to use expressions in macro name:
<jx:set var="macroName" value="customTagName"/>
<jx:call macro="${macroName}">
<jx:withParam name="paramA" value="someValue"/>
</jx:call>
jx:out
Evaluates an expression and outputs the result of the evaluation:
<jx:out value="Expression"/>
Please note that jx:out automatically handles objects of type Node, Node[], NodeList, XMLizable and renders them as SAX events.
Cocoon 2.2: You can make JXTG parse expression string result into SAX events by using following syntax:
<jx:out value="Expression" xmlize="true"/>
Additionally you can ignore root element of generated content with strip-root="true" attribute.
Example:
myXml = "<root><p>content</p><p>content2</p></root>";
<nonxmlized><jx:out value="${myXml}"/></nonxmlized>
<xmlized><jx:out value="${myXml}" xmlize="true" strip-root="true"/></xmlized>
result is:
<nonxmlized><root><p>content</p><p>content2</p></root></nonxmlized>
<xmlized><p>content</p><p>content2</p></xmlized>
jx:set
Define/set a variable
<jx:set var="Name" value="Value"/>
or
<jx:set var="Name">
[Value=body]
</jx:set>
jx:template
Defines a new JXTemplate
<jx:template>
jx-elements
</jx:template>
jx:attribute (cocoon 2.2-dev)
Set's an attribute.
<jx:attribute name="Name" value="Value"/>
Allows for conditional attribute injection. Example:
<jx:set var="a" value="cd"/>
<two>
<jx:if test="${a == 'dd'}">
<jx:attribute name="second" value="twoAttr"/>
</jx:if>
xyz
</two>
<three foo="bar">
<jx:attribute name="foo2" value="bar2"/>
<jx:attribute name="${a}" value="${a}"/>
<abc>def</abc>
</three>evaluates to:
<jx:set var="a" value="cd"/>
<two>
xyz
</two>
<three foo="bar" foo2="bar2" cd="cd">
<abc>def</abc>
</three>
Advanced
This section describes some advanced options.
Caching
It is possible for cocoon to cache output of this generator. In order to do so you need to provide two pieces of information: the key under which to register the cached response object in the cache and an object that describes the validity of the cached contents.
Note: This feature is experimental and only available in the cocoon 2.2.0-dev branch in CVS
jx:cache-key
Specify the cache key using jx:cache-key attribute.
<element jx:cache-key="Expression"/>
jx:cache-validity
Specify the cache validity using jx:cache-validity attribute.
<element jx:cache-validity="Expression"/>
Example
* template.xml:
<?xml version="1.0"?>
<page jx:cache-key="${cacheKey}" jx:cache-validity="${cacheValidity}"
xmlns:jx="http://apache.org/cocoon/templates/jx/1.0"/>* flow.js:
importPackage(Packages.org.apache.excalibur.source.impl.validity);
function foo() {
sendPage("bar", {cacheKey: "theKey", cacheValidity: new ExpiresValidity(1000)})
}* sitemap.xmap:
<?xml version="1.0"?>
<map:sitemap>
...
<map:pipeline type="caching">
<map:match pattern="foo">
<map:call function="foo"/>
</map:match>
<map:match pattern="bar">
<map:generate type="jx" src="template.xml"/>
<map:serialize type="xml"/>
</map:match>
</map:pipeline>
</map:sitemap>
Heavy business object instantiation
Even though JXTemplateGenerator caches the view data it does not mean the controller will know about that. If your script contains heavy calculations or database operations this is what you can do (based on: http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=108617011419745&w=2)
If your business object takes an age to instantiate, and you can decide whether or not to instantiate it based upon request parameters, then wrap it in a lighter component that does (in pseudocode):
lightObject.getValidity() {
return request.parameters["a"]+ request.parameters["b"];
}
lightObject.getHeavyBusinessObject() {
if (this.heavyBusinessObject == null) {
this.heavyBusinessObject = HeavyBusinessObjectBuilder.newObject();
}
return this.heavyBusinessObject;
}Then, in your jxt, you use jx:cache-validity="${lightObject.getValidity()}" construct, and then later in your jxt, you access your heavy object with #{/lightObject/HeavyObject/property1} . This latter expression will only be invoked if the page is not cached.