1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.jxpath.ri.compiler;
  17. import org.apache.commons.jxpath.ri.EvalContext;
  18. import org.apache.commons.jxpath.ri.axes.InitialContext;
  19. import org.apache.commons.jxpath.ri.axes.NodeSetContext;
  20. import org.apache.commons.jxpath.ri.axes.PredicateContext;
  21. import org.apache.commons.jxpath.ri.axes.SimplePathInterpreter;
  22. import org.apache.commons.jxpath.ri.axes.UnionContext;
  23. import org.apache.commons.jxpath.ri.model.NodePointer;
  24. /**
  25. * An element of the parse tree that represents an expression path, which is a
  26. * path that starts with an expression like a function call: <code>getFoo(.)
  27. * /bar</code>.
  28. *
  29. * @author Dmitri Plotnikov
  30. * @version $Revision: 1.11 $ $Date: 2004/02/29 14:17:39 $
  31. */
  32. public class ExpressionPath extends Path {
  33. private Expression expression;
  34. private Expression predicates[];
  35. private boolean basicKnown = false;
  36. private boolean basic;
  37. public ExpressionPath(
  38. Expression expression,
  39. Expression[] predicates,
  40. Step[] steps)
  41. {
  42. super(steps);
  43. this.expression = expression;
  44. this.predicates = predicates;
  45. }
  46. public Expression getExpression() {
  47. return expression;
  48. }
  49. /**
  50. * Predicates are the expressions in brackets that may follow
  51. * the root expression of the path.
  52. */
  53. public Expression[] getPredicates() {
  54. return predicates;
  55. }
  56. /**
  57. * Returns true if the root expression or any of the
  58. * predicates or the path steps are context dependent.
  59. */
  60. public boolean computeContextDependent() {
  61. if (expression.isContextDependent()) {
  62. return true;
  63. }
  64. if (predicates != null) {
  65. for (int i = 0; i < predicates.length; i++) {
  66. if (predicates[i].isContextDependent()) {
  67. return true;
  68. }
  69. }
  70. }
  71. return super.computeContextDependent();
  72. }
  73. /**
  74. * Recognized paths formatted as <code>$x[3]/foo[2]</code>. The
  75. * evaluation of such "simple" paths is optimized and streamlined.
  76. */
  77. public boolean isSimpleExpressionPath() {
  78. if (!basicKnown) {
  79. basicKnown = true;
  80. basic = isSimplePath() && areBasicPredicates(getPredicates());
  81. }
  82. return basic;
  83. }
  84. public String toString() {
  85. StringBuffer buffer = new StringBuffer();
  86. if (expression instanceof CoreOperation
  87. || expression instanceof ExpressionPath
  88. || expression instanceof LocationPath) {
  89. buffer.append('(');
  90. buffer.append(expression);
  91. buffer.append(')');
  92. }
  93. else {
  94. buffer.append(expression);
  95. }
  96. if (predicates != null) {
  97. for (int i = 0; i < predicates.length; i++) {
  98. buffer.append('[');
  99. buffer.append(predicates[i]);
  100. buffer.append(']');
  101. }
  102. }
  103. Step steps[] = getSteps();
  104. if (steps != null) {
  105. for (int i = 0; i < steps.length; i++) {
  106. buffer.append("/");
  107. buffer.append(steps[i]);
  108. }
  109. }
  110. return buffer.toString();
  111. }
  112. public Object compute(EvalContext context) {
  113. return expressionPath(context, false);
  114. }
  115. public Object computeValue(EvalContext context) {
  116. return expressionPath(context, true);
  117. }
  118. /**
  119. * Walks an expression path (a path that starts with an expression)
  120. */
  121. protected Object expressionPath(
  122. EvalContext evalContext,
  123. boolean firstMatch)
  124. {
  125. Object value = expression.compute(evalContext);
  126. EvalContext context;
  127. if (value instanceof InitialContext) {
  128. // This is an optimization. We can avoid iterating through a
  129. // collection if the context bean is in fact one.
  130. context = (InitialContext) value;
  131. }
  132. else if (value instanceof EvalContext) {
  133. // UnionContext will collect all values from the "value" context
  134. // and treat the whole thing as a big collection.
  135. context =
  136. new UnionContext(
  137. evalContext,
  138. new EvalContext[] {(EvalContext) value });
  139. }
  140. else {
  141. context = evalContext.getRootContext().getConstantContext(value);
  142. }
  143. if (firstMatch
  144. && isSimpleExpressionPath()
  145. && !(context instanceof NodeSetContext)) {
  146. EvalContext ctx = context;
  147. NodePointer ptr = (NodePointer) ctx.getSingleNodePointer();
  148. if (ptr != null
  149. && (ptr.getIndex() == NodePointer.WHOLE_COLLECTION
  150. || predicates == null
  151. || predicates.length == 0)) {
  152. return SimplePathInterpreter.interpretSimpleExpressionPath(
  153. evalContext,
  154. ptr,
  155. predicates,
  156. getSteps());
  157. }
  158. }
  159. if (predicates != null) {
  160. for (int j = 0; j < predicates.length; j++) {
  161. context = new PredicateContext(context, predicates[j]);
  162. }
  163. }
  164. if (firstMatch) {
  165. return getSingleNodePointerForSteps(context);
  166. }
  167. else {
  168. return evalSteps(context);
  169. }
  170. }
  171. }