1 /*
2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xpath.internal.patterns;
22 
23 import com.sun.org.apache.xml.internal.utils.QName;
24 import com.sun.org.apache.xpath.internal.Expression;
25 import com.sun.org.apache.xpath.internal.ExpressionOwner;
26 import com.sun.org.apache.xpath.internal.XPathContext;
27 import com.sun.org.apache.xpath.internal.XPathVisitor;
28 import com.sun.org.apache.xpath.internal.objects.XObject;
29 import java.util.List;
30 
31 /**
32  * This class represents a union pattern, which can have multiple individual
33  * StepPattern patterns.
34  * @xsl.usage advanced
35  * @LastModified: Oct 2017
36  */
37 public class UnionPattern extends Expression
38 {
39     static final long serialVersionUID = -6670449967116905820L;
40 
41   /** Array of the contained step patterns to be tested.
42    *  @serial  */
43   private StepPattern[] m_patterns;
44 
45   /**
46    * No arguments to process, so this does nothing.
47    */
fixupVariables(List<QName> vars, int globalsSize)48   public void fixupVariables(List<QName> vars, int globalsSize)
49   {
50     for (int i = 0; i < m_patterns.length; i++)
51     {
52       m_patterns[i].fixupVariables(vars, globalsSize);
53     }
54   }
55 
56 
57   /**
58    * Tell if this expression or it's subexpressions can traverse outside
59    * the current subtree.
60    *
61    * @return true if traversal outside the context node's subtree can occur.
62    */
canTraverseOutsideSubtree()63    public boolean canTraverseOutsideSubtree()
64    {
65      if(null != m_patterns)
66      {
67       int n = m_patterns.length;
68       for (int i = 0; i < n; i++)
69       {
70         if(m_patterns[i].canTraverseOutsideSubtree())
71           return true;
72       }
73      }
74      return false;
75    }
76 
77   /**
78    * Set the contained step patterns to be tested.
79    *
80    *
81    * @param patterns the contained step patterns to be tested.
82    */
setPatterns(StepPattern[] patterns)83   public void setPatterns(StepPattern[] patterns)
84   {
85     m_patterns = patterns;
86     if(null != patterns)
87     {
88         for(int i = 0; i < patterns.length; i++)
89         {
90                 patterns[i].exprSetParent(this);
91         }
92     }
93 
94   }
95 
96   /**
97    * Get the contained step patterns to be tested.
98    *
99    *
100    * @return an array of the contained step patterns to be tested.
101    */
getPatterns()102   public StepPattern[] getPatterns()
103   {
104     return m_patterns;
105   }
106 
107   /**
108    * Test a node to see if it matches any of the patterns in the union.
109    *
110    * @param xctxt XPath runtime context.
111    *
112    * @return {@link com.sun.org.apache.xpath.internal.patterns.NodeTest#SCORE_NODETEST},
113    *         {@link com.sun.org.apache.xpath.internal.patterns.NodeTest#SCORE_NONE},
114    *         {@link com.sun.org.apache.xpath.internal.patterns.NodeTest#SCORE_NSWILD},
115    *         {@link com.sun.org.apache.xpath.internal.patterns.NodeTest#SCORE_QNAME}, or
116    *         {@link com.sun.org.apache.xpath.internal.patterns.NodeTest#SCORE_OTHER}.
117    *
118    * @throws javax.xml.transform.TransformerException
119    */
execute(XPathContext xctxt)120   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
121   {
122 
123     XObject bestScore = null;
124     int n = m_patterns.length;
125 
126     for (int i = 0; i < n; i++)
127     {
128       XObject score = m_patterns[i].execute(xctxt);
129 
130       if (score != NodeTest.SCORE_NONE)
131       {
132         if (null == bestScore)
133           bestScore = score;
134         else if (score.num() > bestScore.num())
135           bestScore = score;
136       }
137     }
138 
139     if (null == bestScore)
140     {
141       bestScore = NodeTest.SCORE_NONE;
142     }
143 
144     return bestScore;
145   }
146 
147   class UnionPathPartOwner implements ExpressionOwner
148   {
149         int m_index;
150 
UnionPathPartOwner(int index)151         UnionPathPartOwner(int index)
152         {
153                 m_index = index;
154         }
155 
156     /**
157      * @see ExpressionOwner#getExpression()
158      */
getExpression()159     public Expression getExpression()
160     {
161       return m_patterns[m_index];
162     }
163 
164 
165     /**
166      * @see ExpressionOwner#setExpression(Expression)
167      */
setExpression(Expression exp)168     public void setExpression(Expression exp)
169     {
170         exp.exprSetParent(UnionPattern.this);
171         m_patterns[m_index] = (StepPattern)exp;
172     }
173   }
174 
175   /**
176    * @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
177    */
callVisitors(ExpressionOwner owner, XPathVisitor visitor)178   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
179   {
180         visitor.visitUnionPattern(owner, this);
181         if(null != m_patterns)
182         {
183                 int n = m_patterns.length;
184                 for(int i = 0; i < n; i++)
185                 {
186                         m_patterns[i].callVisitors(new UnionPathPartOwner(i), visitor);
187                 }
188         }
189   }
190 
191   /**
192    * @see Expression#deepEquals(Expression)
193    */
deepEquals(Expression expr)194   public boolean deepEquals(Expression expr)
195   {
196         if(!isSameClass(expr))
197                 return false;
198 
199         UnionPattern up = (UnionPattern)expr;
200 
201         if(null != m_patterns)
202         {
203                 int n = m_patterns.length;
204                 if((null == up.m_patterns) || (up.m_patterns.length != n))
205                         return false;
206 
207                 for(int i = 0; i < n; i++)
208                 {
209                         if(!m_patterns[i].deepEquals(up.m_patterns[i]))
210                                 return false;
211                 }
212         }
213         else if(up.m_patterns != null)
214                 return false;
215 
216         return true;
217 
218   }
219 
220 
221 }
222