You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by bu...@apache.org on 2003/11/27 14:28:30 UTC

DO NOT REPLY [Bug 25050] New: - getValue() and iterate() are not consistent

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25050>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25050

getValue() and iterate() are not consistent

           Summary: getValue() and iterate() are not consistent
           Product: Commons
           Version: unspecified
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: Normal
          Priority: Other
         Component: JXPath
        AssignedTo: commons-dev@jakarta.apache.org
        ReportedBy: ydu@zurich.ibm.com


On xpath expression which are not simple path (containing * or //), getValue()
does not always find a value. Using iterate() is a workaround.

example:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.jxpath.JXPathContext;

/**
 * @author Yann Duponchel
 */
public class JXPathRecursiveMap {

	public static String tests[] = {
		"n2/n3/n6",
		"n2//n6", // BUG
		"n2/n3/n6/n7",
		"n2/*/*/n7", // BUG
		"n2//n7", // BUG
		"n2//n7/bytes",
	};
	
	public static void main(String args[]) {
		Map tree = new HashMap();
		Map nodeC, nodeP;
		tree.put("n1", "n1-0");
		nodeC = new HashMap();
		tree.put("n2", nodeC);
		nodeP = nodeC;
		nodeC = new HashMap();
		nodeP.put("n3", nodeC);
		nodeP = nodeC;
		nodeP.put("n4", new HashMap());
		nodeP.put("n5", "n3-1");
		nodeC = new HashMap();
		nodeP.put("n6", nodeC);
		nodeP = nodeC;
		nodeP.put("n7", "n4-0");
		nodeC = new HashMap();
		tree.put("n8", nodeC);
		nodeP = nodeC;
		nodeC = new HashMap();
		nodeP.put("n9", nodeC);
		nodeP = nodeC;
		nodeP.put("n10", "n2-1");
		
		System.out.println(tree);
		System.out.println();

		JXPathContext context = JXPathContext.newContext(tree);
		for (int i = 0; i < tests.length; i++) {
			Object result = context.getValue(tests[i]);
			if (result != null)
				System.out.println("getValue(" + tests[i] + ") = " + result);
			else
				System.out.println("getValue(" + tests[i] + ") = null");
			System.out.print("iterate(" + tests[i] + ") = ");
			for (Iterator it = context.iterate(tests[i]); it.hasNext();) {
				result = it.next();
				System.out.print(result + "; ");
			}
			System.out.println();
		}
	}
}

============================================================

The previous example produces this output:

{n1=n1-0, n8={n9={n10=n2-1}}, n2={n3={n6={n7=n4-0}, n4={}, n5=n3-1}}}

getValue(n2/n3/n6) = {n7=n4-0}
iterate(n2/n3/n6) = {n7=n4-0}; 

getValue(n2//n6) = null
iterate(n2//n6) = {n7=n4-0}; 

getValue(n2/n3/n6/n7) = n4-0
iterate(n2/n3/n6/n7) = n4-0; 

getValue(n2/*/*/n7) = null
iterate(n2/*/*/n7) = n4-0; 

getValue(n2//n7) = null
iterate(n2//n7) = n4-0; 

getValue(n2//n7/bytes) = [B@16cd7d5
iterate(n2//n7/bytes) = 110; 52; 45; 48; 

============================================================
The problem seems to be the following:
context.getValue() calls getSingleNodePointerForSteps() which calls
getSingleNodePointer() and then nextNode() once to get the first matching node,
while context.iterate().next() calls next() through the ValueIterator.

And the real problem is that next() and nextNode() are very clearly different!
next() is defined on Expression while nextNode() is defined on DescendantContext...

At least, this is my impression.

Yann Duponchel

============================================================

Here is a trivial patch of org.apache.commons.jxpath.ri.compiler.Path 
(seems to works, but clearly not optimal)

    protected Pointer getSingleNodePointerForSteps(EvalContext context) {
        if (steps.length == 0) {
            return context.getSingleNodePointer();
        }

        if (isSimplePath()) {
            NodePointer ptr = (NodePointer) context.getSingleNodePointer();
            return SimplePathInterpreter.interpretSimpleLocationPath(
                context,
                ptr,
                steps);
        }
        else {
			// return searchForPath(context); // Identical code as evalSteps() - YD
			//return searchForPathYD(context).getSingleNodePointer(); // Equivalent to
previous code but still buggus - YD
			context = searchForPathYD(context);
			return (Pointer) (context.hasNext() ? context.next() : null); // - YD
        }
    }

    private EvalContext searchForPathYD(EvalContext context) {
        for (int i = 0; i < steps.length; i++) {
            context =
                createContextForStep(
                    context,
                    steps[i].getAxis(),
                    steps[i].getNodeTest());
            Expression predicates[] = steps[i].getPredicates();
            if (predicates != null) {
                for (int j = 0; j < predicates.length; j++) {
                    context = new PredicateContext(context, predicates[j]);
                }
            }
        }
		return context;
    }

    protected EvalContext evalSteps(EvalContext context) {
    	return searchForPathYD(context);
    }

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org