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: UnionPattern.java 468655 2006-10-28 07:12:06Z minchau $
20 */
21package org.apache.xpath.patterns;
22
23import org.apache.xpath.Expression;
24import org.apache.xpath.ExpressionOwner;
25import org.apache.xpath.XPathContext;
26import org.apache.xpath.XPathVisitor;
27import org.apache.xpath.objects.XObject;
28
29/**
30 * This class represents a union pattern, which can have multiple individual
31 * StepPattern patterns.
32 * @xsl.usage advanced
33 */
34public class UnionPattern extends Expression
35{
36    static final long serialVersionUID = -6670449967116905820L;
37
38  /** Array of the contained step patterns to be tested.
39   *  @serial  */
40  private StepPattern[] m_patterns;
41
42  /**
43   * No arguments to process, so this does nothing.
44   */
45  public void fixupVariables(java.util.Vector vars, int globalsSize)
46  {
47    for (int i = 0; i < m_patterns.length; i++)
48    {
49      m_patterns[i].fixupVariables(vars, globalsSize);
50    }
51  }
52
53
54  /**
55   * Tell if this expression or it's subexpressions can traverse outside
56   * the current subtree.
57   *
58   * @return true if traversal outside the context node's subtree can occur.
59   */
60   public boolean canTraverseOutsideSubtree()
61   {
62     if(null != m_patterns)
63     {
64      int n = m_patterns.length;
65      for (int i = 0; i < n; i++)
66      {
67        if(m_patterns[i].canTraverseOutsideSubtree())
68          return true;
69      }
70     }
71     return false;
72   }
73
74  /**
75   * Set the contained step patterns to be tested.
76   *
77   *
78   * @param patterns the contained step patterns to be tested.
79   */
80  public void setPatterns(StepPattern[] patterns)
81  {
82    m_patterns = patterns;
83    if(null != patterns)
84    {
85    	for(int i = 0; i < patterns.length; i++)
86    	{
87    		patterns[i].exprSetParent(this);
88    	}
89    }
90
91  }
92
93  /**
94   * Get the contained step patterns to be tested.
95   *
96   *
97   * @return an array of the contained step patterns to be tested.
98   */
99  public StepPattern[] getPatterns()
100  {
101    return m_patterns;
102  }
103
104  /**
105   * Test a node to see if it matches any of the patterns in the union.
106   *
107   * @param xctxt XPath runtime context.
108   *
109   * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
110   *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
111   *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
112   *         {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
113   *         {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}.
114   *
115   * @throws javax.xml.transform.TransformerException
116   */
117  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
118  {
119
120    XObject bestScore = null;
121    int n = m_patterns.length;
122
123    for (int i = 0; i < n; i++)
124    {
125      XObject score = m_patterns[i].execute(xctxt);
126
127      if (score != NodeTest.SCORE_NONE)
128      {
129        if (null == bestScore)
130          bestScore = score;
131        else if (score.num() > bestScore.num())
132          bestScore = score;
133      }
134    }
135
136    if (null == bestScore)
137    {
138      bestScore = NodeTest.SCORE_NONE;
139    }
140
141    return bestScore;
142  }
143
144  class UnionPathPartOwner implements ExpressionOwner
145  {
146  	int m_index;
147
148  	UnionPathPartOwner(int index)
149  	{
150  		m_index = index;
151  	}
152
153    /**
154     * @see ExpressionOwner#getExpression()
155     */
156    public Expression getExpression()
157    {
158      return m_patterns[m_index];
159    }
160
161
162    /**
163     * @see ExpressionOwner#setExpression(Expression)
164     */
165    public void setExpression(Expression exp)
166    {
167    	exp.exprSetParent(UnionPattern.this);
168    	m_patterns[m_index] = (StepPattern)exp;
169    }
170  }
171
172  /**
173   * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
174   */
175  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
176  {
177  	visitor.visitUnionPattern(owner, this);
178  	if(null != m_patterns)
179  	{
180  		int n = m_patterns.length;
181  		for(int i = 0; i < n; i++)
182  		{
183  			m_patterns[i].callVisitors(new UnionPathPartOwner(i), visitor);
184  		}
185  	}
186  }
187
188  /**
189   * @see Expression#deepEquals(Expression)
190   */
191  public boolean deepEquals(Expression expr)
192  {
193  	if(!isSameClass(expr))
194  		return false;
195
196  	UnionPattern up = (UnionPattern)expr;
197
198  	if(null != m_patterns)
199  	{
200  		int n = m_patterns.length;
201  		if((null == up.m_patterns) || (up.m_patterns.length != n))
202  			return false;
203
204  		for(int i = 0; i < n; i++)
205  		{
206  			if(!m_patterns[i].deepEquals(up.m_patterns[i]))
207  				return false;
208  		}
209  	}
210  	else if(up.m_patterns != null)
211  		return false;
212
213  	return true;
214
215  }
216
217
218}
219