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