    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.axes;
    17
    18  import org.apache.commons.jxpath.Pointer;
    19  import org.apache.commons.jxpath.ri.EvalContext;
    20  import org.apache.commons.jxpath.ri.compiler.NodeTest;
    21  import org.apache.commons.jxpath.ri.model.NodeIterator;
    22  import org.apache.commons.jxpath.ri.model.NodePointer;
    23
    24  /***
    25   * EvalContext that can walk the "child::", "following-sibling::" and
    26   * "preceding-sibling::" axes.
    27   *
    28   * @author Dmitri Plotnikov
    29   * @version $Revision: 1.16 $ $Date: 2004/03/25 03:49:50 $
    30   */
    31  public class ChildContext extends EvalContext {
    32      private NodeTest nodeTest;
    33      private boolean startFromParentLocation;
    34      private boolean reverse;
    35      private NodeIterator iterator;
    36
    37      public ChildContext(
    38          EvalContext parentContext,
    39          NodeTest nodeTest,
    40          boolean startFromParentLocation,
    41          boolean reverse)
    42      {
    43          super(parentContext);
    44          this.nodeTest = nodeTest;
    45          this.startFromParentLocation = startFromParentLocation;
    46          this.reverse = reverse;
    47      }
    48
    49      public NodePointer getCurrentNodePointer() {
    50          if (position == 0) {
    51              if (!setPosition(1)) {
    52                  return null;
    53              }
    54          }
    55          if (iterator != null) {
    56              return iterator.getNodePointer();
    57          }
    58          else {
    59              return null;
    60          }
    61      }
    62
    63      /***
    64       * This method is called on the last context on the path when only
    65       * one value is needed.  Note that this will return the whole property,
    66       * even if it is a collection. It will not extract the first element
    67       * of the collection.  For example, "books" will return the collection
    68       * of books rather than the first book from that collection.
    69       */
    70      public Pointer getSingleNodePointer() {
    71          if (position == 0) {
    72              while (nextSet()) {
    73                  prepare();
    74                  if (iterator == null) {
    75                      return null;
    76                  }
    77                  // See if there is a property there, singular or collection
    78                  NodePointer pointer = iterator.getNodePointer();
    79                  if (pointer != null) {
    80                      return pointer;
    81                  }
    82              }
    83              return null;
    84          }
    85          return getCurrentNodePointer();
    86      }
    87
    88      public boolean nextNode() {
    89          return setPosition(getCurrentPosition() + 1);
    90      }
    91
    92      public void reset() {
    93          super.reset();
    94          iterator = null;
    95      }
    96
    97      public boolean setPosition(int position) {
    98          int oldPosition = getCurrentPosition();
    99          super.setPosition(position);
    100         if (oldPosition == 0) {
    101             prepare();
    102         }
    103         if (iterator == null) {
    104             return false;
    105         }
    106         return iterator.setPosition(position);
    107     }
    108
    109     /***
    110      * Allocates a PropertyIterator.
    111      */
    112     private void prepare() {
    113         NodePointer parent = parentContext.getCurrentNodePointer();
    114         if (parent == null) {
    115             return;
    116         }
    117         if (startFromParentLocation) {
    118             NodePointer pointer = parent.getParent();
    119             iterator = pointer.childIterator(nodeTest, reverse, parent);
    120         }
    121         else {
    122             iterator = parent.childIterator(nodeTest, reverse, null);
    123         }
    124     }
    125 }