1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xpath.internal.axes;
  22 
  23 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  24 import com.sun.org.apache.xml.internal.utils.QName;
  25 import com.sun.org.apache.xpath.internal.XPathContext;
  26 import com.sun.org.apache.xpath.internal.objects.XObject;
  27 import com.sun.org.apache.xpath.internal.patterns.NodeTest;
  28 import java.util.List;
  29 
  30 /**
  31  * This class defines a simplified type of union iterator that only
  32  * tests along the child axes.  If the conditions are right, it is
  33  * much faster than using a UnionPathIterator.
  34  *
  35  * @LastModified: Oct 2017
  36  */
  37 public class UnionChildIterator extends ChildTestIterator
  38 {
  39     static final long serialVersionUID = 3500298482193003495L;
  40   /**
  41    * Even though these may hold full LocPathIterators, this array does
  42    * not have to be cloned, since only the node test and predicate
  43    * portion are used, and these only need static information.  However,
  44    * also note that index predicates can not be used!
  45    */
  46   private PredicatedNodeTest[] m_nodeTests = null;
  47 
  48   /**
  49    * Constructor for UnionChildIterator
  50    */
  51   public UnionChildIterator()
  52   {
  53     super(null);
  54   }
  55 
  56   /**
  57    * Add a node test to the union list.
  58    *
  59    * @param test reference to a NodeTest, which will be added
  60    * directly to the list of node tests (in other words, it will
  61    * not be cloned).  The parent of this test will be set to
  62    * this object.
  63    */
  64   public void addNodeTest(PredicatedNodeTest test)
  65   {
  66 
  67     // Increase array size by only 1 at a time.  Fix this
  68     // if it looks to be a problem.
  69     if (null == m_nodeTests)
  70     {
  71       m_nodeTests = new PredicatedNodeTest[1];
  72       m_nodeTests[0] = test;
  73     }
  74     else
  75     {
  76       PredicatedNodeTest[] tests = m_nodeTests;
  77       int len = m_nodeTests.length;
  78 
  79       m_nodeTests = new PredicatedNodeTest[len + 1];
  80 
  81       System.arraycopy(tests, 0, m_nodeTests, 0, len);
  82 
  83       m_nodeTests[len] = test;
  84     }
  85     test.exprSetParent(this);
  86   }
  87 
  88   /**
  89    * This function is used to fixup variables from QNames to stack frame
  90    * indexes at stylesheet build time.
  91    * @param vars List of QNames that correspond to variables.  This list
  92    * should be searched backwards for the first qualified name that
  93    * corresponds to the variable reference qname.  The position of the
  94    * QName in the vector from the start of the vector will be its position
  95    * in the stack frame (but variables above the globalsTop value will need
  96    * to be offset to the current stack frame).
  97    */
  98   public void fixupVariables(List<QName> vars, int globalsSize)
  99   {
 100     super.fixupVariables(vars, globalsSize);
 101     if (m_nodeTests != null) {
 102       for (int i = 0; i < m_nodeTests.length; i++) {
 103         m_nodeTests[i].fixupVariables(vars, globalsSize);
 104       }
 105     }
 106   }
 107 
 108   /**
 109    * Test whether a specified node is visible in the logical view of a
 110    * TreeWalker or NodeIterator. This function will be called by the
 111    * implementation of TreeWalker and NodeIterator; it is not intended to
 112    * be called directly from user code.
 113    * @param n  The node to check to see if it passes the filter or not.
 114    * @return  a constant to determine whether the node is accepted,
 115    *   rejected, or skipped, as defined  above .
 116    */
 117   public short acceptNode(int n)
 118   {
 119     XPathContext xctxt = getXPathContext();
 120     try
 121     {
 122       xctxt.pushCurrentNode(n);
 123       for (int i = 0; i < m_nodeTests.length; i++)
 124       {
 125         PredicatedNodeTest pnt = m_nodeTests[i];
 126         XObject score = pnt.execute(xctxt, n);
 127         if (score != NodeTest.SCORE_NONE)
 128         {
 129           // Note that we are assuming there are no positional predicates!
 130           if (pnt.getPredicateCount() > 0)
 131           {
 132             if (pnt.executePredicates(n, xctxt))
 133               return DTMIterator.FILTER_ACCEPT;
 134           }
 135           else
 136             return DTMIterator.FILTER_ACCEPT;
 137 
 138         }
 139       }
 140     }
 141     catch (javax.xml.transform.TransformerException se)
 142     {
 143 
 144       // TODO: Fix this.
 145       throw new RuntimeException(se.getMessage());
 146     }
 147     finally
 148     {
 149       xctxt.popCurrentNode();
 150     }
 151     return DTMIterator.FILTER_SKIP;
 152   }
 153 
 154 }