cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ricardo Rocha <rica...@apache.org>
Subject On Logicsheets (long)
Date Wed, 24 May 2000 15:41:52 GMT
Hi guys,

We all know logicsheets are a very poweful mechanism for
markup-to-code transformation.

So far, however, most users have shied away from logicsheet
authoring because it appears to be too complex and the
arcanes of XSLT-based code generation remain largely unkown
due to lack of documentation [my fault, I admit, :-(]

Despite its name, XSP is more than just server pages. Its
underlying markup-to-code transformation machinery can be
used for all sorts of applications and execution environments
beyond servlets and web publishing...

Thus, for instance, XSP now produces Cocoon2 Generators only
but we're extending it to generate any program type (e.g.,
Filters) as well as to support multiple execution
environments (servlet, offline, others).

Seen from this perspective, XSP is simply an XML application
aimed at transforming markup into executable code for a
wide variety of potential applications.

Code generation in XSP is XSLT-based (though it's not
really required to be so). XSLT-based code generation is
extremely powerful and, imho, much more general and better
suited for markup-to-code transformation than "manual"
approaches.

Granted, some logicsheets may look somewhat schizophrenic at
first sight. While it appears to be possible to come up with
a proper XSLT/Xpath expression for almost any kind of code-
generation requirement, some _recurrent_ constructs are just
too long, too complex or error-prone. Needless to say, this
is also reflected in more difficult debugging.

This clearly calls for a higher-level transformation
language whose vocabulary is explicitly targeted to code
generation and whose matching expressions are easier to
write and understand.

[Improvised] Example.

Given the logicsheet:

<cgl:namespace prefix="response" uri="..."/>
<cgl:template match-type="element" name="send-redirect">
  <cgl:parameter name="location" required="true"/>
  <cgl:body type="logic">
    response.sendRedirect(<cgl:parameter-value name="url"/>);
  </cgl:body>
</cgl:element>

the input expression:

<response:send-redirect>
  <response:location>
    <xsp:expr>context.getErrorPage()</xsp:expr>
  </response:location>
</response:send-redirect>

would yield:

<xsp:logic>
  response.sendRedirect(context.getErrorPage());
</xsp:logic>

while the input expression:

<response-send:redirect location="error-page.xsp"/>

would yield:

<xsp:logic>
  response.sendRedirect("error-page.xsp");
</xsp:logic>

Note that the "location" parameter can be passed as either
an attribute (when its constant value is known at design
time) or as a nested element (when it must be computed from
some other expression, itself possibly logicsheet-based).
This example also assumes that some parameter validation
is performed at code-generation time.

The idea here is to shield the logicsheet author from
the complexities of plain-vanilla XSLT argument collection
and validation, as well as dealing with string constants
vs. Java expressions, etc.

Such complexity is reflected in the following, _equivalent_
XSLT templates: (please, be patient!)

<xsl:template match="response:send-redirect">
  <xsl:variable name="location">
    <xsl:call-template name="get-parameter">
      <xsl:with-param name="name">location</xsl:with-param>
      <xsl:with-param name="required">true</xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  <xsp:logic>
    response.sendRedirect(<xsl:copy-of select="$location"/>);
  <xsp:logic>
</xsl:template>
<xsl:template name="get-parameter">
  <xsl:param name="name"/>
  <xsl:param name="default"/>
  <xsl:param name="required">false</xsl:param>
  <xsl:variable name="qname">
    <xsl:value-of select="concat($prefix, ':param')"/>
  </xsl:variable>
  <xsl:choose>
    <xsl:when test="@*[name(.) = $name]">"<xsl:value-of
select="@*[name(.) = $name]"/>"</xsl:when>
    <xsl:when test="(*[name(.) = $qname])[@name = $name]">
      <xsl:call-template name="get-nested-content">
        <xsl:with-param name="content"
           select="(*[name(.) = $qname])[@name = $name]"/>
        </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:choose>
        <xsl:when test="string-length($default) = 0">
          <xsl:choose>
            <xsl:when test="$required = 'true'">
              <xsl:call-template name="error">
                <xsl:with-param name="message">[Logicsheet processor]
Parameter '<xsl:value-of select="$name"/>' missing in dynamic tag
&lt;<xsl:value-of select="name(.)"/>&gt;
                </xsl:with-param>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>""</xsl:otherwise>
          </xsl:choose>
         </xsl:when>
         <xsl:otherwise><xsl:copy-of select="$default"/></xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
<xsl:template name="get-nested-content">
  <xsl:param name="content"/>
  <xsl:choose>
    <xsl:when test="$content/*">
      <xsl:apply-templates select="$content/*"/>
    </xsl:when>
    <xsl:otherwise>"<xsl:value-of select="$content"/>"</xsl:otherwise>
  </xsl:choose>
</xsl:template>
<xsl:template name="error">
  <xsl:param name="message"/>
  <xsl:message terminate="yes"><xsl:value-of
select="$message"/></xsl:message>
</xsl:template>


Geez! _All_ this XSLT code is equivalent to the much (!)
simpler above logicsheet template:

<cgl:template match-type="element" name="send-redirect">
  <cgl:parameter name="location" required="true"/>
  <cgl:body type="logic">
    response.sendRedirect(<cgl:parameter-value name="url"/>);
  </cgl:body>
</cgl:element>

NOTE: Please, don't take this example as a proposal for the
"real" logicsheet language syntax. I just made it up to
illustrate my point...

This "cgl" XML language can be readily translated into
an equivalent XSLT stylesheet, so that the existing
XSP code-generation machinery would continue to work
unchanged.

Logicsheet authors, though, would certainly benefit from
a higher-level, more intuitive syntax to write their
code templates.

There's nothing really new to this. Code generation in the
old days was usually based on templates written in macro
preproprocessing languages like the unforgettable m4. Many
of you, C(++) programmers, may have missed the proprocessor
on many an occasion...

Code generation uses only a manageable subset of XSLT
transformation capabilities and the usage patterns it
exhibits are indeed _very_ simple (though, admittedly,
too verbose).

Well, enough for now. This is not a formal, carefully thought out
proposal.

It's just a hint that logicsheet authoring can be made
much simpler with a properly designed transformation
language.

It's also a call to start discussing the underlying issues:
the logicsheet language syntax, how to achieve target
programming language independence/portability, etc.

Regards,

Ricardo

Mime
View raw message