Coverage Report - org.jaxen.expr.PredicateSet
 
Classes in this File Line Coverage Branch Coverage Complexity
PredicateSet
65%
53/81
60%
9/15
3.111
 
 1  
 /*
 2  
  * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/expr/PredicateSet.java,v 1.23 2006/11/13 22:38:17 elharo Exp $
 3  
  * $Revision: 1.23 $
 4  
  * $Date: 2006/11/13 22:38:17 $
 5  
  *
 6  
  * ====================================================================
 7  
  *
 8  
  * Copyright 2000-2002 bob mcwhirter & James Strachan.
 9  
  * All rights reserved.
 10  
  *
 11  
  *
 12  
  * Redistribution and use in source and binary forms, with or without
 13  
  * modification, are permitted provided that the following conditions are
 14  
  * met:
 15  
  * 
 16  
  *   * Redistributions of source code must retain the above copyright
 17  
  *     notice, this list of conditions and the following disclaimer.
 18  
  * 
 19  
  *   * Redistributions in binary form must reproduce the above copyright
 20  
  *     notice, this list of conditions and the following disclaimer in the
 21  
  *     documentation and/or other materials provided with the distribution.
 22  
  * 
 23  
  *   * Neither the name of the Jaxen Project nor the names of its
 24  
  *     contributors may be used to endorse or promote products derived 
 25  
  *     from this software without specific prior written permission.
 26  
  * 
 27  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 28  
  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 29  
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 30  
  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 31  
  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 32  
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 33  
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 34  
  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 35  
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 36  
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 37  
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 38  
  *
 39  
  * ====================================================================
 40  
  * This software consists of voluntary contributions made by many
 41  
  * individuals on behalf of the Jaxen Project and was originally
 42  
  * created by bob mcwhirter <bob@werken.com> and
 43  
  * James Strachan <jstrachan@apache.org>.  For more information on the
 44  
  * Jaxen Project, please see <http://www.jaxen.org/>.
 45  
  *
 46  
  * $Id: PredicateSet.java,v 1.23 2006/11/13 22:38:17 elharo Exp $
 47  
  */
 48  
 
 49  
 
 50  
 
 51  
 package org.jaxen.expr;
 52  
 
 53  
 import java.io.Serializable;
 54  
 import java.util.ArrayList;
 55  
 import java.util.Collections;
 56  
 import java.util.Iterator;
 57  
 import java.util.List;
 58  
 import org.jaxen.Context;
 59  
 import org.jaxen.ContextSupport;
 60  
 import org.jaxen.JaxenException;
 61  
 import org.jaxen.function.BooleanFunction;
 62  
 
 63  
 /**
 64  
  * <p>
 65  
  * Represents the collection of predicates that follow the node-test in a
 66  
  * location path. 
 67  
  * </p>
 68  
  * 
 69  
  * <p>
 70  
  * There is no rule that the same predicate may not 
 71  
  * appear twice in an XPath expression, nor does this class enforce any such rule.
 72  
  * This is implemented more as a list than a set. However, adding the swme predicate 
 73  
  * twice should have no effect on the final result other than slowing it down.
 74  
  * </p>
 75  
  */
 76  
 public class PredicateSet implements Serializable
 77  
 {
 78  
 
 79  
     private static final long serialVersionUID = -7166491740228977853L;
 80  
     
 81  
     private List predicates;
 82  
 
 83  
     /**
 84  
      * Create a new empty predicate set.
 85  
      */
 86  
     public PredicateSet()
 87  18680
     {
 88  18680
         this.predicates = Collections.EMPTY_LIST;
 89  18680
     }
 90  
 
 91  
     /**
 92  
      * Add a predicate to the set.
 93  
      * 
 94  
      * @param predicate the predicate to be inserted
 95  
      */
 96  
     public void addPredicate(Predicate predicate)
 97  
     {
 98  1356
         if ( this.predicates == Collections.EMPTY_LIST )
 99  
         {
 100  1306
             this.predicates = new ArrayList();
 101  
         }
 102  
 
 103  1356
         this.predicates.add( predicate );
 104  1356
     }
 105  
 
 106  
     /**
 107  
      * Returns the list containing the predicates.
 108  
      * This list is live, not a copy.
 109  
      * 
 110  
      * @return a live list of predicates
 111  
      */
 112  
     public List getPredicates()
 113  
     {
 114  16154
         return this.predicates;
 115  
     }
 116  
 
 117  
     /**
 118  
      * Simplify each of the predicates in the list.
 119  
      */
 120  
     public void simplify()
 121  
     {
 122  18516
         Iterator  predIter = this.predicates.iterator();
 123  18516
         Predicate eachPred = null;
 124  
 
 125  19854
         while ( predIter.hasNext() )
 126  
         {
 127  1338
             eachPred = (Predicate) predIter.next();
 128  1338
             eachPred.simplify();
 129  1338
         }
 130  18516
     }
 131  
 
 132  
     /**
 133  
      * Returns the XPath string containing each of the predicates.
 134  
      * 
 135  
      * @return the XPath string containing each of the predicates
 136  
      */
 137  
     public String getText()
 138  
     {
 139  3748
         StringBuffer buf = new StringBuffer();
 140  
 
 141  3748
         Iterator  predIter = this.predicates.iterator();
 142  3748
         Predicate eachPred = null;
 143  
 
 144  4314
         while ( predIter.hasNext() )
 145  
         {
 146  566
             eachPred = (Predicate) predIter.next();
 147  566
             buf.append( eachPred.getText() );
 148  566
         }
 149  
 
 150  3748
         return buf.toString();
 151  
     }
 152  
 
 153  
     /**
 154  
      * <p>Returns true if any of the supplied nodes satisfy 
 155  
      * all the predicates in the set. Returns false if none of the supplied
 156  
      * nodes matches all the predicates in the set. Returns false if the 
 157  
      * node-set is empty.</p>
 158  
      * 
 159  
      * @param contextNodeSet the nodes to test against these predicates
 160  
      * @param support ????
 161  
      * @return true if any node in the contextNodeSet matches all the predicates
 162  
      * @throws JaxenException
 163  
      */
 164  
     protected boolean evaluateAsBoolean(List contextNodeSet,
 165  
                                       ContextSupport support) throws JaxenException
 166  
     {
 167  0
         return anyMatchingNode( contextNodeSet, support );
 168  
     }
 169  
 
 170  
    private boolean anyMatchingNode(List contextNodeSet, ContextSupport support)
 171  
      throws JaxenException {
 172  
         // Easy way out (necessary)
 173  0
         if (predicates.size() == 0) {
 174  0
             return false;
 175  
         }
 176  0
         Iterator predIter = predicates.iterator();
 177  
 
 178  
         // initial list to filter
 179  0
         List nodes2Filter = contextNodeSet;
 180  
         // apply all predicates
 181  0
         while(predIter.hasNext()) {
 182  0
             final int nodes2FilterSize = nodes2Filter.size();
 183  
             // Set up a dummy context with a list to hold each node
 184  0
             Context predContext = new Context(support);
 185  0
             List tempList = new ArrayList(1);
 186  0
             predContext.setNodeSet(tempList);
 187  
             // loop through the current nodes to filter and add to the
 188  
             // filtered nodes list if the predicate succeeds
 189  0
             for (int i = 0; i < nodes2FilterSize; ++i) {
 190  0
                 Object contextNode = nodes2Filter.get(i);
 191  0
                 tempList.clear();
 192  0
                 tempList.add(contextNode);
 193  0
                 predContext.setNodeSet(tempList);
 194  
                 // ????
 195  0
                 predContext.setPosition(i + 1);
 196  0
                 predContext.setSize(nodes2FilterSize);
 197  0
                 Object predResult = ((Predicate)predIter.next()).evaluate(predContext);
 198  0
                 if (predResult instanceof Number) {
 199  
                     // Here we assume nodes are in forward or reverse order
 200  
                     // as appropriate for axis
 201  0
                     int proximity = ((Number) predResult).intValue();
 202  0
                     if (proximity == (i + 1)) {
 203  0
                         return true;
 204  
                     }
 205  0
                 }
 206  
                 else {
 207  0
                     Boolean includes =
 208  
                         BooleanFunction.evaluate(predResult,
 209  
                                                 predContext.getNavigator());
 210  0
                     if (includes.booleanValue()) {
 211  0
                         return true;
 212  
                     }
 213  
                 }
 214  
             }
 215  0
         }
 216  
         
 217  0
         return false;
 218  
     }
 219  
    
 220  
     
 221  
     
 222  
     
 223  
    /**
 224  
     * <p>Returns all of the supplied nodes that satisfy 
 225  
     * all the predicates in the set. </p>
 226  
     * 
 227  
     * @param contextNodeSet the nodes to test against these predicates
 228  
     * @param support ????
 229  
     * @return all the nodes that match each of the predicates
 230  
     * @throws JaxenException
 231  
     */
 232  
    protected List evaluatePredicates(List contextNodeSet, ContextSupport support)
 233  
             throws JaxenException {
 234  
         // Easy way out (necessary)
 235  18212
         if (predicates.size() == 0) {
 236  12800
             return contextNodeSet;
 237  
         }
 238  5412
         Iterator predIter = predicates.iterator();
 239  
 
 240  
         // initial list to filter
 241  5412
         List nodes2Filter = contextNodeSet;
 242  
         // apply all predicates
 243  10846
         while(predIter.hasNext()) {
 244  5438
             nodes2Filter =
 245  
                 applyPredicate((Predicate)predIter.next(), nodes2Filter, support);
 246  5434
         }
 247  
         
 248  5408
         return nodes2Filter;
 249  
     }
 250  
    
 251  
     public List applyPredicate(Predicate predicate, List nodes2Filter, ContextSupport support)
 252  
             throws JaxenException {
 253  5438
         final int nodes2FilterSize = nodes2Filter.size();
 254  5438
         List filteredNodes = new ArrayList(nodes2FilterSize);
 255  
         // Set up a dummy context with a list to hold each node
 256  5438
         Context predContext = new Context(support);
 257  5438
         List tempList = new ArrayList(1);
 258  5438
         predContext.setNodeSet(tempList);
 259  
         // loop through the current nodes to filter and add to the
 260  
         // filtered nodes list if the predicate succeeds
 261  13316
         for (int i = 0; i < nodes2FilterSize; ++i) {
 262  7882
             Object contextNode = nodes2Filter.get(i);
 263  7882
             tempList.clear();
 264  7882
             tempList.add(contextNode);
 265  7882
             predContext.setNodeSet(tempList);
 266  
             // ????
 267  7882
             predContext.setPosition(i + 1);
 268  7882
             predContext.setSize(nodes2FilterSize);
 269  7882
             Object predResult = predicate.evaluate(predContext);
 270  7878
             if (predResult instanceof Number) {
 271  
                 // Here we assume nodes are in forward or reverse order
 272  
                 // as appropriate for axis
 273  1514
                 int proximity = ((Number) predResult).intValue();
 274  1514
                 if (proximity == (i + 1)) {
 275  322
                     filteredNodes.add(contextNode);
 276  
                 }
 277  1514
             }
 278  
             else {
 279  6364
                 Boolean includes =
 280  
                     BooleanFunction.evaluate(predResult,
 281  
                                             predContext.getNavigator());
 282  6364
                 if (includes.booleanValue()) {
 283  980
                     filteredNodes.add(contextNode);
 284  
                 }
 285  
             }
 286  
         }
 287  5434
         return filteredNodes;
 288  
     }
 289  
     
 290  
 }