evalcontext.java
来自「JXPath」· Java 代码 · 共 361 行
JAVA
361 行
/*
* 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;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?