001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.jxpath.ri.axes; 018 019import org.apache.commons.jxpath.Pointer; 020import org.apache.commons.jxpath.ri.EvalContext; 021import org.apache.commons.jxpath.ri.compiler.NodeTest; 022import org.apache.commons.jxpath.ri.model.NodeIterator; 023import org.apache.commons.jxpath.ri.model.NodePointer; 024 025/** 026 * EvalContext that can walk the "child::", "following-sibling::" and 027 * "preceding-sibling::" axes. 028 * 029 * @author Dmitri Plotnikov 030 * @version $Revision: 652903 $ $Date: 2008-05-02 22:46:32 +0200 (Fr, 02 Mai 2008) $ 031 */ 032public class ChildContext extends EvalContext { 033 private NodeTest nodeTest; 034 private boolean startFromParentLocation; 035 private boolean reverse; 036 private NodeIterator iterator; 037 038 /** 039 * Create a new ChildContext. 040 * @param parentContext parent EvalContext 041 * @param nodeTest NodeTest 042 * @param startFromParentLocation whether to start from parent location 043 * @param reverse whether to iterate in reverse 044 */ 045 public ChildContext(EvalContext parentContext, NodeTest nodeTest, 046 boolean startFromParentLocation, boolean reverse) { 047 super(parentContext); 048 this.nodeTest = nodeTest; 049 this.startFromParentLocation = startFromParentLocation; 050 this.reverse = reverse; 051 } 052 053 public NodePointer getCurrentNodePointer() { 054 if (position == 0 && !setPosition(1)) { 055 return null; 056 } 057 return iterator == null ? null : iterator.getNodePointer(); 058 } 059 060 /** 061 * This method is called on the last context on the path when only 062 * one value is needed. Note that this will return the whole property, 063 * even if it is a collection. It will not extract the first element 064 * of the collection. For example, "books" will return the collection 065 * of books rather than the first book from that collection. 066 * @return Pointer 067 */ 068 public Pointer getSingleNodePointer() { 069 if (position == 0) { 070 while (nextSet()) { 071 prepare(); 072 if (iterator == null) { 073 return null; 074 } 075 // See if there is a property there, singular or collection 076 NodePointer pointer = iterator.getNodePointer(); 077 if (pointer != null) { 078 return pointer; 079 } 080 } 081 return null; 082 } 083 return getCurrentNodePointer(); 084 } 085 086 public boolean nextNode() { 087 return setPosition(getCurrentPosition() + 1); 088 } 089 090 public void reset() { 091 super.reset(); 092 iterator = null; 093 } 094 095 public boolean setPosition(int position) { 096 int oldPosition = getCurrentPosition(); 097 super.setPosition(position); 098 if (oldPosition == 0) { 099 prepare(); 100 } 101 return iterator == null ? false : iterator.setPosition(position); 102 } 103 104 /** 105 * Allocates a PropertyIterator. 106 */ 107 private void prepare() { 108 NodePointer parent = parentContext.getCurrentNodePointer(); 109 if (parent == null) { 110 return; 111 } 112 NodePointer useParent = startFromParentLocation ? parent.getParent() : parent; 113 iterator = useParent.childIterator(nodeTest, reverse, 114 startFromParentLocation ? parent : null); 115 } 116}