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