cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Javier del Gesu <delgesu-coc...@thinknola.com>
Subject Re: EffectTransformer/WoodyTemplateTransformer
Date Tue, 14 Oct 2003 18:38:54 GMT
* Timothy Larson <timlarsonwork@yahoo.com> [2003-10-14 14:44]:

> I posted the source to two Java classes on my page on the wiki:
>   http://wiki.cocoondev.org/Wiki.jsp?page=TimLarson
> The first class, EffectTransformer, make writing transformers in Java
> much easier and cleaner, IMHO.  The second class, WoodyTemplateTransformer,
> is an example of its namesake rewritten to use the Effect transformer style.
> 
> Here is an explaination:
> 
> Stylesheets let the structure of your code reflect the structure of the
> data you are processing, making them relatively easy to understand.
> The downside to stylesheets is when you really need the support of a
> full programming language and when you need side effects such as looking
> up widgets or talking to a database.  Sure you can do it, but it just
> does not feel right and can require too much gymnastics.
> 
> To solve this we try writing transformers in Java, but end up with the
> logic for handling different elements mixed in the same startElement
> method, etc. and have to introduce multiple flag and status variables
> to keep track of the current state.  At least we gained a full programming
> language and the ability to have side effects.
> 
> The (side-) Effect transformer solves all of these issues.

> I will give more details and examples if anybody is interested.
> WDYT?

This is reassuring. I wrote something similiar to create a SAX
filter, where processing of diferent nodes is handled by different
objects.

The user implements this interface:

public interface ContentFilter {
    /* Called when this content filter is pushed onto the stack */
    public void start(FilterContext filterContext, SAXStartElementEvent event)
        throws SAXException;

    /* Called when this content filter is popped off the stack */
    public void end(FilterContext filterContext, SAXEndElementEvent event)
        throws SAXException;

    /* Handle a SAX events */
    public void startElement(FilterContext filterContext,
        SAXStartElementEvent event) throws SAXException;

    public void endElement(FilterContext filterContext,
        SAXEndElementEvent event) throws SAXException;

    public void characters(FilterContext filterContext,
        SAXCharacterEvent event) throws SAXException;
}

Rather than change content filters after each call, the content
filter handles decendant elements until it decides it wants to
swtich filters. The filter switch is performed by calling
FilterContext.startContentFilter(). 

The FilterContext interface:

public interface FilterContext {
    /* Push a new content filter onto the stack */
    public void startContentFilter(ContentFilter contentFilter)
        throws SAXException;

    /* Make note of something in this context */
    public void put(String key, Object value);

    /* Retrieve a note of something in this context */
    public Object get(String key);

    /* Find the filter context with a non-null value for key */ 
    public FilterContext find(String key);

    /* Retrieve the filter context parent */
    public FilterContext parent();
}

The FilterContext keeps track of state. ContentFilter imps put data
into the filter context. Decendants can search for values obtained
in the tree traversal with the find method. They can return values
to a parent context with filterContext.parent().put("key", value).

When FilterContext.startContentFilter() is called, the
ContentFilter.start() method is called. ContentFilter.end() is
called when the element of the current filter context ends.

The SAXEvent class acts as both an ecapsulation of a sax event, and
as an interface to the next ContentHandler in the filter chain.

public interface SAXEvent {
    /* Forward this event.  */
    public void forward() throws SAXException;

    /* Create create an attribute with the attributes of this event.  */
    public SAXAttributes createSAXAttributes();

    public SAXAttributes createSAXAttributes(Attributes attributes);

    /* Send a start element event to the next content handler in the
     * chain of content handlers */
    public void forwardStartElement(String uri, String localName,
        Attributes attributes) throws SAXException;

    public void forwardStartElement(String uri, String localName,
        String[] attributes) throws SAXException;

    public void forwardStartElement(String uri, String localName)
        throws SAXException;

    /* Send an end element event to the next content handler in the
     * chain of content handlers */
    public void forwardEndElement(String uri, String localName)
        throws SAXException;

    /* Send characters to the listening content handler */
    public void forwardCharacters(char[] characters, int start
         int length) throws SAXException;

    public void forwardCharacters(String characters)
        throws SAXException;

    /* Play a DOM document to the next content handler */
    public void forwardNode(Node node) throws SAXException;

    /* Namespace information */
    public Iterator getNamespaceURIs();

    public String getPrefix(String uri);
}

public interface SAXEndElementEvent extends SAXEvent {
    public String getURI();

    public String getLocalName();

    public String getQualifiedName();
}

That's what I got. I think it is good to know that we both hit upon
the same solution, using an object stack to gather state.

-- 
Javier del Gesu - delgesu@thinknola.com

Mime
View raw message