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