Hi all,

Just thought I'd throw in my two cents on this issue.

I agree that the structure connecting object models with Navigator
implementations should change somewhat. As I see it, we could go one of
two ways (there may be more - please suggest them if you have any).

1. Similar to the current structure, but with the following changes:

   * org.jaxen.JaXPath combined with BaseXPath and renamed to
org.jaxen.XPath
   * org.jaxen.dom.XPath renamed to org.jaxen.dom.DomXPath
   * org.jaxen.dom4j.XPath renamed to org.jaxen.dom4j.Dom4jXPath
   * etc...

This would then be used in the following manner:

  org.jaxen.XPath xpath = new org.jaxen.jdom.JdomXPath("//foo/bar");
  List nodes = xpath.selectNodes( myJdomDocument );

This is similar to the pattern used by the Collections API, were you
will generally have the local variable as one of the super-types
(List, Map, Set) which are initialised to a specific implementation
(ArrayList, HashMap, HashSet).

Advantages:
   * No reflection, leading to slightly better performance and
     (depending on your opinion) better readability.
   * Fairly simple to implement - it's basically already done.
   * Object model support is completely decoupled from the core engine
Disadvantages:
   * Requires an almost-empty subclass that simply overrides one
     method. Seems wasteful.

OR

2. Have a single XPath implementation that uses reflection to determine
which Navigator implementation to use.

   * org.jaxen.JaXPath combined with BaseXPath and renamed to
org.jaxen.XPath
   * org.jaxen.dom.XPath removed.
   * etc...

The new org.jaxen.XPath would examine the class type of the object
being passed in to it's 'selectNodes()' or 'selectSingleNode()'
or other methods and use reflection to determine which Navigator
implementation supports it.

It would then be used in the following manner:

  org.jaxen.XPath xpath = new org.jaxen.XPath("//foo/bar");
  List nodes = xpath.selectNodes( myXmlDocumentModel );

It would also have to support adding extra (non-standard) object models.
This could be done in a couple of ways. One would be to have a static
registry of navigators that can be added to by users of custom object
models. Eg:

   // Register my custom object model
   XPath.registerNavigator("org.myxml.jaxen.DocumentNavigator",
"org.myxml");
   org.jaxen.XPath xpath = new org.jaxen.XPath("//foo/bar");
   List nodes = xpath.selectNodes( myXmlDocument );

...where "org.myxml" being passed in indicates that all objects that are
in the "org.myxml" package (or it's descendants) should use the
"org.myxml.jaxen.DocumentNavigator" navigator implementation.

Alternately, the Navigator instance could be passed in, either to the
XPath constructor or the selectNodes() method. Eg:

   Navigator nav = new org.myxml.jaxen.DocumentNavigator();
   org.jaxen.XPath = new XPath("//foo/bar");
   List nodes = xpath.selectNodes( myXmlDocument, nav );



Advantages:
   * Simple to use in the common case: just create the same XPath object
every time
     and it works for most models.
   * Allows changing of the XML object model without changing
     the XPath code.
Disadvantages:
   * Uses reflection.
   * Requires some hard-coded links somewhere (be they Strings or
     otherwise) that map object types to a Navigator implementation.

Conclusion:
-----------

At first, I was quite attracted to the reflection structure. It would
mean you have a single class (org.jaxen.XPath) that can be used
everywhere, no matter what object model you are using.

On further reflection however, the model doesn't have that many
advantages and has several significant disadvantages.

Firstly, the first structure suggested above isn't that arduous. If you
use the abstract base class (org.jaxen.XPath) everywhere in your code
other than when constructing, switching between object models is
trivial. If you change your object model from JDOM to Dom4J, it requires
changes to a single line of code for each XPath instance. And chances
are that if you're switching between two models, those line changes will
be the simplest changes you have to make.

Secondly, using the reflection structure requires more work that
previously for non-standard object models. You have to either register
your Navigator somewhere, or pass it around all over the place.

Thirdly, and perhaps most critically, using reflection is not that
simple, and it means there are concrete (or at least masking-tape) links
between the core engine and the standard XML object models. To use
reflection, something will either have to map each specific Object in
the XML object model (eg. org.jdom.Document, org.jdom.Element, etc...)
to it's appropriate Navigator, or use the short-cut of mapping to the
package name rather than the specific classes (eg "org.jdom",
"org.w3.dom", etc). The former method is tedious, the latter dangerous
(it will allow inserting of other objects such as
"org.jdom.JDOMException"), and both are more inefficient.

I definitely believe that whatever scenario you decide on,
"org.jaxen.XPath" should be the standard variable type, something I'm
not comfortable doing with JaXPath or BaseXPath at the moment. But I
don't think it is necessary or even advantagious to change to a
reflection model. If you're really keen, you could make
"org.jaxen.XPath" an interface (except that you also have an interface
called "org.jaxen.expr.XPath" - could/should that be changed also?) and
have BaseXPath as the abstract base class implementing org.jaxen.XPath.

Anyway, sorry for the length and thanks for your attention...

David Peterson


_______________________________________________
Jaxen-interest mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jaxen-interest

Reply via email to