001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jxpath.ri.axes;
017:
018: import java.util.Iterator;
019:
020: import org.apache.commons.jxpath.ri.EvalContext;
021: import org.apache.commons.jxpath.ri.InfoSetUtil;
022: import org.apache.commons.jxpath.ri.compiler.Expression;
023: import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
024: import org.apache.commons.jxpath.ri.model.NodePointer;
025: import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
026: import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
027:
028: /**
029: * EvalContext that checks predicates.
030: *
031: * @author Dmitri Plotnikov
032: * @version $Revision: 1.22 $ $Date: 2004/02/29 14:17:37 $
033: */
034: public class PredicateContext extends EvalContext {
035: private Expression expression;
036: private boolean done = false;
037: private Expression nameTestExpression;
038: private PropertyPointer dynamicPropertyPointer;
039:
040: public PredicateContext(EvalContext parentContext,
041: Expression expression) {
042: super (parentContext);
043: this .expression = expression;
044: if (expression instanceof NameAttributeTest) {
045: nameTestExpression = ((NameAttributeTest) expression)
046: .getNameTestExpression();
047: }
048: }
049:
050: public boolean nextNode() {
051: if (done) {
052: return false;
053: }
054: while (parentContext.nextNode()) {
055: if (setupDynamicPropertyPointer()) {
056: Object pred = nameTestExpression
057: .computeValue(parentContext);
058: String propertyName = InfoSetUtil.stringValue(pred);
059:
060: // At this point it would be nice to say:
061: // dynamicPropertyPointer.setPropertyName(propertyName)
062: // and then: dynamicPropertyPointer.isActual().
063: // However some PropertyPointers, e.g. DynamicPropertyPointer
064: // will declare that any property you ask for is actual.
065: // That's not acceptable for us: we really need to know
066: // if the property is currently declared. Thus,
067: // we'll need to perform a search.
068: boolean ok = false;
069: String names[] = dynamicPropertyPointer
070: .getPropertyNames();
071: for (int i = 0; i < names.length; i++) {
072: if (names[i].equals(propertyName)) {
073: ok = true;
074: break;
075: }
076: }
077: if (ok) {
078: dynamicPropertyPointer
079: .setPropertyName(propertyName);
080: position++;
081: return true;
082: }
083: } else {
084: Object pred = expression.computeValue(parentContext);
085: if (pred instanceof Iterator) {
086: if (!((Iterator) pred).hasNext()) {
087: return false;
088: }
089: pred = ((Iterator) pred).next();
090: }
091:
092: if (pred instanceof NodePointer) {
093: pred = ((NodePointer) pred).getNode();
094: }
095:
096: if (pred instanceof Number) {
097: int pos = (int) InfoSetUtil.doubleValue(pred);
098: position++;
099: done = true;
100: return parentContext.setPosition(pos);
101: } else if (InfoSetUtil.booleanValue(pred)) {
102: position++;
103: return true;
104: }
105: }
106: }
107: return false;
108: }
109:
110: /**
111: * Used for an optimized access to dynamic properties using the
112: * "map[@name = 'name']" syntax
113: */
114: private boolean setupDynamicPropertyPointer() {
115: if (nameTestExpression == null) {
116: return false;
117: }
118:
119: NodePointer parent = parentContext.getCurrentNodePointer();
120: if (parent == null) {
121: return false;
122: }
123: parent = parent.getValuePointer();
124: if (!(parent instanceof PropertyOwnerPointer)) {
125: return false;
126: }
127: dynamicPropertyPointer = (PropertyPointer) ((PropertyOwnerPointer) parent)
128: .getPropertyPointer().clone();
129: return true;
130: }
131:
132: public boolean setPosition(int position) {
133: if (nameTestExpression == null) {
134: return setPositionStandard(position);
135: } else {
136: if (dynamicPropertyPointer == null) {
137: if (!setupDynamicPropertyPointer()) {
138: return setPositionStandard(position);
139: }
140: }
141: if (position < 1
142: || position > dynamicPropertyPointer.getLength()) {
143: return false;
144: }
145: dynamicPropertyPointer.setIndex(position - 1);
146: return true;
147: }
148: }
149:
150: public NodePointer getCurrentNodePointer() {
151: if (position == 0) {
152: if (!setPosition(1)) {
153: return null;
154: }
155: }
156: if (dynamicPropertyPointer != null) {
157: return dynamicPropertyPointer.getValuePointer();
158: } else {
159: return parentContext.getCurrentNodePointer();
160: }
161: }
162:
163: public void reset() {
164: super .reset();
165: done = false;
166: }
167:
168: public boolean nextSet() {
169: reset();
170: return parentContext.nextSet();
171: }
172:
173: private boolean setPositionStandard(int position) {
174: if (this .position > position) {
175: reset();
176: }
177:
178: while (this .position < position) {
179: if (!nextNode()) {
180: return false;
181: }
182: }
183: return true;
184: }
185: }
|