cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Daniel Fagerstrom <dani...@nada.kth.se>
Subject Re: Implementation of a tag attribute language
Date Sun, 05 Dec 2004 15:33:07 GMT
Jonas Ekstedt wrote:
> Hello
> 
> The recent discussions about tag attribute languages has been very
> interesting and enlightening.

Both by generating interesting ideas and illustraiting some interesting 
aspects of mail list social dynamics ;)

> To make it more concrete here are a few
> ideas on how to actually implement these concepts.
> 
> TALGenerator
> ------------
> * Extends the generator in the template block.
> * Does not support tag bundles (ie taglibs)
> * Only treats elements containing a tal:do attribute in a special way.
> 
> A new TALToken is introduced (for an introduction to tokens see
> http://www.mail-archive.com/dev@cocoon.apache.org/msg25040.html). Here's
> an example of how a TAL template is compiled:
> 
> <table>
>   <tr tal:do="forEach(listOfBeans)">
>     <td>${it.beanProperty1}</td>
>     <td>${it.beanProperty2}</td>
>   </tr>
> </table>
> 
> => (ignoring whitespace nodes) =>
> 
> PlainElementToken  localName="table"
> TALToken           localName="tr", do="forEach(listOfBeans)"
> PlainElementToken  localName="td"
> ExpressionToken    expression="it.beanProperty1"
> PlainElementToken  localName="td"
> ExpressionToken    expression="it.beanProperty2"

Something in that direction. I would prefer this:

PlainElementToken  localName="table"
TALToken           do="forEach(listOfBeans)"
PlainElementToken  localName="tr"
PlainElementToken  localName="td"
ExpressionToken    expression="it.beanProperty1"
PlainElementToken  localName="td"
ExpressionToken    expression="it.beanProperty2"

It gives the TALToken access to its enclosing element (with the tal:do 
attribute removed). It also generalizes to multiple directives in an 
natural way:

<tr tal:do="forEach(listOfBeans);if(...)">
...

=>

PlainElementToken  localName="table"
TALToken           do="forEach(listOfBeans)"
TALToken           do="if(...)"
PlainElementToken  localName="tr"
...

Where the "forEach" TALToken invoke the "if" TALToken while executing 
invokeBody, which in turn can invoke the "tr" PlainElementToken. The 
"getAttributes" method in the TALToken class just calls the 
"getAttributes" method in its child.

> 
> TALToken might look something like:
> 
> public class TALToken {
>   ...
> 
>   public void invoke(ScriptContext context) {
>     if (getDoCommand().equals("forEach")) {
> 
>       Iterator it = evaluateToIterator(getDoParameter(0));
>       while (it.hasNext()) {
>         context.getVariables().put("it", it.next());
>         context.getConsumer().startElement(uri, localName, qname, attrs)
>         invokeBody(context);
>         context.getConsumer().endElement(uri, localName, qname);
>       }
> 
>     } else if (getDoCommand().equals("if")) {
> 
>       boolean test = evaluateToBoolean(getDoParameter(0));
>       if (test) {
>         context.getConsumer().startElement(uri, localName, qname, attrs)
>         invokeBody(context);
>         context.getConsumer().endElement(uri, localName, qname);
>       }
> 
>     } else if (...) {
>       ...
>     }
>   }
> }

Yes, that will do it, but by separating the TAL handling and element 
handling we get rid of the calls to "startElement" and "endElement", 
that is done in the PlainElementToken handling.

By having a standardized way to pass arguments to both attribute and tag 
driven directives they can share implementation.

The directives should still IMO be implemented as separate classes. Then 
we can install them programatically in the TalTemplateGenerator and 
declare the class as final. In that way we protect the users when they 
become obsessed by self destructive thoughts and want to add their own 
directives ;)

> I think a TALGenerator that is limited in scope (ie only supports a
> few control structures like if, forEach etc) would be quite easy
> to implement if it is built on top of the current template block.

Certainly.

Do you have any suggestions about how to implement the directives parser?

BTW: I think that your implementation of the script and token structure 
is quite cool in the way that we get the tree structure nearly for free 
and it also seem quite space efficient. But on the other hand I believe 
that the explicit handling data structure implementation details spreads 
to much to other parts of the code. Which will make the implementation 
unecesarilly complex.

I would prefer to refactor the code so that element, attribute and 
character tokens are responsible for their children with methods like 
"addChild(...)", "addAttribute(...)", "getAttributeItterator()" etc. 
This can be implemented efficiently by e.g. using single linked lists of 
  tokens where each token has a reference to the next token.

We can squeze out the last few bits of space efficency later if needed, 
but at this stage in the project I think we should strive for simplicity.

WDYT, am I missing something? Do you have anything against if I refactor 
the code in the direction I described above?

/Daniel

Mime
View raw message