1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jxpath.ri.compiler;
17
18 import org.apache.commons.jxpath.Pointer;
19 import org.apache.commons.jxpath.ri.EvalContext;
20 import org.apache.commons.jxpath.ri.model.NodePointer;
21 import org.apache.commons.jxpath.ri.QName;
22 import org.apache.commons.jxpath.util.ValueUtils;
23
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.Locale;
27
28 /***
29 * Common superclass for several types of nodes in the parse tree. Provides
30 * APIs for optimization of evaluation of expressions. Specifically, an
31 * expression only needs to executed once during the evaluation of an xpath
32 * if that expression is context-independent. Expression.isContextDependent()
33 * provides that hint.
34 *
35 * @author Dmitri Plotnikov
36 * @version $Revision: 1.10 $ $Date: 2004/02/29 14:17:38 $
37 */
38 public abstract class Expression {
39
40 protected static final Double ZERO = new Double(0);
41 protected static final Double ONE = new Double(1);
42 protected static final Double NOT_A_NUMBER = new Double(Double.NaN);
43
44 private boolean contextDependencyKnown = false;
45 private boolean contextDependent;
46
47 /***
48 * Returns true if this expression should be re-evaluated
49 * each time the current position in the context changes.
50 */
51 public boolean isContextDependent() {
52 if (!contextDependencyKnown) {
53 contextDependent = computeContextDependent();
54 contextDependencyKnown = true;
55 }
56 return contextDependent;
57 }
58
59 /***
60 * Implemented by subclasses and result is cached by isContextDependent()
61 */
62 public abstract boolean computeContextDependent();
63
64 /***
65 * Evaluates the expression. If the result is a node set, returns
66 * the first element of the node set.
67 */
68 public abstract Object computeValue(EvalContext context);
69 public abstract Object compute(EvalContext context);
70
71 public Iterator iterate(EvalContext context) {
72 Object result = compute(context);
73 if (result instanceof EvalContext) {
74 return new ValueIterator((EvalContext) result);
75 }
76 return ValueUtils.iterate(result);
77 }
78
79 public Iterator iteratePointers(EvalContext context) {
80 Object result = compute(context);
81 if (result == null) {
82 return Collections.EMPTY_LIST.iterator();
83 }
84 if (result instanceof EvalContext) {
85 return (EvalContext) result;
86 }
87 return new PointerIterator(ValueUtils.iterate(result),
88 new QName(null, "value"),
89 context.getRootContext().getCurrentNodePointer().getLocale());
90 }
91
92 public static class PointerIterator implements Iterator {
93 private Iterator iterator;
94 private QName qname;
95 private Locale locale;
96
97 /***
98 * @deprecated Use the method that takes a NamespaceManager
99 */
100 public PointerIterator(Iterator it, QName qname, Locale locale) {
101 this.iterator = it;
102 this.qname = qname;
103 this.locale = locale;
104 }
105
106 public boolean hasNext() {
107 return iterator.hasNext();
108 }
109
110 public Object next() {
111 Object o = iterator.next();
112 return NodePointer.newNodePointer(qname, o, locale);
113 }
114
115 public void remove() {
116 throw new UnsupportedOperationException();
117 }
118 }
119
120 public static class ValueIterator implements Iterator {
121 private Iterator iterator;
122
123 public ValueIterator(Iterator it) {
124 this.iterator = it;
125 }
126
127 public boolean hasNext() {
128 return iterator.hasNext();
129 }
130
131 public Object next() {
132 Object o = iterator.next();
133 if (o instanceof Pointer) {
134 return ((Pointer) o).getValue();
135 }
136 return o;
137 }
138
139 public void remove() {
140 throw new UnsupportedOperationException();
141 }
142 }
143 }