001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: UnionPattern.java 468655 2006-10-28 07:12:06Z minchau $
020     */
021    package org.apache.xpath.patterns;
022    
023    import org.apache.xpath.Expression;
024    import org.apache.xpath.ExpressionOwner;
025    import org.apache.xpath.XPathContext;
026    import org.apache.xpath.XPathVisitor;
027    import org.apache.xpath.objects.XObject;
028    
029    /**
030     * This class represents a union pattern, which can have multiple individual 
031     * StepPattern patterns.
032     * @xsl.usage advanced
033     */
034    public class UnionPattern extends Expression
035    {
036        static final long serialVersionUID = -6670449967116905820L;
037    
038      /** Array of the contained step patterns to be tested.
039       *  @serial  */
040      private StepPattern[] m_patterns;
041      
042      /**
043       * No arguments to process, so this does nothing.
044       */
045      public void fixupVariables(java.util.Vector vars, int globalsSize)
046      {
047        for (int i = 0; i < m_patterns.length; i++) 
048        {
049          m_patterns[i].fixupVariables(vars, globalsSize);
050        }
051      }
052    
053      
054      /**
055       * Tell if this expression or it's subexpressions can traverse outside 
056       * the current subtree.
057       * 
058       * @return true if traversal outside the context node's subtree can occur.
059       */
060       public boolean canTraverseOutsideSubtree()
061       {
062         if(null != m_patterns)
063         {
064          int n = m_patterns.length;
065          for (int i = 0; i < n; i++) 
066          {
067            if(m_patterns[i].canTraverseOutsideSubtree())
068              return true;
069          }
070         }
071         return false;
072       }
073    
074      /**
075       * Set the contained step patterns to be tested. 
076       *
077       *
078       * @param patterns the contained step patterns to be tested. 
079       */
080      public void setPatterns(StepPattern[] patterns)
081      {
082        m_patterns = patterns;
083        if(null != patterns)
084        {
085            for(int i = 0; i < patterns.length; i++)
086            {
087                    patterns[i].exprSetParent(this);
088            }
089        }
090        
091      }
092    
093      /**
094       * Get the contained step patterns to be tested. 
095       *
096       *
097       * @return an array of the contained step patterns to be tested. 
098       */
099      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    }