Ok,
I think I nailed that bug. Please find attached a new version of DefaultLocationPath.java. I can't run junit right now because it has dom4j hardcoded all over the core tests (why? :) and I don't want to install dom4j :) Could you please run a regression test on it? I'm quite keen to use this stuff. What it does is instead of evaluating the step on all context nodes, and then evaluating the predicate over the result, it evaluates the predicate for EACH context node, stores the result in an interim list, and compiles a new list at the end. It passes my tests for the bug. Christian
// Copyright 2001 bob mcwhirter and James Strachan. All rights reserved. package org.jaxen.expr; import org.jaxen.Context; import org.jaxen.ContextSupport; import org.jaxen.UnsupportedAxisException; import org.jaxen.JaxenException; import org.jaxen.util.IdentityHashMap; import org.jaxen.util.SingleObjectIterator; import org.jaxen.util.LinkedIterator; import java.util.List; import java.util.ArrayList; import java.util.LinkedList; import java.util.Iterator; import java.util.Map; import java.util.Collections; abstract class DefaultLocationPath extends DefaultExpr implements LocationPath { private List steps; private final static Object PRESENT = new Object(); public DefaultLocationPath() { this.steps = new LinkedList(); } public void addStep(Step step) { getSteps().add( step ); } public List getSteps() { return this.steps; } public Expr simplify() { Iterator stepIter = getSteps().iterator(); Step eachStep = null; while ( stepIter.hasNext() ) { eachStep = (Step) stepIter.next(); eachStep.simplify(); } return this; } public String getText() { StringBuffer buf = new StringBuffer(); Iterator stepIter = getSteps().iterator(); while ( stepIter.hasNext() ) { buf.append( ((Step)stepIter.next()).getText() ); if ( stepIter.hasNext() ) { buf.append( "/" ); } } return buf.toString(); } public String toString() { StringBuffer buf = new StringBuffer(); Iterator stepIter = getSteps().iterator(); while( stepIter.hasNext() ) { buf.append( stepIter.next().toString() ); if ( stepIter.hasNext() ) { buf.append("/"); } } return buf.toString(); } public boolean isAbsolute() { return false; } public Object evaluate(Context context) throws JaxenException { List contextNodeSet = new ArrayList(); Map unique = new IdentityHashMap(); contextNodeSet.addAll( context.getNodeSet() ); Object eachContextNode = null; Iterator stepIter = getSteps().iterator(); Step eachStep = null; List newNodeSet = new ArrayList(); int contextSize = 0; OUTTER: while ( stepIter.hasNext() ) { eachStep = (Step) stepIter.next(); contextSize = contextNodeSet.size(); INNER: for ( int i = 0 ; i < contextSize ; ++i ) { eachContextNode = contextNodeSet.get( i ); Iterator axisNodeIter = eachStep.axisIterator( eachContextNode, context.getContextSupport() ); if ( axisNodeIter == null ) { continue INNER; } Object eachAxisNode = null; List interimSet=new ArrayList(); while ( axisNodeIter.hasNext() ) { eachAxisNode = axisNodeIter.next(); // System.err.println( "----> " + eachAxisNode + " // " + eachStep.matches( eachAxisNode, context.getContextSupport() ) ); if ( eachStep.matches( eachAxisNode, context.getContextSupport() ) ) { if ( ! unique.containsKey( eachAxisNode ) ) { unique.put( eachAxisNode, PRESENT ); interimSet.add( eachAxisNode ); } } } eachStep.getPredicateSet().evaluatePredicates(interimSet, context.getContextSupport() ); newNodeSet.addAll(interimSet); } contextNodeSet.clear(); contextNodeSet.addAll( newNodeSet ); newNodeSet.clear(); unique.clear(); } return contextNodeSet; } }