1. jaxen
  2. JAXEN-154

Decoupling Navigator and XPath


    • Type: Improvement Improvement
    • Status: Open Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: 1.2
    • Component/s: core
    • Labels:
    • Number of attachments :


      Brian Ewins noted this on the mailing list about a year ago. Adding his comments here so we don't losr track fo them:

      The one cycle that always bothers me is the one between 'Navigator' and 'XPath'.

      For comparison, first here's how things work in jaxp:
      //in jaxen we could use OM uris which are Navigator class names.
      String uri = "urn:jaxen:my.funky.jaxen.Navigator";
      XPathFactory xpf = XPathFactory.newInstance(uri);
      // set up the evaluation context
      XPath xpath = xpf.newXPath();
      // because we have the resolvers set up we can do all var/fn resolving
      // in the /parsing/ stage (unless someone made the mistake of adding
      an 'eval' function!)
      XPathExpression xexpr = xpath.compile(expression);
      // the compiled expression needs the navigator.
      // other evaluation paths are just sugar for getting the compiled
      expression first.
      Object result1 = xexpr.evaluate(context1, returnType);
      Object result2 = xexpr.evaluate(context2, returnType);

      The Navigator only appeared in that as something other classes depended on,
      it never depends on the public xpath api, or on the parser. Contrast
      this with jaxen:

      Navigator nav = new MyNavigator();
      // option 1: compile using navigator
      XPath xpath = nav.parseXPath(expression);
      // option 2: create by hand from base xpath
      XPath xpath = new BaseXPath(expression, nav);
      // option 3: use OM-specific xpath implementation
      XPath xpath = new MyXPath(nav);
      Object result1 = xpath.stringValueOf(context1);
      // jaxen has very late binding. This means that we can't do the
      // lookups earlier, to eliminate constant expressions etc.
      Object result2 = xpath.stringValueOf(context2);

      So, "option 1" makes the navigator depend on the parser and the xpath
      implementation, which in turn depends on the navigator - a cycle.
      Option 3 is just sugar for option 2. Option 2 is a little grotty
      compared to jaxp, a factory method returning an XPath given a string
      and a navigator would be just as good.

      Another cause of odd dependencies is the 'eval' function. This causes
      the 'function' package to depend on 'saxpath', which depends on 'expr'
      which depends on 'function'... ew. And once you're rid of 'eval',
      theres no longer a reason why fc/vc need to be bound so late, allowing
      some optimisations.

      Finally, theres the 'evaluate/simplify' methods in the expr package.
      In order to break the dependency between the parser and the runtime,
      we have saxpath calling a handler which creates objects of a given
      interface, which can be evaluated directly. However, because saxpath
      is borked, it really only works properly if you always create the tree
      with the expr.Default* objects. An alternative approach would be to
      have separate parser/evaluator packages both depending on a concrete
      AST package with visitor support - all of the 'BlahExpr' classes can
      be concrete so theres no need for all those interfaces to break the
      cycles. However, I don't think the current split is responsible for
      any cycles.

      I think if you drop that Navigator.parseXPath method and remove the
      'eval' function (which is completely unnecessary IMHO) most of the
      cycles can be made to disappear.


        No changes have yet been made on this issue.


          • Assignee:
            Brian Ewins
            Elliotte Rusty Harold


            • Created: