[jdom-interest] Jason's Node challenge

Amy Lewis amyzing at talsever.com
Tue May 1 05:30:45 PDT 2001


Jason has suggested here that a reasonable Node implementation can't be
developed.  I think, in the context of JDOM, that this is probably
true.  Nonetheless, I present a Node-based interface specification
here (without implementation).  It won't work with JDOM, because it
lies at some conceptual distance from the underpinnings of JDOM.  Most
notably, there is no way to extend final java.lang.String to StringNode
extends String implements LeafNode.  Nevertheless, FWIW, YMMV, IANAL. 
Also, this definition is somewhat incomplete.  *shrug*

This is somewhat lengthy, ignore, an it please you.

interface Node
{
    BranchNode getParent();

    String getValue();

    RootNode getRoot();

    // doesn't start you at the root, starts at this node
    TreeIterator iterator();

    NodeSet collectNodes(Axis axis, Namespace namespace, String name);

    NodeSet collectNodes(Axis axis, Class nodeType);

    NodeSet collectNodes(Axis axis, String value);
}

interface LeafNode extends Node
{
    // pure marker
}

interface BranchNode extends Node
{
    Node getFirstChild();

    Node getNextChild(Node sibling);

    NodeSet getChildren();

    void addChild(Node child);

    void removeChild(Node child);

    String getName();

    Namespace getNamespace();

    NodeSet getAttributes();

    void addAttribute(Attribute attrib);

    void removeAttribute(Attribute attrib);
}

interface RootNode extends BranchNode
{
// note that it "extends" because in Java you can't say "restricts"
// the contract is that getParent() returns a marker (null, perhaps),
// and the attribute methods do nothing.  Otherwise, a marker.
}

interface NodeSet
{
    // set the context for collection, for a new set.
    void setContext(Node context);

    // these three add to the existing collection, using each current
    // node in the set as a starting point.
    NodeSet collectNodes(Axis axis, Namespace namespace, String name);

    NodeSet collectNodes(Axis axis, Class nodeType);

    NodeSet collectNodes(Axis axis, String value);

    // these three operate to reduce the existing collection by
    // filtering
    NodeSet selectNodes(Axis axis, Namespace namespace, String name);

    NodeSet selectNodes(Axis axis, Class nodeType);

    NodeSet selectNodes(Axis axis, String value);

    NodeSet union(NodeSet unionWith);

    NodeSet intersection(NodeSet intersectWith);

    void addNode(Node content, Node context);

    void removeNode(Node content);

    int size();

    Node get(int);

    // not a tree iterator.  It ought to be a NodeIterator, but WTF
    // typical Collections semantics
    Iterator iterator();
}

interface TreeIterator
{
    boolean hasNext();

    Node next();

    boolean hasPrevious();

    Node previous();

    boolean hasParent();

    BranchNode parent();

    boolean hasFirstChild();

    Node firstChild();

    boolean hasNextSibling();

    nextSibling();

    boolean hasPreviousSibling();

    previousSibling();
}

Axis is an interface containing manifest constants appropriate to
XPath; Attribute is a LeafNode; Namespace is a namespace.

As noted, probably not suitable to Jason's challenge, because it would
do violence to the JDOM model.  Nevertheless, in concept it's possible. 
The advantage of this model--if there really is one, which is of course
unproven 'cause the implementation is still not finished and deadlines
*always* seem to loom--is a high degree of navigability and mutability,
starting from any position in the tree and moving relatively (this is
mostly achieved by the existence of collectNodes() and iterator() in
the Node interface).

In case it isn't obvious, Element implements BranchNode, Document
implements RootNode, everything else implements LeafNode (although the
implementation that I've got treats DocType and the like as attributes
of the root, not as nodes, for instance).  Most of the complexity (in
the implementation) is in NodeSet and TreeIterator; it's hidden
elsewhere.  The model is fairly easy to extend, as long as the
subclasses hold to contract (Node isn't directly implemented, for
instance).  The use of java.lang.Class in the signature for one of the
collectNodes/selectNodes variants requires that the class supplied
implement Node (it should IAE if it doesn't).  The implementation I've
got also guarantees no nulls, using a static final Node (with suitable
overrides) instead; this allows dotted-on methods:
NodeSet set = node.collectNodes(this, that).selectNodes(theOther, blah);
(and a NodeSet is always returned, even if empty, never null).

It's possible, I suppose, that some of the ideas here might be portable
to JDOM, so here it is.

Amy!
-- 
Amelia A. Lewis          alicorn at mindspring.com          amyzing at talsever.com
Tongue-tied and twisted, just an earthbound misfit, I.		-- Pink Floyd



More information about the jdom-interest mailing list