I finally found some time to finish a first version of pipe-aware selection.
It has some rough edges and there is no caching yet, but as I think it will
be useful for the current form handling and validation development, I would
like to share my results this far. The example is fairly pointless, I will
try to build something better as soon as I have cached up with the technical
details in the Cocoon input form discussion.

/Daniel Fagerstrom

The README file:
----------------

Pipe-aware selectors
====================

This contribution makes it possible to have selectors in a pipeline
that reacts on the output from the previous step in the pipeline.

Motivation
----------

See
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=101494021330277&w=2
and the rest of the discussions in the threads:
XML-Based Selection (Redirect Serializer?)
http://marc.theaimsgroup.com/?t=101480865500001&r=1&w=2
and Pipe-aware Selectors
http://marc.theaimsgroup.com/?t=101536052100002&r=1&w=2
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=101554683923592&w=2
for motivation. There have also been some discussion about pipe aware
selection in the current threads about form handling and validation.

The main idea is that if the input to Cocoon is XML or is transformed
to XML in an early step, it is useful to be able to make choices
dependent on this input. The standard selector model in Cocoon does
not allow for this.

Hypothetical usage example
--------------------------

<map:match pattern="userDataInsert.xml">
  <map:generate type="stream"/>
  <map:transform src="userData.xsd" type="validator"/>
  <map:select type="xpath">
    <map:when test="/*/@fatal-error">
      <map:transform src="structureErrors.xsl"/>
    </map:when>
    <map:when test="/*/@field-error">
      <map:transform src="userDataForm.xsl"/>
    </map:when>
    <map:otherwise>
      <map:transform type="file-writer" dest="userData.xml"/>
      <map:select type="xpath">
        <map:when test="/result/file-writen='true'">
          <map:transform src="reportInsertResult.xsl"/>
        </map:when>
        <map:otherwise>
          <map:transform src="reportInsertError.xsl"/>
        </map:otherwise>
      </map:select>
    </map:otherwise>
  </map:select>
  <map:serialize/>
</map:match>

In this example the yet to be implemented "validator transformer"
annotates invalid input elements with error describing
attributes. These annotated input is feed back to "userDataForm.xsl",
that create a partially filled in form with appropriate error messages.

Design
------

Pipe aware selection is only implemented for the TreeProcessor.  To
make a selector pipe aware it must implement the marker interface
PipeAware. In SelectNode (that performs selection in the
TreeProcessor) non-pipe aware selectors are handled exactly as
before. For PipeAware selectors the following happen:

* The current EventPipeline is processed and the result is put as a
DOM-tree in an objectModel parameter: "pipeline-result".
* A new EventPipeline is created with a special DOMGenerator as
generator. The DOMGenerator streams the DOM-tree in the objectModel.
* The SelectNode proceeds as for ordinary selection, but the PipeAware
Selector, can e.g. apply XPaths on the DOM-tree in the objectModel.

Caching
-------

Caching is yet to be implemented. The EventPipeline before the
selector will be cashed according to the ordinary scheme. The
pipeline that starts with the DOMGenerator would be cashable if the
DOMGenerator was cashable, which could be achieved by calculating a
CacheKey from the DOM-tree. This scheme seem however unnecessarily
inefficient as the selection has to be recalculated even if it is in
principle determined from the previous pipeline.
I need some more thinking about this, I would appreciate any input.

Running the example
------------------

Apply the patch. Copy the example directory to the mount directory.
Test:
http://localhost:8080/cocoon/mount/pipeSelector/test.html?myparam=a
and
http://localhost:8080/cocoon/mount/pipeSelector/test.html

The example does not do anything useful at all it just tests the
functionality.

Implementation details
----------------------

I tried to minimize the changes to existing classes but I had add a
method to InvokeContext and of course some code to SelectNode in
the treeprocessor.

Classes:

SelectNode: added some functionality to handle PipeAware selectors.

InvokeContext: added the method resetPipelines()

PipeAware: marker interface.

DOMGenerator: streams the DOM-tree in the objectModel.

XPathSelector: an xpath is applied on the DOM-tree in the
objectModel. (BTW, I could not find any documentation about how
namespaces are handled in the XPathProcessor, any pointers?).

Todo
----

There are a lot of references to the variable "pipeline-result" in the
objectModel, this variable should be accessed through the
ObjectModelHelper. (I didn't want to change existing code if I could
avoid it).

In PipeSelectNode, DOMGenerator is supposed to be declared in the
sitemap under the name "dom-generator", this is a ugly hack, but the
only solution that I found that didn't required additions to the
EventPipeline interface.

Cachability!!!

Meaningful examples

Attachment: pipeSelector.tgz
Description: application/compressed

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to