cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ricardo Rocha <rica...@apache.org>
Subject Re: XSP code namespace & sql taglib
Date Thu, 06 Apr 2000 05:04:00 GMT
On Wed, 05 Apr 2000, you wrote:
> I just updated Cocoon from CVS.  sql.xsl version 1.7 adds some
> exception catching code while creating max_rows and skip_rows.  It hit
> a namespace problem for me in the generated code.  The exceptions are
> defined "Exception e" which conflicts with "Enumeration e" declared
> earlier on my page.  I'm not sure what to do other than rename my
> pages variables.
> I think the proper solution to this is to move that max_rows and
> skip_rows code into XSPSQLLibrary.processQuery() which would avoid all
> problems.
> In the future with the whole world using taglibs <grin> it could get
> frustrating if one XSP taglib declares variables that another XSP
> tablib from a different author uses too.  I'm not sure there is a
> solution to this other than recommending taglibs try to avoid this
> situation.

A good way to avoid this problem is to restrict code inlined by
logicsheets to [static] method calls.

This approach ensures that no local variable name conflict
arises because values originated in dynamic tags are passed
to methods "anonymously" as arguments.

Thus, instead of writing:

    <!-- Class-level declarations -->
    <xsl:template match="xsp:page">
       <xsp:page>
         <xsl:copy><xsl:apply-templates select="@*"/></xsl:copy>
         <xsp:structure>
           <xsp:include>java.text.SimpleDateFormat</xsp:include>
         </xsp:structure>
       </xsp:page>
    </xsl:template>
    <!-- Dynamic Tag -->
    <xsl:template match="time-of-day">
      <xsp:logic>
        String mask = "<xsl:value-of select='@format'/>";
         if (mask.length() == 0) {
           mask= "hh:mm:ss aa";
         }
         xspCurrentNode.appendChild(
           document.createTextNode(
             (new SimpleDateFormat(mask)).format(new Date())
           )
         );
      </xsp:logic>
    </xsl:template>

(which will generate a name clash with any other variable called
"mask") one may prefer to write:

    <!-- Class-level declarations -->
    <xsl:template match="xsp:page">
       <xsp:page>
         <xsl:copy><xsl:apply-templates select="@*"/></xsl:copy>
         <xsp:structure>
           <xsp:include>java.text.SimpleDateFormat</xsp:include>
         </xsp:structure>
         <xsp:logic>
           // Class-level logic
             public static String formatDate(Date date, String pattern) {
               if (pattern == null || pattern.length() == 0) {
                 pattern = "yyyy/MM/dd hh:mm:ss aa";
               }
               try {
                 return (new SimpleDateFormat(pattern)).format(date);
               } catch (Exception e) {
                 return date.toString();
               }
             }
           </xsp:logic>
       </xsp:page>
    </xsl:template>
    <!-- Dynamic Tag -->
    <xsl:template match="time-of-day">
       <xsp:expr>
         formatDate(new Date(), "<xsl:value-of select='format'/>");
       </xsp:expr>
    </xsl:template>

In this second version, no local variable name conflict arises
because the supplied value (attribute "format") is passed to the
method as an argument.

This is not the final solution though: one still faces the possibility
that 2 logicsheets define the same static method names and
signatures!

To avoid this, static methods should be declared in a _separate_,
external class. This is what the Cocoon-supplied logicsheets do.

This approach eliminates method name/signature collision.

For the above example, a suitable helper class could be:

    // A logicsheet "peer" class
    import java.util.Date;
    import java.text.SimpleDateFormat;
    public class DateUtil {
      public static String formatDate(Date date, String pattern) {
        if (pattern == null || pattern.length() == 0) {
          pattern = "yyyy/MM/dd hh:mm:ss aa";
        }
        try {
          return (new SimpleDateFormat(pattern)).format(date);
         } catch (Exception e) {
           return date.toString();
         }
       }
     }
    }

while the revised logicsheet would look like:

    <!-- Class-level declarations -->
    <xsl:template match="xsp:page">
       <xsp:page>
         <xsl:copy><xsl:apply-templates select="@*"/></xsl:copy>
         <xsp:structure>
           <xsp:include>DateUtil</xsp:include>
         </xsp:structure>
       </xsp:page>
    </xsl:template>
    <!-- Dynamic Tag -->
    <xsl:template match="time-of-day">
       <xsp:expr>
         DateUtil.formatDate(new Date(), "<xsl:value-of select='format'/>");
       </xsp:expr>
    </xsl:template>

If, for some strange reason, one _really_ wants to embed logic in the
logicsheet, it's always possible to enclose the intervening <xsp:logic>
block in braces in order to minimize the possibility that inner variables
(local to the block) collide with other names:

    <xsl:template match="time-of-day">
      <xsp:logic>  {  // Note the opening brace
        String mask = "<xsl:value-of select='@format'/>";
         if (mask.length() == 0) {
           mask= "hh:mm:ss aa";
         }
         xspCurrentNode.appendChild(
           document.createTextNode(
             (new SimpleDateFormat(mask)).format(new Date())
           )
         );
      } // Note the closing brace  </xsp:logic>
    </xsl:template>

Needless to say, this works _only_ if there are no previous,
outer-scope declarations of a variable called "mask"...

Summarizing, a good approach to logicsheet authoring is:

1) Write an external helper class containing as many
    static methods as dynamic tags. Have these methods
    receive as arguments values provided by attributes
    and nested elements in your dynamic tags. Have these
    methods return the proper Java type and wrap their
    invocation inside an <xsp:expr> tag. If these methods
    must build DOM nodes, pass the XSP-defined
    "document" variable to be used as a node factory.

2) In your logicsheets, write dynamic tag templates so that
    they contain only their corresponding helper class method
    invocation

Hope this helps...

Ricardo

Mime
View raw message