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    */
  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    */
  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    */
  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    */
 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    */
 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 
 151         UnionPathPartOwner(int index)
 152         {
 153                 m_index = index;
 154         }
 155 
 156     /**
 157      * @see ExpressionOwner#getExpression()
 158      */
 159     public Expression getExpression()
 160     {
 161       return m_patterns[m_index];
 162     }
 163 
 164 
 165     /**
 166      * @see ExpressionOwner#setExpression(Expression)
 167      */
 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    */
 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    */
 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 }