blob: ef3208c07a1669fbc155284cc22346a2b466ba2c [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">
<title>Logicsheet Concepts</title>
<link href="http://purl.org/DC/elements/1.0/" rel="schema.DC">
<meta content="Ricardo Rocha" name="DC.Creator">
</head>
<body>
<h1>Index</h1>
<p>
This document introduces logicsheet design and writing
principles:
</p>
<ul>
<li>
<a href="#logicsheet">Logicsheets</a>
</li>
<li>
<a href="#helper-classes">Logicsheet Helper Classes</a>
</li>
<li>
<a href="#logicsheet-object">Logicsheets and Objects</a>
</li>
<li>
<a href="#xsl-logicsheets">Logicsheets and XSLT</a>
</li>
<li>
<a href="#java-logicsheets">
XSLT Logicsheets and XSP for Java
</a>
</li>
<li>
<a href="#logicsheet-language">
The SiLLy Logicsheet Language
</a>
</li>
</ul>
<a name="logicsheet"></a>
<h1>Logicsheets</h1>
<p>
A <em>logicsheet</em> is an XML filter used to translate user-defined,
dynamic markup into equivalent code embedding directives for a given
markup language.
</p>
<p>
Logicsheets lie at the core of XSP's promise to separate logic from
content and presentation: they make dynamic content generation
capabilities available to content authors not familiar with (and
not interested in) programming.
</p>
<p>
Logicsheets are <em>not</em> programming-language independent.
They translate dynamic tags to <em>actual code</em> enclosed in
code-embedding directives. Fortunately, this dependency can be
alleviated by judiciously using
<a href="#helper-classes">helper classes</a>.
</p>
<p>
Logicsheets are used to translate <em>dynamic tags</em> into markup
language code-embedding directives. Thus, for example, the dynamic
tag:
</p>
<pre class="code">
&lt;util:time-of-day format="hh:mm:ss"/&gt;
</pre>
<p>
would be transformed by the <em>util</em> logicsheet into an
equivalent XSP expression:
</p>
<pre class="code">
&lt;xsp:expr&gt;
SimpleDateFormat.getInstance().format(new Date(), "hh:mm:ss")
&lt;/xsp:expr&gt;
</pre>
<p>
Note that the output of logicsheet processing is <em>not</em>
final code, but rather <em>code-embedding markup language directives</em>
(<em>&lt;xsp:expr&gt;</em> in this case).
</p>
<p>
Logicsheets can be applied in sequence so that it's possible for one
logicsheet to produce dynamic tags further processed by another
logicsheet. Thus, for example:
</p>
<pre class="code">
&lt;util:time-of-day&gt;
&lt;util:param name="format"&gt;
&lt;request:get-parameter name="time-format" default="hh:mm:ss"/&gt;
&lt;/util:param&gt;
&lt;/util:time-of-day&gt;
</pre>
<p>
would be transformed by the <em>util</em> logicsheet into:
</p>
<pre class="code">
&lt;xsp:expr&gt;
SimpleDateFormat.getInstance().format(
new Date(),
&lt;request:get-parameter name="time-format" default="hh:mm:ss"/&gt;
)
&lt;/xsp:expr&gt;
</pre>
<p>
which would be transformed by the <em>request</em> logicsheet,
in turn, into:
</p>
<pre class="code">
&lt;xsp:expr&gt;
SimpleDateFormat.getInstance().format(
new Date(),
XSPRequestHelper.getParameter("name", "hh:mm:ss")
)
&lt;/xsp:expr&gt;
</pre>
<p>
Note in the examples above that dynamic tags can be
"overloaded" in the sense that they can take as parameters
either <em>constant attribute values</em> or
<em>nested parameter elements</em>:
</p>
<pre class="code">
&lt;!-- Parameter "format" known at page authoring time --&gt;
&lt;util:time-of-day format="hh:mm:ss"/&gt;
&lt;!-- Parameter "format" known at request time --&gt;
&lt;util:time-of-day&gt;
&lt;util:param name="format"&gt;
&lt;request:get-parameter name="time-format" default="hh:mm:ss"/&gt;
&lt;/util:param&gt;
&lt;/util:time-of-day&gt;
</pre>
<p>
This means that logicsheets must be able to cope with constant
strings, complex expressions and nested parameter processing.
Also, logicsheets must be capable of reporting parameter value
errors and, possibly, halt code generation altogether.
</p>
<p>
In order to minimize this complexity (and its associated debugging
nightmares!), properly designed logicsheets typically make use of
<strong>helper classes</strong>.
</p>
<a name="helper-classes"></a>
<h1>Logicsheet Helper Classes</h1>
<p>
A <em>helper class</em> is a Java class containing a collection
of <em>static</em> methods whose arguments correspond (one-to-one)
with their dynamic tag counterparts.
</p>
<p>
Consider the following dynamic tag use-case:
</p>
<pre class="code">
&lt;sql:create-connection name="demo"&gt;
&lt;sql:jdbc-driver&gt;
oracle.jdbc.driver.OracleDriver
&lt;/sql:jdbc-driver&gt;
&lt;sql:connect-url&gt;
jdbc:oracle:thin:@localhost:1521:ORCL
&lt;/sql:connect-url&gt;
&lt;sql:user-name&gt;
&lt;request:get-parameter name="user"/&gt;
&lt;/sql:user-name&gt;
&lt;sql:password&gt;
&lt;request:get-parameter name="password"/&gt;
&lt;/sql:password&gt;
&lt;/sql:create-connection&gt;
</pre>
<p>
A brute-force logicsheet template may be implemented
(in XSLT, as discussed <a href="#xsl-logicsheets">below</a>)
as:
</p>
<pre class="code">
&lt;xsl:template match="sql:create-connection"&gt;
&lt;!-- *** Argument collection skipped for the sake of brevity *** --&gt;
&lt;xsp:logic&gt; {
Class.forName(&lt;xsl:copy-of select="$jdbc-driver"/&gt;).newInstance();
Connection myConnection =
DriverManager.getConnection(
&lt;xsl:copy-of select="$connect-url"/&gt;,
&lt;xsl:copy-of select="$user-name"/&gt;,
&lt;xsl:copy-of select="$password"/&gt;
);
Session mySession = request.getSession(true);
Connection previousConnection = (Connection)
mySession.getAttribute(
"connection." + &lt;xsl:copy-of select="$name"/&gt;
);
if (previousConnection != null) {
previousConnection.commit();
previousConnection.close();
}
mySession.setAttribute(
"connection." + &lt;xsl:copy-of select="$name"/&gt;,
myConnection
)
} &lt;/xsp:logic&gt;
&lt;/xsl:template&gt;
</pre>
<p>
This approach has a number of drawbacks.
</p>
<ul>
<li>
Even when using enclosing braces around the <em>&lt;xsp:logic&gt;</em>
section, there's always the risk that the page author (or another
logicsheet!) has previously defined variables called
<span class="codefrag">myConnection</span>, <span class="codefrag">previousConnection</span> or
<span class="codefrag">mySession</span>. This will result in multiply-defined variable
compilation errors
</li>
<li>
Parameter values (like <span class="codefrag">$name</span>) cannot be safely used
more than once. As much as they can come from harmless string
constants, they can also come from complex expressions involving
method/function calls which can have unpredictable side-effects
should they be called more than once in the current context
</li>
<li>
If another logicsheet (or the page author) has imported a class
called <span class="codefrag">Connection</span> the generated code will produce an
ambiguous class definition compiler error
</li>
</ul>
<p>
It's here that helper classes come to the rescue. By moving all
the above logic to a static method <span class="codefrag">createConnection</span>
in helper class <span class="codefrag">SQLHelper</span>, we can now rewrite
(and simplify!) our logicsheet to read:
</p>
<pre class="code">
&lt;xsl:template match="sql:create-connection"&gt;
&lt;!-- *** Argument collection skipped for the sake of brevity *** --&gt;
&lt;xsp:logic&gt;
SQLHelper.createConnection(
&lt;xsl:copy-of select="$name"/&gt;,
&lt;xsl:copy-of select="$connect-url"/&gt;,
&lt;xsl:copy-of select="$user-name"/&gt;,
&lt;xsl:copy-of select="$password"/&gt;,
request
);
&lt;/xsp:logic&gt;
&lt;/xsl:template&gt;
</pre>
<p>
This simple approach brings several benefits:
</p>
<ul>
<li>
Safer parameter evaluation, with no unpredictable side
effects
</li>
<li>
Programming language-independence: expressions calling
"native" Java code tend to have the same syntax in all
programming languages, thus reducing the need to maintain
multiple versions of the same logicsheet
</li>
<li>
Simpler debugging: syntax errors can now be traced to bad
parameter values, rather than invalid code
</li>
<li>
Easier logic maintenance: it takes places at the helper
class level, rather than at the logicsheet's
</li>
<li>
Reduced generated code size.
</li>
</ul>
<a name="logicsheet-object"></a>
<h1>Logicsheets and Objects</h1>
<p>
Though not required to do so, each logicsheet typically deals with
a single <em>object type</em>.
</p>
<p>
What objects must be manipulated by means of logicsheets depends
mostly on the calling <em>host environment</em>.
</p>
<p>
Thus, for example, when Cocoon is used as a servlet, XSP pages
need access to the underlying servlet engine objects: request,
response, session, servlet config, etc.
</p>
<p>
In general, in order to enable dynamic content generation for each
host environment, logicsheets must be written that provide
markup-based access to its objects and methods:
</p>
<pre class="code">
&lt;request:get-parameter name="part-number"/&gt;
&lt;response:send-redirect location="error-page.xml"/&gt;
&lt;cookie:create name="user-preferences"/&gt;
</pre>
<p>
In general, for each object type required by a server pages
application a helper class should be written that:
</p>
<ul>
<li>
Provides access to the object's methods and services
</li>
<li>
Provides convenience methods to wrap values returned
by object methods as XML
</li>
</ul>
<p>
Within this discipline, <em>each object type must define a separate,
identifying namespace</em>.
</p>
<p>
Finally, logicsheets may require a <em>preprocessor</em> that augments
its input document with extra information prior to markup
transformation.
</p>
<p>
As an example of logicsheet preprocessing, consider an
<span class="codefrag">xbean</span> logicsheet providing services similar to the
JSP's intrinsic <span class="codefrag">&lt;jsp:useBean&gt;</span> tag:
</p>
<pre class="code">
. . .
&lt;xbean:use-bean id="myCart" class="com.acme.cart.CartBean" scope="session"&gt;
&lt;xbean:set-property property-name="type" property-value="promotion"/&gt;
&lt;xbean:set-property property-name="customer" parameter-value="custid"/&gt;
&lt;/xbean:use-bean&gt;
. . .
&lt;p&gt;
Hello &lt;xbean:get-property bean-id="myCart" property-name="customerName"/&gt;,
welcome back!
You have the following discounts:
&lt;/p&gt;
&lt;xbean:get-property bean-id="myCart" property-name="discount"/&gt;
. . .
</pre>
<p>
In this case, code to be emitted by the logicsheet will vary
wildly depending on whether a given bean property is indexed,
multivalued or object-typed; different conversions and traversing
code may be needed for each property based on its Java and
bean types.
</p>
<p>
A logicsheet preprocessor could introspect the given bean at code
generation time to augment the input document with additional
information as to make it possible for an XSLT-based logicsheet
to emit appropriate code:
</p>
<pre class="code">
. . .
&lt;xbean:use-bean id="myCart" class="com.acme.cart.CartBean" scope="session"&gt;
&lt;xbean:set-property
property-name="type" property-value="promotion"
java-type="String"
is-indexed="false"
/&gt;
&lt;xbean:set-property property-name="customer" parameter-value="custid"
java-type="String"
is-indexed="false"
/&gt;
&lt;/xbean:use-bean&gt;
. . .
&lt;p&gt;
Hello
&lt;xbean:get-property bean-id="myCart" property-name="customerName"
java-type="String"
is-indexed="false"
/&gt;,
welcome back!
You have the following discounts
&lt;/p&gt;
&lt;xbean:get-property bean-id="myCart" property-name="discount"
java-type="float"
is-indexed="true"
/&gt;
. . .
</pre>
<p>
Using this information, the logicsheet can decide, for a given
bean property, whether to generate a simple
<span class="codefrag">String.valueOf()</span> or an indexed loop displaying
individual property values.
</p>
<div class="note">
Logicsheet preprocessor is still unimplemented.
Preprocessing may be performed as well in XSLT by using
<em>extension functions</em>. Logicsheet preprocessing is meant to be
used in those cases where the XSLT processor being used by Cocoon
does not support XSLT extensions. (As of this writing, only
<a class="external" href="http://xml.apache.org/xalan/">Xalan</a>
is known to support XSLT extensions).
</div>
<a name="xsl-logicsheets"></a>
<h1>Logicsheets and XSLT</h1>
<p>
XSLT-based transformation is clearly the obvious choice for
implementing logicsheets.
</p>
<p>
XSLT provides all the capabilities needed for dynamic markup
transformation as well for final code generation (described
in
<a href="xsp-internals.html#logicsheet-generator">
Logicsheet Code Generators
</a>).
</p>
<p>
In fact, logicsheet transformations require only a subset of
XSLT much more general capabilities:
</p>
<ul>
<li>
Transforming an input element into other element(s) and
nested text (code)
</li>
<li>
Collecting and validating parameters as variables
</li>
<li>
Substituting variables as either text or nested elements
</li>
</ul>
<p>
Paradoxically, though, the XSLT and XPath expressions required
to perform these apparently simple tasks can easily become too
verbose, and hard-to-read.
</p>
<p>
This real disadvantage doesn't stem from XSLT not being appropriate
or powerful enough to perform the required transformations, but
rather from its directives being too low-level for this particular task.
</p>
<p>
In a classical XML spirit, the solution to this problem is found in
the definition of a higher-level language specifically targeted to
code-generation transformations. Documents written in this language
are transformed into "regular" XSLT stylesheets and subsequently
applied to input documents for code generation.
</p>
<p>
Such language is described in detail below, under
<a href="#logicsheet-language">
The SiLLy Logicsheet Language
</a>.
</p>
<p>
In general, XSLT logicsheets <strong>must</strong> preserve all markup
not recognized by its own templates:
</p>
<pre class="code">
&lt;xsl:template match="@*|node()" priority="-1"&gt;
&lt;xsl:copy&gt;&lt;xsl:apply-templates select="@*|node()"/&gt;&lt;/xsl:copy&gt;
&lt;/xsl:template&gt;
</pre>
<p>
Parameters should be passed to dynamic tags by means of <em>both</em>
attributes and nested elements. Also, dynamic tag parameters must be
accepted <em>both</em> as constant strings and as (potentially complex)
expressions. These two requirements are illustrated in the above
<em>util</em> logicsheet example:
</p>
<pre class="code">
&lt;!-- Parameter "format" known at page authoring time --&gt;
&lt;util:time-of-day format="hh:mm:ss"/&gt;
&lt;!-- Parameter "format" known at request time --&gt;
&lt;util:time-of-day&gt;
&lt;util:param name="format"&gt;
&lt;xsp:expr&gt;
request.getParameter("format");
&lt;/xsp:expr&gt;
&lt;/util:param&gt;
&lt;/util:time-of-day&gt;
</pre>
<p>
In order to support this, a number of utility templates have been
defined:
</p>
<pre class="code">
&lt;!-- Utility templates --&gt;
&lt;xsl:template name="get-parameter"&gt;
&lt;xsl:param name="name"/&gt;
&lt;xsl:param name="default"/&gt;
&lt;xsl:param name="required"&gt;false&lt;/xsl:param&gt;
&lt;xsl:variable name="qname"&gt;
&lt;xsl:value-of select="concat($prefix, ':param')"/&gt;
&lt;/xsl:variable&gt;
&lt;xsl:choose&gt;
&lt;xsl:when test="@*[name(.) = $name]"&gt;
"&lt;xsl:value-of select="@*[name(.) = $name]"/&gt;"
&lt;/xsl:when&gt;
&lt;xsl:when test="(*[name(.) = $qname])[@name = $name]"&gt;
&lt;xsl:call-template name="get-nested-content"&gt;
&lt;xsl:with-param name="content"
select="(*[name(.) = $qname])[@name = $name]"/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:when&gt;
&lt;xsl:otherwise&gt;
&lt;xsl:choose&gt;
&lt;xsl:when test="string-length($default) = 0"&gt;
&lt;xsl:choose&gt;
&lt;xsl:when test="$required = 'true'"&gt;
&lt;xsl:call-template name="error"&gt;
&lt;xsl:with-param name="message"&gt;
[Logicsheet processor]
Parameter '&lt;xsl:value-of select="$name"/&gt;'
missing in dynamic tag
&amp;lt;&lt;xsl:value-of select="name(.)"/&gt;&amp;gt;
&lt;/xsl:with-param&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:when&gt;
&lt;xsl:otherwise&gt;""&lt;/xsl:otherwise&gt;
&lt;/xsl:choose&gt;
&lt;/xsl:when&gt;
&lt;xsl:otherwise&gt;&lt;xsl:copy-of select="$default"/&gt;&lt;/xsl:otherwise&gt;
&lt;/xsl:choose&gt;
&lt;/xsl:otherwise&gt;
&lt;/xsl:choose&gt;
&lt;/xsl:template&gt;
&lt;xsl:template name="get-nested-content"&gt;
&lt;xsl:param name="content"/&gt;
&lt;xsl:choose&gt;
&lt;xsl:when test="$content/*"&gt;
&lt;xsl:apply-templates select="$content/*"/&gt;
&lt;/xsl:when&gt;
&lt;xsl:otherwise&gt;"&lt;xsl:value-of select="$content"/&gt;"&lt;/xsl:otherwise&gt;
&lt;/xsl:choose&gt;
&lt;/xsl:template&gt;
&lt;xsl:template name="get-nested-string"&gt;
&lt;xsl:param name="content"/&gt;
&lt;xsl:choose&gt;
&lt;xsl:when test="$content/*"&gt;
""
&lt;xsl:for-each select="$content/node()"&gt;
&lt;xsl:choose&gt;
&lt;xsl:when test="name(.)"&gt;
+ &lt;xsl:apply-templates select="."/&gt;
&lt;/xsl:when&gt;
&lt;xsl:otherwise&gt;
+ "&lt;xsl:value-of select="translate(.,'&amp;#9;&amp;#10;&amp;#13;',' ')"/&gt;"
&lt;/xsl:otherwise&gt;
&lt;/xsl:choose&gt;
&lt;/xsl:for-each&gt;
&lt;/xsl:when&gt;
&lt;xsl:otherwise&gt;"&lt;xsl:value-of select="$content"/&gt;"&lt;/xsl:otherwise&gt;
&lt;/xsl:choose&gt;
&lt;/xsl:template&gt;
&lt;xsl:template name="error"&gt;
&lt;xsl:param name="message"/&gt;
&lt;xsl:message terminate="yes"&gt;&lt;xsl:value-of select="$message"/&gt;&lt;/xsl:message&gt;
&lt;/xsl:template&gt;
</pre>
<p>
Given these utility templates, the example
<span class="codefrag">&lt;util:time-of-day&gt;</span> template would look like:
</p>
<a name="complex-example"></a>
<pre class="code">
&lt;xsl:template match="sql:create-connection"&gt;
&lt;xsl:variable name="name"&gt;
&lt;xsl:call-template name="get-parameter"&gt;
&lt;xsl:with-param name="name"&gt;name&lt;/xsl:with-param&gt;
&lt;xsl:with-param name="required"&gt;true&lt;/xsl:with-param&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:variable&gt;
&lt;xsl:variable name="jdbc-driver"&gt;
&lt;xsl:call-template name="get-parameter"&gt;
&lt;xsl:with-param name="name"&gt;jdbc-driver&lt;/xsl:with-param&gt;
&lt;xsl:with-param name="required"&gt;true&lt;/xsl:with-param&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:variable&gt;
&lt;xsl:variable name="connect-url"&gt;
&lt;xsl:call-template name="get-parameter"&gt;
&lt;xsl:with-param name="name"&gt;connect-url&lt;/xsl:with-param&gt;
&lt;xsl:with-param name="required"&gt;true&lt;/xsl:with-param&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:variable&gt;
&lt;xsl:variable name="user-name"&gt;
&lt;xsl:call-template name="get-parameter"&gt;
&lt;xsl:with-param name="name"&gt;user-name&lt;/xsl:with-param&gt;
&lt;xsl:with-param name="required"&gt;true&lt;/xsl:with-param&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:variable&gt;
&lt;xsl:variable name="password"&gt;
&lt;xsl:call-template name="get-parameter"&gt;
&lt;xsl:with-param name="name"&gt;password&lt;/xsl:with-param&gt;
&lt;xsl:with-param name="required"&gt;true&lt;/xsl:with-param&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:variable&gt;
&lt;xsp:logic&gt;
SQLHelper.createConnection(
&lt;xsl:copy-of select="$name"/&gt;,
&lt;xsl:copy-of select="$connect-url"/&gt;,
&lt;xsl:copy-of select="$user-name"/&gt;,
&lt;xsl:copy-of select="$password"/&gt;,
request
);
&lt;/xsp:logic&gt;
&lt;/xsl:template&gt;
</pre>
<p>
This example shows clearly why we need a
<a href="#logicsheet-language">SiLLy</a>
language!
</p>
<a name="java-logicsheets"></a>
<h1>XSLT Logicsheets and XSP for Java</h1>
<p>
The Java programming language defines a source program structure that
must be take into account for properly generating code:
</p>
<ul>
<li>Package declaration</li>
<li>Imports</li>
<li>Class declaration</li>
<li>Class-level declarations (methods and variables)</li>
<li>Application-specific method body</li>
</ul>
<p>
The <span class="codefrag">&lt;xsp:page&gt;</span> tag must contain one (and only
one) "user" root element.
</p>
<p>
All markup enclosed within the user root element will be placed
inside method <span class="codefrag">generate()</span> of the generated
<span class="codefrag">XSPGenerator</span> subclass.
</p>
<p>
The <span class="codefrag">&lt;xsp:structure&gt;</span>
and <span class="codefrag">&lt;xsp:include&gt;</span> tags are used to
import "external" classes and <strong>must</strong> be
top-level elements (i.e., they must placed directly under
the <span class="codefrag">&lt;xsp:page&gt;</span> root element):
</p>
<pre class="code">
&lt;xsp:structure&gt;
&lt;xsp:include&gt;java.sql.*&lt;/xsp:include&gt;
&lt;xsp:include&gt;java.text.SimpleDateFormat&lt;/xsp:include&gt;
&lt;/xsp:structure&gt;
</pre>
<p>
The <span class="codefrag">&lt;xsp:logic&gt;</span> tag can be used to
generate <em>class-level</em> variable and method declarations
when used as a top-level element:
</p>
<pre class="code">
&lt;xsp:page&gt;
&lt;xsp:structure&gt;
&lt;xsp:include&gt;java.text.SimpleDateFormat&lt;/xsp:include&gt;
&lt;/xsp:structure&gt;
&lt;!-- Class-level declarations --&gt;
&lt;xsp:logic&gt;
private static String timeOfDay(String format) {
if (format == null || format.length() == 0) {
format = "hh:mm:ss";
}
return SimpleDateFormat.getInstance().format(new Date(), format);
}
&lt;/xsp:logic&gt;
. . .
&lt;user-root&gt;
. . .
&lt;p&gt;
It's now
&lt;xsp:expr&gt;
timeOfDay(request.getParameter("timeFormat"));
&lt;/xsp:expr&gt;
&lt;/p&gt;
. . .
&lt;/user-root&gt;
&lt;xsp:page&gt;
</pre>
<p>
Thus, when a logicsheet adds to the import or class-level declaration
"sections", it <strong>must</strong> preserve all the declarations
possibly generated by previous logicsheets:
</p>
<pre class="code">
&lt;xsl:template match="xsp:page"&gt;
&lt;xsp:page&gt;
&lt;xsl:apply-templates select="@*"/&gt;
&lt;xsp:structure&gt;
&lt;xsp:include&gt;java.text.*&lt;/xsp:include&gt;
&lt;/xsp:structure&gt;
&lt;xsp:logic&gt;
private static int count = 0;
private static synchronized int getCounter() {
return ++count;
}
. . .
&lt;/xsp:logic&gt;
&lt;xsl:apply-templates/&gt;
&lt;/xsp:page&gt;
&lt;/xsl:template&gt;
</pre>
<a name="logicsheet-language"></a>
<h1>The SiLLy Logicsheet Language</h1>
<div class="note">As of today, the SiLLy Logicsheet Language does not exist. What is described below
are thoughts on possible implementation of the language.</div>
<p>
In order to overcome the extreme complexity of logicsheet transformations
expressed in XSLT, a simpler, higher-level XML transformation language
is being defined: <em>Simple Logicsheet Language</em>
(or <em>SiLLy</em>, so baptized by Stefano Mazzocchi in a humorous
rejection of its first proposed name).
</p>
<p>
SiLLy templates are much terser and easier to read and write than
the XSLT-based examples presented
<a href="#complex-example">above</a>:
</p>
<pre class="code">
&lt;sll:logicsheet
xmlns:sll="http://xml.apache.org/sll"
xmlns:xsl="http://www.w3c.org/1999/XSL/Transform"
&gt;
&lt;sll:namespace prefix="sql" uri="http://xml.apache.org/sql"/&gt;
&lt;sll:prolog&gt;
&lt;xsp:structure&gt;
&lt;xsp:include&gt;import SQLHelper;&lt;/xsp:include&gt;
&lt;/xsp:structure&gt;
&lt;sll:prolog&gt;
&lt;sll:element name="create-connection"&gt;
&lt;sll:parameter name="name" required="true"/&gt;
&lt;sll:parameter name="jdbc-driver"
default="oracle.jdbc.driver.OracleDriver"/&gt;
&lt;sll:parameter name="connect-url"
default="jdbc:oracle:thin:@localhost:1521:ORCL"/&gt;
&lt;sll:parameter name="user-name" required="true"/&gt;
&lt;sll:parameter name="password" required="true"/&gt;
&lt;sll:body&gt;
&lt;xsp:logic&gt;
SQLHelper.createConnection(
&lt;sll:parameter-value select="name"/&gt;,
&lt;sll:parameter-value select="jdbc-driver"/&gt;,
&lt;sll:parameter-value select="connect-url"/&gt;,
&lt;sll:parameter-value select="user-name"/&gt;,
&lt;sll:parameter-value select="password"/&gt;,
request
);
&lt;/xsp:logic&gt;
&lt;/sll:body&gt;
&lt;/sll:element&gt;
&lt;/sll:logicsheet&gt;
</pre>
<p>
SiLLy logicsheets are translated into an equivalent XSLT stylesheet
using XSLT itself.
</p>
<div class="note">
It is possible (and, indeed, simple) to generate a stylesheet that
uses the <span class="codefrag">xsl</span> namespace without ambiguity: XSLT processors
are bound to the XSL namespace <em>URI</em>, rather than to its
prefix. In addition to this, XSLT defines a
<span class="codefrag">&lt;xsl:namespace-alias&gt;</span> directive that can
be used to map one namespace's URI to another.
</div>
<p>
SiLLy provides a limited form of parameter validation: when a dynamic
tag parameter is defined as <em>required</em> its absence in the
source XML document will trigger the abnormal termination of the
code generation process producing a (more or less) meaningful message
by means of <span class="codefrag">&lt;xsl:message&gt;</span>
</p>
<p>
It's also possible to specify a list valid values for a parameter.
Such list will be used for parameter validation when values passed
are constants known at transformation time.
</p>
<p>
In addition to dynamic <em>tags</em>, SiLLy can also match attributes,
and processing instructions.
</p>
<p>
In absence of a schema or DTD, the following examples illustrate
the basic SiLLy matching and transformation capabilities (use-cases
are shown as XML comments):
</p>
<pre class="code">
&lt;!-- &lt;util:time-of-day format="hh:mm aa"/&gt; --&gt;
&lt;sll:element name="time-of-day" uri="http://www.plenix.org/util" prefix="util"&gt;
&lt;sll:parameter name="format" default="hh:mm:ss"/&gt;
&lt;sll:body&gt;
&lt;xsp:expr&gt;
SimpleDateFormat.getInstance().format(
new Date(),
&lt;sll:parameter-value name="format"/&gt;
)
&lt;/xsp:expr&gt;
&lt;/sll:body&gt;
&lt;/sll:element&gt;
&lt;!-- &lt;img flag:src="languageCode"/&gt; --&gt;
&lt;sll:attribute name="src" uri="http://www.plenix.org/translator" prefix="flag"&gt;
&lt;sll:body&gt;
&lt;xsp:attribute name="src"&gt;&lt;xsp:expr&gt;
request.getParameter("&lt;sll:attribute-value/&gt;");
&lt;/xsp:expr&gt;.gif&lt;/xsp:attribute&gt;
&lt;/sll:body&gt;
&lt;/sll:attribute&gt;
&lt;!-- &lt;?log Commit point reached?&gt; --&gt;
&lt;sll:processing-instruction target="log"&gt;
&lt;sll:body&gt;
&lt;xsp:logic&gt;
logger.log("&lt;sll:pi-data/&gt;");
&lt;/xsp:logic&gt;
&lt;/sll:body&gt;
&lt;/sll:attribute&gt;
</pre>
<div class="note">
<span class="codefrag">&lt;sll:processing-instruction&gt;</span> is probably
overkill
</div>
</body>
</html>