You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@velocity.apache.org by Attila Szegedi <sz...@freemail.hu> on 2001/07/26 10:52:52 UTC

Creative criticism on Anakia design

Hi all!

I've looked at Anakia, and while I find the overall idea neat, I'm quite
unsatisfied with the implementation.

Namely, the way Anakia deals with the JDOM document can hardly be named
object-oriented. It sticks all kinds of "tools" ($xmlout, $treewalk, $xpath,
$escape) into the context that can be applied to JDOM nodes. I feel that it
would be more natural to have the functionality of these objects
encapsulated in a class that wraps a list of JDOM nodes, so methods could be
called on them.

In the current design, to output the <title> elements of all chapters of a
book, you'd have to write:

  #set( $titles = $xpath.applyTo("book/chapter/title") )
  #foreach( $title in $titles )
    $xmlout.outputString($title)
  #end

Now, imagine you have a NodeList class that contains a java.util.List of
JDOM nodes internally, and it:
- has a "NodeList applyXPath(String xpath)" method that produces another
NodeList by applying an XPath to the current NodeList,
- has "String toString()" implemented such that it produces a valid XML
fragment (complete with proper escaping) consisting of JDOM nodes it
currently contains - this greatly simplifies writing XML-to-XML transforming
templates,
- has a "java.util.List getList()" method, so if you *really* have custom
processing needs, you can access the underlying nodes individually from the
template,
- has a "void setXMLOutputter(XMLOutputter xmlout)" method so you're in
control of how will toString() render the nodes.

Were $root such a NodeList instead of plainly a JDOM Element, the above
Velocity fragment could be rewritten as:

  $root.applyXPath("book/chapter/title")

Looks efficient, doesn't it? And it feels much more like being
object-oriented, IMHO. Note that this expression itself results in a
NodeList that can be assigned to a variable and further manipulated. The
reason above expression will produce the XML fragment consisting of title
nodes is that the NodeList's toString() is overridden to do so.

Imagine it's even performance optimized because:
- it doesn't parse the XPath expression every time, but uses a WeakHashMap
to cache already parsed XPath expressions - as long as the template uses the
same String object to call the applyXPath method (which I suspect it does)
this will work nicely.
- toString() uses a single StringWriter to output all nodes, whereas using
xmlout.outputString in a #foreach uses one StringWriter per node.

Finally, imagine that you need not imagine this class, as I already wrote it
and attached it to this letter.

This design makes $xmlout, $xpath, and $escape obsolete. $treewalk is
already needless as even in the current Anakia design

  $treewalk.allElements($element) <=> $xpath.applyTo(".//*", $element)

I hope you (the community) will like NodeList and consider redesigning
Anakia to use it and thus become more OO and intuitive. If so, let someone
commit it (I'm no committer, this is my first post - my first itch to
scratch in Velocity...) and do the required modifications in AnakiaTask
($root and $project should be NodeList instances).

Cheers,
  Attila.


Re: Creative criticism on Anakia design

Posted by piero de salvia <pi...@yahoo.com>.
To everybody who should not know who Attila is, he is
the one who created FreeMarker, which is still a very
serious contender to Velocity, at least until some
edges have been smoothed out, stuff like whitespace
handling and newlines in list definitions...

So, Attila, were you thinking about something like
this ?:

http://jaxen.org/

piero de salvia

--- Attila Szegedi <sz...@freemail.hu> wrote:
> Hi all!
> 
> I've looked at Anakia, and while I find the overall
> idea neat, I'm quite
> unsatisfied with the implementation.
> 
> Namely, the way Anakia deals with the JDOM document
> can hardly be named
> object-oriented. It sticks all kinds of "tools"
> ($xmlout, $treewalk, $xpath,
> $escape) into the context that can be applied to
> JDOM nodes. I feel that it
> would be more natural to have the functionality of
> these objects
> encapsulated in a class that wraps a list of JDOM
> nodes, so methods could be
> called on them.
> 
> In the current design, to output the <title>
> elements of all chapters of a
> book, you'd have to write:
> 
>   #set( $titles =
> $xpath.applyTo("book/chapter/title") )
>   #foreach( $title in $titles )
>     $xmlout.outputString($title)
>   #end
> 
> Now, imagine you have a NodeList class that contains
> a java.util.List of
> JDOM nodes internally, and it:
> - has a "NodeList applyXPath(String xpath)" method
> that produces another
> NodeList by applying an XPath to the current
> NodeList,
> - has "String toString()" implemented such that it
> produces a valid XML
> fragment (complete with proper escaping) consisting
> of JDOM nodes it
> currently contains - this greatly simplifies writing
> XML-to-XML transforming
> templates,
> - has a "java.util.List getList()" method, so if you
> *really* have custom
> processing needs, you can access the underlying
> nodes individually from the
> template,
> - has a "void setXMLOutputter(XMLOutputter xmlout)"
> method so you're in
> control of how will toString() render the nodes.
> 
> Were $root such a NodeList instead of plainly a JDOM
> Element, the above
> Velocity fragment could be rewritten as:
> 
>   $root.applyXPath("book/chapter/title")
> 
> Looks efficient, doesn't it? And it feels much more
> like being
> object-oriented, IMHO. Note that this expression
> itself results in a
> NodeList that can be assigned to a variable and
> further manipulated. The
> reason above expression will produce the XML
> fragment consisting of title
> nodes is that the NodeList's toString() is
> overridden to do so.
> 
> Imagine it's even performance optimized because:
> - it doesn't parse the XPath expression every time,
> but uses a WeakHashMap
> to cache already parsed XPath expressions - as long
> as the template uses the
> same String object to call the applyXPath method
> (which I suspect it does)
> this will work nicely.
> - toString() uses a single StringWriter to output
> all nodes, whereas using
> xmlout.outputString in a #foreach uses one
> StringWriter per node.
> 
> Finally, imagine that you need not imagine this
> class, as I already wrote it
> and attached it to this letter.
> 
> This design makes $xmlout, $xpath, and $escape
> obsolete. $treewalk is
> already needless as even in the current Anakia
> design
> 
>   $treewalk.allElements($element) <=>
> $xpath.applyTo(".//*", $element)
> 
> I hope you (the community) will like NodeList and
> consider redesigning
> Anakia to use it and thus become more OO and
> intuitive. If so, let someone
> commit it (I'm no committer, this is my first post -
> my first itch to
> scratch in Velocity...) and do the required
> modifications in AnakiaTask
> ($root and $project should be NodeList instances).
> 
> Cheers,
>   Attila.
> 
> > package org.apache.velocity.anakia;
> 
> /*
>  * The Apache Software License, Version 1.1
>  *
>  * Copyright (c) 2001 The Apache Software
> Foundation.  All rights
>  * reserved.
>  *
>  * Redistribution and use in source and binary
> forms, with or without
>  * modification, are permitted provided that the
> following conditions
>  * are met:
>  *
>  * 1. Redistributions of source code must retain the
> above copyright
>  *    notice, this list of conditions and the
> following disclaimer.
>  *
>  * 2. Redistributions in binary form must reproduce
> the above copyright
>  *    notice, this list of conditions and the
> following disclaimer in
>  *    the documentation and/or other materials
> provided with the
>  *    distribution.
>  *
>  * 3. The end-user documentation included with the
> redistribution, if
>  *    any, must include the following
> acknowlegement:
>  *       "This product includes software developed
> by the
>  *        Apache Software Foundation
> (http://www.apache.org/)."
>  *    Alternately, this acknowlegement may appear in
> the software itself,
>  *    if and wherever such third-party
> acknowlegements normally appear.
>  *
>  * 4. The names "The Jakarta Project", "Velocity",
> and "Apache Software
>  *    Foundation" must not be used to endorse or
> promote products derived
>  *    from this software without prior written
> permission. For written
>  *    permission, please contact apache@apache.org.
>  *
>  * 5. Products derived from this software may not be
> called "Apache"
>  *    nor may "Apache" appear in their names without
> prior written
>  *    permission of the Apache Group.
>  *
>  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY
> EXPRESSED OR IMPLIED
>  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> IMPLIED WARRANTIES
>  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE ARE
>  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE
> SOFTWARE FOUNDATION OR
>  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
> INDIRECT, INCIDENTAL,
>  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> (INCLUDING, BUT NOT
>  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> SERVICES; LOSS OF
>  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> HOWEVER CAUSED AND
>  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT LIABILITY,
>  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> ARISING IN ANY WAY OUT
>  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
> THE POSSIBILITY OF
>  * SUCH DAMAGE.
>  *
>
====================================================================
>  *
>  * This software consists of voluntary contributions
> made by many
>  * individuals on behalf of the Apache Software
> Foundation.  For more
>  * information on the Apache Software Foundation,
> please see
>  * <http://www.apache.org/>.
>  */
> 
> import com.werken.xpath.XPath;
> import java.io.Writer;
> import java.io.IOException;
> import java.util.ArrayList;
> import java.util.Collections;
> import java.util.Iterator;
> import java.util.List;
> import java.util.WeakHashMap;
> import java.util.Map;
> import org.jdom.*;
> import org.jdom.output.*;
> 
> /**
>  * Provides a class for wrapping a list of JDOM
> objects primarily for use in template
>  * engines and other kinds of text transformation
> tools.
>  * It has a {@link #toString()} method that will
> output the serialized form of the
>  * nodes it contains - again focusing on template
> engine usage, as well as the
>  * {@link #applyXPath(String)} method that helps
> selecting a different set of nodes
>  * starting from the nodes in this list. 
>  * The order of nodes in a NodeList returned through
> method invocations on another 
>  * NodeList is the order of evaluation of the method
> on each node from left to right.
>  * Evaluation of the method on a single node always
> yields the results in serialization
>  * order (that of the document preorder traversal),
> even for uptree traversals
>  * (i.e. getAncestor() returns a list with root
> element first). As a consequence, if 
>  * this node list's nodes are listed in
> serialization order, applying any of the 
>  * methods will produce a node list that is also
> serialization-ordered. As a special 
>  * case, all node lists that are directly or
> indirectly generated from a single 
>  * Document or Element node through repeated
> invocations of methods will be 
>  * serialization-ordered.
>  * @author Attila Szegedi, szegedia@freemail.hu
>  * @version 1.0
>  */
> public class NodeList
> {
>     private static final AttributeXMLOutputter
> DEFAULT_OUTPUTTER = new AttributeXMLOutputter();
>     
>     // Cache of already parsed XPath expressions,
> keyed by String representations
>     // of the expression as passed to applyXPath().
>     private static final Map XPATH_CACHE = new
> WeakHashMap();
> 
>     // The contained nodes
>     private List nodes;
>     // The outputter used to create toString
> representation
>     private XMLOutputter outputter;
>     
>     /**
>      * Creates an empty node list.
>      */
>     public NodeList()
>     {
>         nodes = new ArrayList();
>         outputter = DEFAULT_OUTPUTTER;
>     }
>     
>     /**
>      * Creates a node set template that holds a
> single {@link Document} node.
>      */
>     public NodeList(Document document)
>     {
>         this((Object)document);
>     }
>     
>     /**
>      * Creates a node set template that holds a
> single {@link Element} node.
>      */
>     public NodeList(Element element)
>     {
>         this((Object)element);
>     }
> 
>     private NodeList(Object object)
>     {
>         if(object == null)
>             throw new IllegalArgumentException(
>                 "Cannot construct NodeList with
> null.");
>         nodes = new ArrayList(1);
>         nodes.add(object);
>         outputter = DEFAULT_OUTPUTTER;
>     }
>     
>     /**
>      * Creates a node set template that holds a list
> of nodes. 
>      * @param nodes the list of nodes this template
> should hold. The created 
>      * template will copy the passed nodes list, so
> changes to the passed list
>      * will not affect the model.
>      */
>     public NodeList(List nodes)
> 
=== message truncated ===


__________________________________________________
Do You Yahoo!?
Make international calls for as low as $.04/minute with Yahoo! Messenger
http://phonecard.yahoo.com/

Re: Creative criticism on Anakia design

Posted by Jon Stevens <jo...@latchkey.com>.
on 7/31/01 7:18 PM, "bob mcwhirter" <bo...@werken.com> wrote:

>> Anakia hasn't had much innovation added to it since it was released. I look
>> forward to your further patches and contributions.
> 
> btw, I plan on updating Anakia to use Jaxen to replace werken.xpath once
> it's more stable, to allow for not only JDOM documents in the context,
> but also dom4j, W3C-DOM, EXML, or whatnot.
> 
> -bob

+1

-jon


Re: Creative criticism on Anakia design

Posted by bob mcwhirter <bo...@werken.com>.
> Anakia hasn't had much innovation added to it since it was released. I look
> forward to your further patches and contributions.

btw, I plan on updating Anakia to use Jaxen to replace werken.xpath once
it's more stable, to allow for not only JDOM documents in the context,
but also dom4j, W3C-DOM, EXML, or whatnot.

	-bob


Re: Creative criticism on Anakia design

Posted by Jon Stevens <jo...@latchkey.com>.
on 7/26/01 1:52 AM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> Hi all!
> 
> I've looked at Anakia, and while I find the overall idea neat, I'm quite
> unsatisfied with the implementation.

Cool!

> Namely, the way Anakia deals with the JDOM document can hardly be named
> object-oriented.

I never remember claiming that it was OO. :-)

I should also add that Anakia was a weekend proof of concept hack that has
turned into something a bit more powerful and important than I ever
imagined.

> It sticks all kinds of "tools" ($xmlout, $treewalk, $xpath,
> $escape) into the context that can be applied to JDOM nodes. I feel that it
> would be more natural to have the functionality of these objects
> encapsulated in a class that wraps a list of JDOM nodes, so methods could be
> called on them.

Great idea!

> In the current design, to output the <title> elements of all chapters of a
> book, you'd have to write:
> 
> #set( $titles = $xpath.applyTo("book/chapter/title") )
> #foreach( $title in $titles )
>   $xmlout.outputString($title)
> #end
> 
> Now, imagine you have a NodeList class that contains a java.util.List of
> JDOM nodes internally, and it:
> - has a "NodeList applyXPath(String xpath)" method that produces another
> NodeList by applying an XPath to the current NodeList,
> - has "String toString()" implemented such that it produces a valid XML
> fragment (complete with proper escaping) consisting of JDOM nodes it
> currently contains - this greatly simplifies writing XML-to-XML transforming
> templates,
> - has a "java.util.List getList()" method, so if you *really* have custom
> processing needs, you can access the underlying nodes individually from the
> template,
> - has a "void setXMLOutputter(XMLOutputter xmlout)" method so you're in
> control of how will toString() render the nodes.
> 
> Were $root such a NodeList instead of plainly a JDOM Element, the above
> Velocity fragment could be rewritten as:
> 
> $root.applyXPath("book/chapter/title")
> 
> Looks efficient, doesn't it? And it feels much more like being
> object-oriented, IMHO. Note that this expression itself results in a
> NodeList that can be assigned to a variable and further manipulated. The
> reason above expression will produce the XML fragment consisting of title
> nodes is that the NodeList's toString() is overridden to do so.

Sounds great!

> Imagine it's even performance optimized because:
> - it doesn't parse the XPath expression every time, but uses a WeakHashMap
> to cache already parsed XPath expressions - as long as the template uses the
> same String object to call the applyXPath method (which I suspect it does)
> this will work nicely.
> - toString() uses a single StringWriter to output all nodes, whereas using
> xmlout.outputString in a #foreach uses one StringWriter per node.

Sounds great!

> Finally, imagine that you need not imagine this class, as I already wrote it
> and attached it to this letter.

You forgot to attach some nice documentation as well as the patch to Anakia
itself to use it. 

:-)

There is also the minor issue of the fact that this would break all of the
existing .vsl files out there if it was applied to Anakia itself.

> This design makes $xmlout, $xpath, and $escape obsolete. $treewalk is
> already needless as even in the current Anakia design
> 
> $treewalk.allElements($element) <=> $xpath.applyTo(".//*", $element)

This is a result of my complete lack of intelligence (and care) with regards
to Xpath. :-)

> I hope you (the community) will like NodeList and consider redesigning
> Anakia to use it and thus become more OO and intuitive. If so, let someone
> commit it (I'm no committer, this is my first post - my first itch to
> scratch in Velocity...) and do the required modifications in AnakiaTask
> ($root and $project should be NodeList instances).

If you are really interested in seeing this class applied to CVS, you are
going to have to do the rest of the work to make it happen (I really don't
have time right now).

My suggestions:

#1. Factor the core of Anakia.java into a base class which people can extend
to add their own functionality on top of. Keep the Anakia.java functionality
the same and have it extend the base class.

#2. Create an AnakiaNodeList.java which extends the base class and which
people can refer to directly in their Ant build.xml files and implements
your new functionality without breaking the existing functionality.

#3. Create another xdoc which documents this new functionality.

Anakia hasn't had much innovation added to it since it was released. I look
forward to your further patches and contributions.

Thanks!

-jon