XSP Processor

| Introduction |
XSP (eXtensible Server Pages) is Cocoon's technology for building web applications based on dynamic XML content. Beyond static content (i. e., hand-written documents produced by web authors), web applications demand dynamic content generation capabilities, where XML documents or fragments are programmatically produced at request time. In this context, content is the result of computations based on request parameters and, often, on access to external data sources such as databases or remote server processes. This distinction in content origin extends the "traditional" regions of web publishing (content and presentation) to also encompass that of logic. Dynamic web content generation has traditionally been addressed by embedding procedural code into otherwise static markup. This approach is fully supported by XSP. Consider the following example:
    . . .
    <p>
      Good
      <xsp:logic>
        String timeOfDay = (
          new SimpleDateFormat("aa")
        ).format(new Date());

        if (timeOfDay.equals("AM")) {
          <xsp:content>Morning</xsp:content>
        } else {
          <xsp:content>Afternoon</xsp:content>
        }
      </xsp:logic>!
    </p>
    . . .
Upon XSP processing, this XML fragment will yield:
    <p>Good Morning!</p>
before noon and:
    <p>Good Afternoon!</p>
afterwards. While the above may appear simple (to a Java developer, that is!), XSP has been conceived to allow web authors to generate dynamic content without forcing them to learn a programming language. Thus, XSP allows us to rephrase our example as:
    ...
    <p>Good <util:time-of-day/>!</p>
    ...
where `<util:time-of-day/>` is a library tag encapsulating dynamic content in a simple, transparent way. This feature promotes an ideal division of labor where: Application Developers encapsulate application logic in a consistent, intuitive dynamic tagset Content authors use an application-oriented markup vocabulary (augmented with dynamic tags) to produce XML documents Presentation designers write XSLT stylesheets to render the resulting content as visually appealing web pages Of course, for those of us subject to "real world" constraints, XSP also supports the time-honored approach of first using embedded logic and then incrementally evolving the resulting pages into a well-structured web application. These concepts are illustrated in the XSP Samples included in the distribution. David Parry has also written a nice tutorial to supplement this documentation.
| What is an XSP Page? |
An XSP page is a Cocoon XML document containing tag-based directives that specify how to generate dynamic content at request time. Upon Cocoon processing, these directives are replaced by generated content so that the resulting, augmented XML document can be subject to further processing (typically an XSLT transformation) XSP pages are transformed into Cocoon producers, typically as Java classes, though any scripting language for which a Java-based processor exists could also be used. Directives can be either XSP built-in processing tags or user-defined library tags. XSP built-in tags are used to embed procedural logic, substitute expressions and dynamically build XML nodes. User-defined library tags act as templates that dictate how program code is generated from information encoded in each dynamic tag.
| A Simple Example: Embedded Logic |
In the following XSP page, the Java language is used to generate some dynamic content:
    <?xml version="1.0"?>
    <?cocoon-process type="xsp"?>
    <?cocoon-process type="xslt"?>
    <?xml-stylesheet href="sample.xsl" type="text/xsl"?>

    <xsp:page language="java" xmlns:xsp="http://www.apache.org/1999/XSP/Core">
      <page title="Time of Day">

        <xsp:logic>
          // Define a variable to hold the time of day
          Date now = new Date();
        </xsp:logic>

        <p>
          To the best of my knowledge, it's now
          <!-- Substitute time of day here -->
          <xsp:expr>now</xsp:expr>
        </p>
      </page>
    </xsp:page>
Upon Cocoon processing, this page should yield something like:
    <html>
    <head><title>Time of Day</title></head>
    <body>
      <h3 style="color: navy; text-align: center">Time of Day</h3>
      <p>It's now Thu Dec 23 20:11:18 PST 1999</p>
    </body>
    </html>
Let's dissect this example:
| The XSP Processing Instruction |
Two processing instructions are used in our example to control how Cocoon processes its XML content: `<?cocoon-process type="xsp"?>` instructs Cocoon to generate a program (a producer) that rebuilds the static portions of the document as augmented by the embedded logic `<?cocoon-process type="xslt"?>` `<?xml-stylesheet href="sample.xsl" type="text/xsl"?>` instructs Cocoon to apply the sample.xsl XSLT stylesheet to the XML tree resulting from executing the generated XSP producer program Note that it is not mandatory for an XSP page to be further processed by XSLT. Any (or none) other Cocoon XML processing step(s) may be subsequently applied depending on application requeriments.
| The XSP Namespace |
All XSP directives belong to the `<xsp:>` namespace. Also, XSP pages are required to have an `<xsp:page>` root element:
    <xsp:page language="java" xmlns:xsp="http://www.apache.org/1999/XSP/Core">
The `<xsp:page>` root element can specify the programming language used in the XSP page by means of the `language` attribute. If this attribute is omitted, java will be used. The root element must also specify the XSP namespace URL by means of the `xmlns:` attribute. As will be explained later, this attribute is also used to introduce user-supplied tag libraries. Finaly, the XSP root element must contain only one non-XSP nested element. Such element (`<page>` in the above example) will become the root element of the generated document.
| The Logic Tags |
In our example, the "user" root element contains:
    <page title="Time of Day">
        <xsp:logic>
          // Define a variable to hold the time of day
          Date now = new Date();
        </xsp:logic>
        <p>
          To the best of my knowledge, it's now
          <!-- Substitute time of day here -->
          <xsp:expr>now</xsp:expr>
        </p>
      </page>
Here, we use the two essential XSP logic tags: `<xsp:logic>`. This tag encloses developer-supplied program logic. Such logic will be transcribed verbatim into the generated Cocoon producer. `<xsp:expr>`. This tag evaluates a program expression and substitutes its value as a `Text` DOM node in the resulting document. In the fragment:
    <xsp:logic>
      // Define a variable to hold the time of day
      Date now = new Date();
    </xsp:logic>
a new variable (`now`) is declared that can be subsequently referenced anywhere in the remaining page content. Note that, in this particular example, it's not necessary to fully specify the Java type (`java.util.Date`) because XSP automatically generates `import` statements for the most commonly used Java libraries. In the fragment:
    <!-- Substitute time of day here -->
    <xsp:expr>now</xsp:expr>
the variable `now` is referenced so that its value is inlined in the resulting XML document as a `Text` node. Note also that it's not necessary to explicitly cast `now` to `String`. `<xsp:expr>` takes care of converting all Java types so that values are properly converted depending on context. In general, `<xsp:expr>` values are inlined according to the following rules: Primitive Java types (`int`, `long`, etc) are converted to their `String` representation and wrapped as `Text` `Node`s (which is to say, instances of all subclasses of `org.w3c.dom.Node`) are left as-is if their owner document is the same as the XSP output document, or cloned if not (in order to change the owner document). Efficiency gains can be made by always creating Nodes to be inserted with `document` as their owner document (although this is probably what you are doing anyway!). NOTE: You should not insert objects whose type is equal to `Node` because this is considered an abstract class - instead, use Element to insert one element at a time, or DocumentFragment to insert multiple elements at the same time. (Here "one element" and "multiple elements" refers to elements at the top level, so <a><b/></a> still counts as "one element" in this context, but <a/><b/> counts as two.) All other Java objects are wrapped as follows: `String`s are directly wrapped as `Text`. WARNING: This means that if you try to insert some XML as a `String` using `<xsp:expr>`, it will not work! Instead, you will need to either use `<util:include-expr>`, or build `XMLFragment`s or `org.w3c.dom.Node`s instead - please read the FAQ on this before asking questions about it. Arrays are wrapped as `DocumentFragment`s and each element is recursively applied these same transformation rules. Non-string objects are converted to `String` (by means of their `toString` method) and subsquently wrapped as `Text`. Note that some types may not provide a suitable string representation, so they may require a more elaborate, explicit expression. A nice XSP feature (not present in other server pages technologies) is that the `<xsp:logic>` element allows for the arbitrary nesting of other markup without the need to "prematurely" close it. For example:
    <table>
      <xsp:logic>
        for (int i = 0; i &lt; countries.length; i++) {
          <tr>
            <td>
              <xsp:expr>countries[i].getName()</xsp:expr>
            </td>
            <td>
              <xsp:expr>countries[i].getCurrency()</xsp:expr>
            </td>
          </tr>
        }
      </xsp:logic>
    </table>
If such nesting was not allowed, the purely programmatic alternative would be considerably more complex:
    <table>
      <xsp:logic>
        for (int i = 0; i &lt; countries.length; i++) {
          // <tr>
          xspParentNode = xspCurrentNode;
          xspNodeStack.push(xspParentNode);
          xspCurrentNode = document.createElement("tr");
          xspParentNode.appendChild(xspCurrentNode);

          // <td>name</td>
          xspParentNode = xspCurrentNode;
          xspNodeStack.push(xspParentNode);
          xspCurrentNode = document.createElement("td");
          xspParentNode.appendChild(xspCurrentNode);
          xspCurrentNode.appendChild(
            document.createTextNode(countries[i].getName())
          );
          xspCurrentNode = (Node) xspNodeStack.pop();

          // <td>currency</td>
          xspParentNode = xspCurrentNode;
          xspNodeStack.push(xspParentNode);
          xspCurrentNode = document.createElement("td");
          xspParentNode.appendChild(xspCurrentNode);
          xspCurrentNode.appendChild(
            document.createTextNode(countries[i].getCurrency())
          );
          xspCurrentNode = (Node) xspNodeStack.pop();

          // </tr>
          xspCurrentNode = (Node) xspNodeStack.pop();
        }
      </xsp:logic>
    </table>
Note, however, that it is not allowed to nest `<xsp:expr>` tags directly inside `<xsp:logic>`. For an expression to be inlined inside an `<xsp:logic>` element, it must be escaped by surrounding it with an `<xsp:content>` tag. Example:
    <xsp:logic>
      for (int i = 0; i &lt; parameterValues.length; i++) {
        <xsp:content>
          <xsp:expr>parameterValues[i]</xsp:expr>
        </xsp:content>
        <br/>
      }
    </xsp:logic>
The observant reader may have noticed a rather unpleasant feature in the above code: the less-than sign (`<`) must be represented as `&lt;`! This is an undesirable (but unavoidable) consequence of the `<` and `&` characters being special to XML parsers. A workaround is to escape code chunks contaning the less-than (`<`) and ampersand (`&`) characters as CDATA sections:
    <table>
      <xsp:logic><![CDATA[
        for (int i = 0; i < countries.length; i++)]]>
          <tr>
           . . .
          </tr>
        }
      </table>
    </xsp:logic>
Caution must be exercised, though, to avoid enclosing static markup inside the `<![CDATA]]>` section, as this will result in syntax errors upon compiling the generated Cocoon producer!
| Another Example: Tag Libraries |
In the following example, a developer-supplied tag library is used instead of embedding procedural code:
    <?xml version="1.0"?>
    <?cocoon-process type="xsp"?>
    <?cocoon-process type="xslt"?>
    <?xml-stylesheet href="sample.xsl" type="text/xsl"?>

    <xsp:page
      language="java"
      xmlns:xsp="http://www.apache.org/1999/XSP/Core"
      xmlns:example="http://www.plenix.com/DTD/XSP/Example"
    >
      <page title="Time of Day">
        <p>
          To the best of my knowledge, it's now
          <!-- Substitute time of day here -->
          <example:time-of-day format="yy/MM/dd hh:mm:ss aa"/>
        </p>
      </page>
    </xsp:page>
Here, the web author is shielded from programming complexities at the expense of additional developer effort in devising and implementing a proper dynamic tagset. As mentioned early, this is the "ideal" XSP scenario: dynamic content generation requirements are identified before hand and represented in reusable tag libraries. Web authors can then focus on their their "true" purpose in life: producing content. XSP uses XSLT stylesheets for source code generation. Thus, each dynamic tag in a library is supported by an XSLT template containing the program logic to be generated. Upon execution, generated logic will yield the dynamic content encoded by its underlying dynamic tag. Without yet delving into the finer details of the XSP object model, let's see how the example tag library stylesheet looks like:
    <?xml version="1.0"?>
    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/XSL/Transform/1.0"
      xmlns:xsp="http://www.apache.org/1999/XSP/Core"
      xmlns:example="http://www.plenix.com/DTD/XSP/Example"
    >
      <xsl:template match="xsp:page">
        <xsp:page>
          <xsl:copy>
            <xsl:apply-templates select="@*"/>
          </xsl:copy>
          <xsp:structure>
            <xsp:include>java.util.Date</xsp:include>
            <xsp:include>java.text.SimpleDateFormat</xsp:include>
          </xsp:structure>
          <xsp:logic>
            /* "Example" Class Level Logic */
            private static String formatDate(Date date, String pattern) {
              if (pattern == null || pattern.length() == 0) {
                pattern = "yyyy/MM/dd hh:mm:ss aa";
              }
              return (new SimpleDateFormat(pattern)).format(date);
            }
          </xsp:logic>
          <xsl:apply-templates/>
        </xsp:page>
      </xsl:template>
      <xsl:template match="example:time-of-day">
        <xsp:expr>
          formatDate(new Date(), "<xsl:value-of select="@format"/>")
        </xsp:expr>
      </xsl:template>
      <xsl:template match="@*|node()" priority="-1">
        <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
Let's focus our attention on 4 key features of this library: Namespace Structure Class-level logic Tag code templates
| Library Namespace |
Each XSP library defines a separate XML namespace:
    xmlns:example="http://www.plenix.com/DTD/XSP/Example"
Thus, all dynamic tags should belong to the same namespace associated with their defining library
    <example:time-of-day format="hh:mm:ss"/>
While this discipline is not enforced by XSP, developers are strongly encouraged to follow this pattern because it prevents ambiguities and promotes document readability.
| Program Structure |
The `<xsp:structure>` section provides the context for program-level declarations such as the Java `import` directive.
    <xsp:structure>
      <xsp:include>java.util.Date</xsp:include>
      <xsp:include>java.text.SimpleDateFormat</xsp:include>
    </xsp:structure>
The `<xsp:structure>` tag may contain zero or more `<xsp:include>` directives, each specifying an external program module to be made available to the generated XSP program. Note that the exact semantics of this elments is language-dependent. For Java, it corresponds to an `import` statement. For Fesi Javascript, for example, it may be interpreted as a `load()` function call. In our example, we're importing the `java.util.Date` and `java.text.SimpleDateFormat` class definitions. In all honesty, though, including `java.util.Date` is redundant because XSP always imports `java.util.*`. It's included here only to emphasize that the example library depends on it. `java.text.SimpleDateFormat`, on the other hand, must be included, because it's not among XSP's "preferred" Java packages.
| Cache Control |
Also in the <xsp:structure> tag, a <util:cacheable/> tag may be defined. This empty tag simply allows the page to be cached. This should always be combined with a method declaration as follows:
            <xsp:logic>
              public boolean hasChanged (Object context) {
                // context is a HttpServletRequest
                return // whether the page has changed.
              }
            </xsp:logic>
Please read the guide to Cocoon caching for more information. See also the next section for details on declaring methods.
| Class-level logic |
In general, XSP class-level declarations (such as instance variables or methods) are defined by means of `<xsp:logic>` blocks placed outside the user root element. XSP libraries exploit this feature to declare class-level variables and methods used by code generated in reponse to the use of dynamic tags in XSP pages. In our example, the following method is used to generate a `String` representation of the current system time:
    <xsp:logic>
      /* "Example" Class Level Logic */
      private static String formatDate(Date date, String pattern) {
        if (pattern == null || pattern.length() == 0) {
          pattern = "yyyy/MM/dd hh:mm:ss aa";
        }
        return (new SimpleDateFormat(pattern)).format(date);
      }
    </xsp:logic>
Dynamic tag templates may then refer to this method.
| Tag Code template |
Finally, each dynamic tag must provide an associated XSLT template that dictates what source code must be generated whenever the tag is encountered in an XSP page. Note that the source code to be generated must be enclosed in either an `<xsp:expr>` or an `<xsp:logic>` element. This is so because these XSP tags will be later evaluated by the XSP built-in library (itself an XSLT stylesheet!)
    <xsl:template match="example:time-of-day">
      <xsp:expr>
        formatDate(new Date(), "<xsl:value-of select="@format"/>")
      </xsp:expr>
    </xsl:template>
In this example, each reference to a `<example:time-of-day>` tag will be replaced by a corresponding `<xsp:expr>` "call". Thus, if an XSP page using the example library contains:
    <example:time-of-day format="hh:mm:ss"/>
XSP will expand this reference to:
    <xsp:expr>formatDate(new Date(), "hh:mm:ss")</xsp:expr>
during library processing. Upon source program generation this directive will be finally expanded to:
    xspCurrentNode.appendChild(
      xspExpr(
        formatDate(new Date(), "hh:mm:ss"),
        document
      )
    );
where the `xspExpr()` built-in method is overloaded to wrap all possible Java types as a `Text` Node. Finicky developers may prefer to map dynamic tags to bean method calls, as opposed to inlining "raw" Java code. While some may consider this a matter of taste, using bean properties and methods is certainly advisable because it isolates library code from implementation details. This would allow, for instance, for a complex Enterprise Java Bean to be modified without impacting existing XSP pages.
| The XSP Tagset |
| Tag List |
`<xsp:page>` This element is the root of all XSP pages and specifies the scripting language and the tag libraries used by a particular XSP page `<xsp:structure>` This top-level element encloses source program-level declarations such as `<xsp:include>` `<xsp:include>` This element is used to import external module definitions in a language-dependent way `<xsp:logic>` This element is used to embed procedural logic in an XSP page. Enclosed code is transcribed verbatim into the generated `XSPPage` producer. Other XSP or user markup may be nested inside this tag `<xsp:content>` This element is used to embed "regular" XML content inside an `<xsp:logic>` block so that no nested additional `<xsp:logic>` sections are required `<xsp:expr>` This element inlines a program expression as a `Text` node, except when used directly inside another `<xsp:>` element, where it is substituted as an expression, not a node. If you want to substitute an `<xsp:expr>` tag as a node inside another XSP tag, you must enclose it in an `<xsp:content>` element. `<xsp:element>` This tag is used to dynamically build an element when its attribute values are not known at compile time `<xsp:attribute>` This element is used to dynamically provide attribute values for a given element (which can be specified statically as markup or dynamically by means of `<xsp:element>`). This tag is typically used in conjunction with `<xsp:expr>`, where the substituted expression is always cast to `String` `<xsp:pi>` This element is used to dynamically create a processing instruction. `<xsp:comment>` This element is used to dynamically create an XML comment.
| Notes on Tag Usage |
| <xsp:page> |
The `<xsp:page>` root element has an optional `language` attribute that defaults to java. Other scripting languages (both interpreted and compiled) will be supported in the near future. The `<xsp:page>` root element requires one or more `xmlns:` attributes specifying tag libraries. These attributes specify each tag library's DTD location as a URL. At least the built-in XSP (currently, `xmlns:xsp="http://www.apache.org/1999/XSP/Core"`) library must be specified. The order in which `xmlns:` attributes appear dictates library processing order. The XSP built-in library, though, is always applied last, regardless of its position in the `xmlns:` attribute list. The `<xsp:page>` element can only have one user element. This element becomes the root of the generated XML document. Only the following node types are valid as direct descendants of the `<xsp:page>` root element: Zero or more `<xsp:structure>` elements. Zero or more `<xsp:logic>` elements. The user root element: as in Highlander, there can be only one. `<xsp:logic>` blocks that are direct descendants of the `<xsp:page>` root element (i. e., placed outside the user root element) are generated as class-level logic. This is used for declaring class fields and methods. Top-level processing instructions (other than `<?cocoon-process type="xsp"?>`) are preserved in the generated XML document. This is convenient, for example, for subsequent XSLT processing. Some Java packages are always imported by default. As such, they do not require explicit `<xsp:include>` directives. These packages are: `java.io.*;` `java.util.*;` `org.w3c.dom.*;` `org.xml.sax.*;` `javax.servlet.*;` `javax.servlet.http.*;` `org.apache.cocoon.parser.*;` `org.apache.cocoon.producer.*;` `org.apache.cocoon.framework.*;` `org.apache.cocoon.processor.xsp.*;`
| <xsp:logic> and <xsp:content> |
`<xsp:content>` can be used inside `<xsp:logic>` blocks to avoid the recursive nesting of additional `<xsp:logic>` elements. Thus, the following XSP fragment (which contains nested `<xsp:logic>` blocks):
    . . .
      <p>
        Good
          <xsp:logic>
            String timeOfDay = (new SimpleDateFormat("aa")).format(new Date());
            if (timeOfDay.equals("AM")) {
          </xsp:logic>
        Morning
          <xsp:logic>
            } else {
          </xsp:logic>
        Afternoon
          <xsp:logic>
            }
          </xsp:logic>!
      </p>
      . . .
can be rewritten as:
    . . .
      <p>
        Good
        <xsp:logic>
          String timeOfDay = (new SimpleDateFormat("aa")).format(new Date());

          if (timeOfDay.equals("AM")) {
            <xsp:content>Morning</xsp:content>
          } else {
            <xsp:content>Afternoon</xsp:content>
          }
        </xsp:logic>!
      </p>
      . . .
Note that this does not work in cases where a non-empty element would be "truncated" by an interspersed `<xsp:logic>` block. Thus, the following example cannot be reduced by means of `<xsp:content>`
    <xsp:logic>
        Enumeration enum = request.getParameterNames();
        while (enum.hasMoreElements()) {
          String parameterName = (String) enum.nextElement();
          String[] parameterValues =
            request.getParameterValues(parameterName);

          <tr>
            <td valign="top">
              <xsp:expr>parameterName</xsp:expr>
            </td>

            <!-- Trouble here -->
            <td>

            <xsp:logic>
              for (int i = 0; i &lt; parameterValues.length; i++) {
                <xsp:content>
                  <xsp:expr>parameterValues[i]</xsp:expr>
                </xsp:content>
                <br/>
              }
            </xsp:logic>

            </td>
            <!-- End trouble -->

          </tr>
        }
      </xsp:logic>
because the second `<td>` would be "cut short" by any intervening `<xsp:content>`.
| <xsp:element> and <xsp:attribute> |
The `<xsp:element>` tag (which requires a `name` attribute) is used in those cases where the element name is known at compile time, but its attribute values are not. For example:
    <xsp:logic>
      for (int i = 0; i &lt; languages.length; i++) {
       <tr>
         <td>
             <img>
               <xsp:attribute name="src">img/
                 <xsp:expr>languages[i].getCode()</xsp:expr>
               .gif</xsp:attribute>
             </img>
         </td>
         <td>
             <xsp:expr>languages[i].getName()</xsp:expr>
         </td>
       </tr>
      }
    </xsp:logic>
Only XML text and `<xsp:expr>` are valid inside an `<xsp:attribute>` element. Note that whitespace is significant inside `<xsp:attribute>` so indenting `<xsp:attribute>` content may result in spurious space being generated. Unless you really need to generate spaces as part of the attribute value, resist the temptation to write something like:
    <img>
      <xsp:attribute name="src">
        img/
        <xsp:expr>
          languages[i].getCode()
        </xsp:expr>
        .gif
      </xsp:attribute>
    </img>
Finally, if an element name is not known at compile time, you must programatically create it:
    <xsp:logic>
      String tagName = null;
      if (ordered) {
        tagName = "ol";
      } else {
        tagName = "ul";
      }
      xspParentElement = xspCurrentElement;
      xspNodeStack.push(xspParentElement);
      xspCurrentElement = document.createElement(tagName);
    </xsp:logic>

      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>

    <xsp:logic>
      xspCurrentElement = (Node) xspNodeStack.pop();
    </xsp:logic>
This may be alleviated in future XSP versions by introducing an idiom similar to the XSLT way of substituting dynamic expressions inside attributes values:
    <xsp:element name='{ordered ? "ol" : "ul"}'>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </xsp:element>
| <xsp:pi> |
The `<xsp:pi>` element requires a `target` attribute specifying the processing instruction name. `<xsp:expr>` is supported within xsp:pi - for example:
    <xsp:pi target="xml-stylesheet">
      href="<xsp:expr>request.getQueryString()</xsp:expr>"
      type="text/xsl"
    </xsp:pi>
In the future, `<xsp:pi>` may be renamed to `<xsp:processing-instruction>` to achieve compatibility with XSLT.
| <xsp:comment> |
Note that dynamically created comments (`<xsp:comment>`) may be removed by subsequent XSLT processing.
| The XSP Object Model |
| Processors and Producers |
A processor is a Cocoon Java type that takes a DOM tree as input and produces another (possibly modified) DOM tree as output. This concept is similar to that of a Unix "filter" in a command pipeline. The XSP engine is implemented as a Cocooon processor that accepts an XSP page as input. The first time a given XSP page is processed, it is translated into an equivalent source program which is then compiled, loaded and executed. Subsequent requests for the same XSP page result in the execution of the generated program. As you may expect, the output DOM tree returned by the XSP engine processor is actually built by the generated program. XSP pages are compiled into Cocoon producers. A producer is a Cocoon Java type normally used to "feed" the initial XML content to the Cocoon processing pipeline. Thus, for example, when Cocoon serves a static, "regular" XML document, file contents are actually delivered by Cocoon's built-in `FileProducer`. Whereas other related server pages technologies (such as JSP) generate servlets, XSP generates producers instead. This is so because, among other reasons, the servlet model does not yet provide a mechanism for portably and efficiently post-processing XML content.
| XSP Built-in Objects |
XSP defines an abstract producer (`XSPPage`) as the base class for generated programs. This class exposes a simple object model that can be easily used by XSP developers to programmatically control how XML content is generated. The following objects are accesible inside an XSP page: `request`. A Cocoon-supplied wrapper to the standard `HttpServletRequest` object. This wrapper provides all the functionality defined for its JSDK interface counterpart. This object is typically used to retrieve Http form parameters as well as to get header and cookie information. `response`. A Cocoon-supplied wrapper to the standard `HttpServletResponse` object. This wrapper provides most of the functionality defined for its JSDK interface counterpart, except for access to the `ServletOutputStream`object and its associated writer. This restriction is necessary to ensure consistent Cocoon servlet output and does not impose any limitation to XML processing. Other suitable, non-output operations (such as setting headers, cookies or content types) are allowed `session`. The standard `HttpSession` servlet object. This object is typically used to store data associated with a user HTTP session `servletContext`. The standard `ServletContext` object. This object is typically used to store application-level data by means of its `setAttribute` and `getAttribute` methods. Other uses include determining the real path of a URL as dictated by the underlying web server virtual directory structure. Note that the application-level data sharing capabilities offered by this object are available only for JSDK version 2.2 and higher. To circumvent this for JSDK prior to 2.2, use the `xspGlobal` object (explained below) `document`. An XSP-supplied `org.w3c.Document` object. Initially empty, this object is populated by the generated `XSPPage` producer and is typically used as a node factory (`document.createElement()`, `document.createProcessingInstruction()`, etc) `xspGlobal`. An XSP-supplied global dictionary offering the same `setAttribute` and `getAttribute` services supported by the standard `ServletContext` object. This surrogate exists only to provide application-level data sharing for older servlet engines (prior to 2.2). Note that, while providing a means for application-level data sharing for older servlet engines, such global data cannot be shared with non-Cocoon servlets or JSP pages. For this purpose, use the standard `servletContext` object. `xspGlobal` may be deprecated in future XSP versions `xspNodeStack`. A `java.util.Stack` used to control element nesting in the XSP page `Document` object. Extreme caution must be exercised in using this object as all DOM manipulations take effect on its top element. `xspCurrentNode`. An `org.w3c.Node` object corresponding to the node being currently populated `xspParentNode`. An `org.w3c.Node` object corresponding to the parent of the node being currently populated. This object is normally the top element of the `xspNodeStack` `xspParser`. A Cocoon-supplied DOM parser which may be used to create new documents and parse external XML documents In addition to the above objects, the `XSPPage` contains an `xspExpr()` method than can be used to wrap any Java value as an `org.w3c.Text` object. Example:
    xspCurrentElement.appendChild(
      document.createTextNode("It's now ")
    );
    xspCurrentElement.appendChild(
      xspExpr(new Date())
    );
| The XSPUtil Class |
In addition to the above infrastructure objects and methods, XSP provides a utility class, called `XSPUtil`, which is automatically imported, offering a number of DOM, HTTP and file manipulation services implemented as public static methods:
| DOM Utility Methods |
`Node cloneNode(Node node, Document factory)`. This method performs a deep copy of its `node` argument using the `factory` document as the creator for the copied nodes. This is typically used to embed external XML documents into the XSP page `document` object. This is required because DOM Level 1 parsers do not allow for a node to be appended as child to another node if the two belong to different document instances `String toMarkup(Node node)`. This method generates an indented String representation of its `node` argument. This is typically used to embed a textual, non-DOM representation of external XML files as well as for debugging purposes
| HTTP Utility Methods |
`String encodeMarkup(String string)`. This method scans its `string` argument replacing occurrences of markup delimiters as follows: 1) `<` is replaced by `&lt;` 2) `>` is replaced by `&gt;` 3) `&` is replaced by `&amp;` `String formEncode(String text)`. This method converts its `text` argument to x-www-form-urlencode format, as required by HTTP form query strings. This method is actually a replacement for `java.net.URLEncoder.encode` (introduced in Java2) and exists solely to provide this functionality for JDK1.1. `String formDecode(String text)`. This method converts its `text` argument from x-www-form-urlencode format to a `String` representation. This method is actually a replacement for `java.net.URLDecoder.decode` (introduced in Java2) and exists solely to provide this functionality for JDK1.1
| File Utility Methods |
`String pathComponent(String filename)`. This method interprets its `filename` argument as a file name and removes the last component to yield only the directory path information. This conversion is performed in an operating system-independent manner `String fileComponent(String filename)`. This method interprets its `filename` argument as a file name and removes the leading path component to yield only the file name portion, including the file name extension, if any. This conversion is performed in an operating system-independent manner `String baseName(String filename)`. This method interprets its `filename` argument as a file name and removes the leading path component to yield only the base file name excluding the last dot file extension, if any. This conversion is performed in an operating system-independent manner `String baseName(String filename, String suffix)`. This method interprets its `filename` argument as a file name and removes the leading path component to yield only the base file name excluding the last occurerence of the extension given by its `suffix` argument. This conversion is performed in an operating system-independent manner `String normalizedBaseName(String filename)`. This method interprets its `filename` argument as a file name and removes the leading path component to yield only the base file name excluding the last dot file extension, if any. The resulting filename is then scanned for non-alphanumeric characters which are replaced by underscore (`_`). An underscore is also preprended to each directory component. This is used to map file names to valid Java identifiers. This conversion is performed in an operating system-independent manner `String relativeFilename(String filename, HttpServletRequest request, ServletContext context)`. This method is used to build a fully qualified pathname for a `filename` relative to the `request` URI. This is typically used to open operating system files given a name relative to the request's virtual path `String relativeFilename(String filename, HttpServletRequest request)`. This method is used to build a fully qualified pathname for a `filename` relative to the `request` URI. This is typically used to open operating system files given a name relative to the request's virtual path. This variant depends on the deprecated `HttpServletRequest.getRealPath` method and exists only for compatibility with older JSDK's in which the `ServletContext` object did not provide a `getRealPath()` method
| String Utility Methods |
`String[] split(String line)`. This method converts its `line` string argument to a `String` array using whitespace (blanks, tabs, carriage returns and newlines) as field separators `String[] split(String line, String delimiter)`. This method converts its `line` string argument to a `String` array using the characters in its `delimiter` argument as field separators `boolean isAlphaNumeric(char c)`. This method tests its `c` argument to assert whether it is an underscore, a lowercase or uppercase letter or a digit
| Other Scripting Languages |
XSP has been designed to support other scripting languages, in addition to Java. In principle, any programming language for which a Java-based interpreter exists could be used to script XSP pages. In general, languages supporting compilation to bytecodes, such as Java itself, Netscape's Rhino Javascript or IBM's NetRexx, perform significantly better than interpreted languages like FESI Javascript or WebL. Interpreted languages, however, are expected to play an important role in XSP scripting. This is so because (in addition to their typical ease of use) more and more field-specialized languages are being developed for the JVM. Such specialized scripting languages usually offer more expressive power and conciseness than strictly object-oriented languages. For a fairly complete list of such languages see Programming Languages for the Java Virtual Machine. Until recently, Java lacked a well-defined scripting architecture that allowed applications to incorporate scripting easily. IBM's Bean Scripting Framework (BSF) is an Alphaworks project providing such architecture. BSF supports a growing number of scripting languages including Rhino, NetRexx, Jacl and JPython. On the Windows platform, BSF also supports JScript, VBScript, and PerlScript. Currently, XSP only supports Java as a scripting language, though its design allows for an easy integration of other languages. In the near future, BSF will be integrated to XSP's own language abstraction mechanism so that most (if not all) of the above mentioned languages may become available for XSP scripting. XSP tag libraries are language-dependent. Thus, the addition of a new language involves (at the very least) porting the XSP built-in libraries. An XSP library is composed of a code-generation XSLT sylesheet and an optional library preprocessor class. A library's code-generation stylesheet is simply a "regular" XSLT stylesheet responsible for translating user-defined dynamic tags into equivalent XSP tags for a given scripting language (sometimes called logicsheet). While a preprocessor is an optional library Java class used to augment an XSP page DOM tree prior to applying the library code-generation stylesheet. Library preprocessors may be language-dependent. Early experience suggests, though, that the same preprocessor class will be typically shared by different languages for the same dynamic tagset. XSLT extension functions and extension elements may replace library preprocessors in the future. In this case, all code-generation logic would reside in the library's stylesheet. At this early development stage, we still don't know how the implementation will evolve and we look forward for public feedback before going any further along with the implementation details.
| Acknowledgements |
This initial implementation of XSP has been developed by Exolab and is being donated to the Apache project as part of Exoffice's commitment to the open source movement. Special thanks must be given to Ismael Ghalimi for sponsoring and supporting XSP development. Last, but not least, cheers to Stefano Mazzocchi, founder and leader of the Cocoon project and original author of the XSP specification. Thanks!!!

Copyright © 1999-2001 The Apache Software Foundation. All Rights Reserved.