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 */
21package org.apache.xpath.axes;
22
23import org.apache.xml.dtm.DTMIterator;
24import org.apache.xpath.XPathContext;
25import org.apache.xpath.objects.XObject;
26import 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 */
33public 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   */
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   */
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   */
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   */
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