|
What this is
Other links
The source code/* * Copyright 1999-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jxpath.ri; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import org.apache.commons.jxpath.BasicNodeSet; import org.apache.commons.jxpath.ExpressionContext; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.JXPathException; import org.apache.commons.jxpath.NodeSet; import org.apache.commons.jxpath.Pointer; import org.apache.commons.jxpath.ri.axes.RootContext; import org.apache.commons.jxpath.ri.model.NodePointer; /** * An XPath evaluation context. * * When evaluating a path, a chain of EvalContexts is created, each context in * the chain representing a step of the path. Subclasses of EvalContext * implement behavior of various XPath axes: "child::", "parent::" etc. * * @author Dmitri Plotnikov * @version $Revision: 1.30 $ $Date: 2004/03/25 05:42:01 $ */ public abstract class EvalContext implements ExpressionContext, Iterator { protected EvalContext parentContext; protected RootContext rootContext; protected int position = 0; private boolean startedSetIteration = false; private boolean done = false; private boolean hasPerformedIteratorStep = false; private Iterator pointerIterator; // Sorts in the reverse order to the one defined by the Comparable // interface. private static final Comparator REVERSE_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { return ((Comparable) o2).compareTo(o1); } }; public EvalContext(EvalContext parentContext) { this.parentContext = parentContext; } public Pointer getContextNodePointer() { return getCurrentNodePointer(); } public JXPathContext getJXPathContext() { return getRootContext().getJXPathContext(); } public int getPosition() { return position; } /** * Determines the document order for this context. * * @return 1 ascending order, -1 descending order, * 0 - does not require ordering */ public int getDocumentOrder() { if (parentContext != null && parentContext.isChildOrderingRequired()) { return 1; } return 0; } /** * Even if this context has the natural ordering and therefore does * not require collecting and sorting all nodes prior to returning them, * such operation may be required for any child context. */ public boolean isChildOrderingRequired() { // Default behavior: if this context needs to be ordered, // the children need to be ordered too if (getDocumentOrder() != 0) { return true; } return false; } /** * Returns true if there are mode nodes matching the context's constraints. */ public boolean hasNext() { if (pointerIterator != null) { return pointerIterator.hasNext(); } if (getDocumentOrder() != 0) { return constructIterator(); } else { if (!done && !hasPerformedIteratorStep) { performIteratorStep(); } return !done; } } /** * Returns the next node pointer in the context */ public Object next() { if (pointerIterator != null) { return pointerIterator.next(); } if (getDocumentOrder() != 0) { if (!constructIterator()) { throw new NoSuchElementException(); } return pointerIterator.next(); } else { if (!done && !hasPerformedIteratorStep) { performIteratorStep(); } if (done) { throw new NoSuchElementException(); } hasPerformedIteratorStep = false; return getCurrentNodePointer(); } } /** * Moves the iterator forward by one position */ private void performIteratorStep() { done = true; if (position != 0 && nextNode()) { done = false; } else { while (nextSet()) { if (nextNode()) { done = false; break; } } } hasPerformedIteratorStep = true; } /** * Operation is not supported */ public void remove() { throw new UnsupportedOperationException( "JXPath iterators cannot remove nodes"); } private boolean constructIterator() { HashSet set = new HashSet(); ArrayList list = new ArrayList(); while (nextSet()) { while (nextNode()) { NodePointer pointer = getCurrentNodePointer(); if (!set.contains(pointer)) { // Pointer cln = (Pointer) pointer.clone(); set.add(pointer); list.add(pointer); } } } if (list.isEmpty()) { return false; } if (getDocumentOrder() == 1) { Collections.sort(list); } else { Collections.sort(list, REVERSE_COMPARATOR); } pointerIterator = list.iterator(); return true; } /** * Returns the list of all Pointers in this context for the current * position of the parent context. */ public List getContextNodeList() { int pos = position; if (pos != 0) { reset(); } List list = new ArrayList(); while (nextNode()) { list.add(getCurrentNodePointer()); } if (pos != 0) { setPosition(pos); } else { reset(); } return list; } /** * Returns the list of all Pointers in this context for all positions * of the parent contexts. If there was an ongoing iteration over * this context, the method should not be called. */ public NodeSet getNodeSet() { if (position != 0) { throw new JXPathException( "Simultaneous operations: " + "should not request pointer list while " + "iterating over an EvalContext"); } BasicNodeSet set = new BasicNodeSet(); while (nextSet()) { while (nextNode()) { set.add((Pointer)getCurrentNodePointer().clone()); } } return set; } /** * Typically returns the NodeSet by calling getNodeSet(), * but will be overridden for contexts that more naturally produce * individual values, e.g. VariableContext */ public Object getValue() { return getNodeSet(); } public String toString() { Pointer ptr = getContextNodePointer(); if (ptr == null) { return "Empty expression context"; } else { return "Expression context [" + getPosition() + "] " + ptr.asPath(); } } /** * Returns the root context of the path, which provides easy * access to variables and functions. */ public RootContext getRootContext() { if (rootContext == null) { rootContext = parentContext.getRootContext(); } return rootContext; } /** * Sets current position = 0, which is the pre-iteration state. */ public void reset() { position = 0; } public int getCurrentPosition() { return position; } /** * Returns the first encountered Pointer that matches the current * context's criteria. */ public Pointer getSingleNodePointer() { reset(); while (nextSet()) { if (nextNode()) { return getCurrentNodePointer(); } } return null; } /** * Returns the current context node. Undefined before the beginning * of the iteration. */ public abstract NodePointer getCurrentNodePointer(); /** * Returns true if there is another sets of objects to interate over. * Resets the current position and node. */ public boolean nextSet() { reset(); // Restart iteration within the set // Most of the time you have one set per parent node // First time this method is called, we should look for // the first parent set that contains at least one node. if (!startedSetIteration) { startedSetIteration = true; while (parentContext.nextSet()) { if (parentContext.nextNode()) { return true; } } return false; } // In subsequent calls, we see if the parent context // has any nodes left in the current set if (parentContext.nextNode()) { return true; } // If not, we look for the next set that contains // at least one node while (parentContext.nextSet()) { if (parentContext.nextNode()) { return true; } } return false; } /** * Returns true if there is another object in the current set. * Switches the current position and node to the next object. */ public abstract boolean nextNode(); /** * Moves the current position to the specified index. Used with integer * predicates to quickly get to the n'th element of the node set. * Returns false if the position is out of the node set range. * You can call it with 0 as the position argument to restart the iteration. */ public boolean setPosition(int position) { this.position = position; return true; } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.