1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * The Apache Software License, Version 1.1 7 * 8 * 9 * Copyright (c) 2000-2002 The Apache Software Foundation. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in 21 * the documentation and/or other materials provided with the 22 * distribution. 23 * 24 * 3. The end-user documentation included with the redistribution, 25 * if any, must include the following acknowledgment: 26 * "This product includes software developed by the 27 * Apache Software Foundation (http://www.apache.org/)." 28 * Alternately, this acknowledgment may appear in the software itself, 29 * if and wherever such third-party acknowledgments normally appear. 30 * 31 * 4. The names "Xerces" and "Apache Software Foundation" must 32 * not be used to endorse or promote products derived from this 33 * software without prior written permission. For written 34 * permission, please contact apache@apache.org. 35 * 36 * 5. Products derived from this software may not be called "Apache", 37 * nor may "Apache" appear in their name, without prior written 38 * permission of the Apache Software Foundation. 39 * 40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 42 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 47 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 48 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This software consists of voluntary contributions made by many 55 * individuals on behalf of the Apache Software Foundation and was 56 * originally based on software copyright (c) 1999, International 57 * Business Machines, Inc., http://www.apache.org. For more 58 * information on the Apache Software Foundation, please see 59 * <http://www.apache.org/>. 60 */ 61 62 package com.sun.org.apache.xerces.internal.util; 63 64 import java.util.Enumeration; 65 import java.util.Iterator; 66 import java.util.NoSuchElementException; 67 import java.util.Vector; 68 69 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 70 71 /** 72 * Namespace support for XML document handlers. This class doesn't 73 * perform any error checking and assumes that all strings passed 74 * as arguments to methods are unique symbols. The SymbolTable class 75 * can be used for this purpose. 76 * 77 * @author Andy Clark, IBM 78 * 79 */ 80 public class NamespaceSupport implements NamespaceContext { 81 82 // 83 // Data 84 // 85 86 /** 87 * Namespace binding information. This array is composed of a 88 * series of tuples containing the namespace binding information: 89 * <prefix, uri>. The default size can be set to anything 90 * as long as it is a power of 2 greater than 1. 91 * 92 * @see #fNamespaceSize 93 * @see #fContext 94 */ 95 protected String[] fNamespace = new String[16 * 2]; 96 97 /** The top of the namespace information array. */ 98 protected int fNamespaceSize; 99 100 // NOTE: The constructor depends on the initial context size 101 // being at least 1. -Ac 102 103 /** 104 * Context indexes. This array contains indexes into the namespace 105 * information array. The index at the current context is the start 106 * index of declared namespace bindings and runs to the size of the 107 * namespace information array. 108 * 109 * @see #fNamespaceSize 110 */ 111 protected int[] fContext = new int[8]; 112 113 /** The current context. */ 114 protected int fCurrentContext; 115 116 protected String[] fPrefixes = new String[16]; 117 118 // 119 // Constructors 120 // 121 122 /** Default constructor. */ NamespaceSupport()123 public NamespaceSupport() { 124 } // <init>() 125 126 /** 127 * Constructs a namespace context object and initializes it with 128 * the prefixes declared in the specified context. 129 */ NamespaceSupport(NamespaceContext context)130 public NamespaceSupport(NamespaceContext context) { 131 pushContext(); 132 // copy declaration in the context 133 Enumeration prefixes = context.getAllPrefixes(); 134 while (prefixes.hasMoreElements()){ 135 String prefix = (String)prefixes.nextElement(); 136 String uri = context.getURI(prefix); 137 declarePrefix(prefix, uri); 138 } 139 } // <init>(NamespaceContext) 140 141 142 // 143 // Public methods 144 // 145 146 /** 147 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#reset() 148 */ reset()149 public void reset() { 150 151 // reset namespace and context info 152 fNamespaceSize = 0; 153 fCurrentContext = 0; 154 155 156 // bind "xml" prefix to the XML uri 157 fNamespace[fNamespaceSize++] = XMLSymbols.PREFIX_XML; 158 fNamespace[fNamespaceSize++] = NamespaceContext.XML_URI; 159 // bind "xmlns" prefix to the XMLNS uri 160 fNamespace[fNamespaceSize++] = XMLSymbols.PREFIX_XMLNS; 161 fNamespace[fNamespaceSize++] = NamespaceContext.XMLNS_URI; 162 163 fContext[fCurrentContext] = fNamespaceSize; 164 //++fCurrentContext; 165 166 } // reset(SymbolTable) 167 168 169 /** 170 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#pushContext() 171 */ pushContext()172 public void pushContext() { 173 174 // extend the array, if necessary 175 if (fCurrentContext + 1 == fContext.length) { 176 int[] contextarray = new int[fContext.length * 2]; 177 System.arraycopy(fContext, 0, contextarray, 0, fContext.length); 178 fContext = contextarray; 179 } 180 181 // push context 182 fContext[++fCurrentContext] = fNamespaceSize; 183 //System.out.println("calling push context, current context = " + fCurrentContext); 184 } // pushContext() 185 186 187 /** 188 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#popContext() 189 */ popContext()190 public void popContext() { 191 fNamespaceSize = fContext[fCurrentContext--]; 192 //System.out.println("Calling popContext, fCurrentContext = " + fCurrentContext); 193 } // popContext() 194 195 /** 196 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#declarePrefix(String, String) 197 */ declarePrefix(String prefix, String uri)198 public boolean declarePrefix(String prefix, String uri) { 199 // ignore "xml" and "xmlns" prefixes 200 if (prefix == XMLSymbols.PREFIX_XML || prefix == XMLSymbols.PREFIX_XMLNS) { 201 return false; 202 } 203 204 // see if prefix already exists in current context 205 for (int i = fNamespaceSize; i > fContext[fCurrentContext]; i -= 2) { 206 if (fNamespace[i - 2] == prefix) { 207 // REVISIT: [Q] Should the new binding override the 208 // previously declared binding or should it 209 // it be ignored? -Ac 210 // NOTE: The SAX2 "NamespaceSupport" helper allows 211 // re-bindings with the new binding overwriting 212 // the previous binding. -Ac 213 fNamespace[i - 1] = uri; 214 return true; 215 } 216 } 217 218 // resize array, if needed 219 if (fNamespaceSize == fNamespace.length) { 220 String[] namespacearray = new String[fNamespaceSize * 2]; 221 System.arraycopy(fNamespace, 0, namespacearray, 0, fNamespaceSize); 222 fNamespace = namespacearray; 223 } 224 225 // bind prefix to uri in current context 226 fNamespace[fNamespaceSize++] = prefix; 227 fNamespace[fNamespaceSize++] = uri; 228 229 return true; 230 231 } // declarePrefix(String,String):boolean 232 233 /** 234 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getURI(String) 235 */ getURI(String prefix)236 public String getURI(String prefix) { 237 238 // find prefix in current context 239 for (int i = fNamespaceSize; i > 0; i -= 2) { 240 if (fNamespace[i - 2] == prefix) { 241 return fNamespace[i - 1]; 242 } 243 } 244 245 // prefix not found 246 return null; 247 248 } // getURI(String):String 249 250 251 /** 252 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getPrefix(String) 253 */ getPrefix(String uri)254 public String getPrefix(String uri) { 255 256 // find uri in current context 257 for (int i = fNamespaceSize; i > 0; i -= 2) { 258 if (fNamespace[i - 1] == uri) { 259 if (getURI(fNamespace[i - 2]) == uri) 260 return fNamespace[i - 2]; 261 } 262 } 263 264 // uri not found 265 return null; 266 267 } // getPrefix(String):String 268 269 /** 270 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getDeclaredPrefixCount() 271 */ getDeclaredPrefixCount()272 public int getDeclaredPrefixCount() { 273 return (fNamespaceSize - fContext[fCurrentContext]) / 2; 274 } // getDeclaredPrefixCount():int 275 276 /** 277 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getDeclaredPrefixAt(int) 278 */ getDeclaredPrefixAt(int index)279 public String getDeclaredPrefixAt(int index) { 280 return fNamespace[fContext[fCurrentContext] + index * 2]; 281 } // getDeclaredPrefixAt(int):String 282 getPrefixes()283 public Iterator getPrefixes(){ 284 int count = 0; 285 if (fPrefixes.length < (fNamespace.length/2)) { 286 // resize prefix array 287 String[] prefixes = new String[fNamespaceSize]; 288 fPrefixes = prefixes; 289 } 290 String prefix = null; 291 boolean unique = true; 292 for (int i = 2; i < (fNamespaceSize-2); i += 2) { 293 prefix = fNamespace[i + 2]; 294 for (int k=0;k<count;k++){ 295 if (fPrefixes[k]==prefix){ 296 unique = false; 297 break; 298 } 299 } 300 if (unique){ 301 fPrefixes[count++] = prefix; 302 } 303 unique = true; 304 } 305 return new IteratorPrefixes(fPrefixes, count); 306 }//getPrefixes 307 /** 308 * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getAllPrefixes() 309 */ getAllPrefixes()310 public Enumeration getAllPrefixes() { 311 int count = 0; 312 if (fPrefixes.length < (fNamespace.length/2)) { 313 // resize prefix array 314 String[] prefixes = new String[fNamespaceSize]; 315 fPrefixes = prefixes; 316 } 317 String prefix = null; 318 boolean unique = true; 319 for (int i = 2; i < (fNamespaceSize-2); i += 2) { 320 prefix = fNamespace[i + 2]; 321 for (int k=0;k<count;k++){ 322 if (fPrefixes[k]==prefix){ 323 unique = false; 324 break; 325 } 326 } 327 if (unique){ 328 fPrefixes[count++] = prefix; 329 } 330 unique = true; 331 } 332 return new Prefixes(fPrefixes, count); 333 } 334 getPrefixes(String uri)335 public Vector getPrefixes(String uri){ 336 int count = 0; 337 String prefix = null; 338 boolean unique = true; 339 Vector prefixList = new Vector(); 340 for (int i = fNamespaceSize; i >0 ; i -= 2) { 341 if(fNamespace[i-1] == uri){ 342 if(!prefixList.contains(fNamespace[i-2])) 343 prefixList.add(fNamespace[i-2]); 344 } 345 } 346 return prefixList; 347 } 348 349 /* 350 * non-NamespaceContext methods 351 */ 352 353 /** 354 * Checks whether a binding or unbinding for 355 * the given prefix exists in the context. 356 * 357 * @param prefix The prefix to look up. 358 * 359 * @return true if the given prefix exists in the context 360 */ containsPrefix(String prefix)361 public boolean containsPrefix(String prefix) { 362 363 // find prefix in context 364 for (int i = fNamespaceSize; i > 0; i -= 2) { 365 if (fNamespace[i - 2] == prefix) { 366 return true; 367 } 368 } 369 370 // prefix not found 371 return false; 372 } 373 374 /** 375 * Checks whether a binding or unbinding for 376 * the given prefix exists in the current context. 377 * 378 * @param prefix The prefix to look up. 379 * 380 * @return true if the given prefix exists in the current context 381 */ containsPrefixInCurrentContext(String prefix)382 public boolean containsPrefixInCurrentContext(String prefix) { 383 384 // find prefix in current context 385 for (int i = fContext[fCurrentContext]; i < fNamespaceSize; i += 2) { 386 if (fNamespace[i] == prefix) { 387 return true; 388 } 389 } 390 391 // prefix not found 392 return false; 393 } 394 395 protected final class IteratorPrefixes implements Iterator { 396 private String[] prefixes; 397 private int counter = 0; 398 private int size = 0; 399 400 /** 401 * Constructor for Prefixes. 402 */ IteratorPrefixes(String [] prefixes, int size)403 public IteratorPrefixes(String [] prefixes, int size) { 404 this.prefixes = prefixes; 405 this.size = size; 406 } 407 408 /** 409 * @see java.util.Enumeration#hasMoreElements() 410 */ hasNext()411 public boolean hasNext() { 412 return (counter < size); 413 } 414 415 /** 416 * @see java.util.Enumeration#nextElement() 417 */ next()418 public Object next() { 419 if (counter< size){ 420 return fPrefixes[counter++]; 421 } 422 throw new NoSuchElementException("Illegal access to Namespace prefixes enumeration."); 423 } 424 toString()425 public String toString(){ 426 StringBuffer buf = new StringBuffer(); 427 for (int i=0;i<size;i++){ 428 buf.append(prefixes[i]); 429 buf.append(" "); 430 } 431 432 return buf.toString(); 433 } 434 remove()435 public void remove(){ 436 throw new UnsupportedOperationException(); 437 } 438 } 439 440 441 protected final class Prefixes implements Enumeration { 442 private String[] prefixes; 443 private int counter = 0; 444 private int size = 0; 445 446 /** 447 * Constructor for Prefixes. 448 */ Prefixes(String [] prefixes, int size)449 public Prefixes(String [] prefixes, int size) { 450 this.prefixes = prefixes; 451 this.size = size; 452 } 453 454 /** 455 * @see java.util.Enumeration#hasMoreElements() 456 */ hasMoreElements()457 public boolean hasMoreElements() { 458 return (counter< size); 459 } 460 461 /** 462 * @see java.util.Enumeration#nextElement() 463 */ nextElement()464 public Object nextElement() { 465 if (counter< size){ 466 return fPrefixes[counter++]; 467 } 468 throw new NoSuchElementException("Illegal access to Namespace prefixes enumeration."); 469 } 470 toString()471 public String toString(){ 472 StringBuffer buf = new StringBuffer(); 473 for (int i=0;i<size;i++){ 474 buf.append(prefixes[i]); 475 buf.append(" "); 476 } 477 478 return buf.toString(); 479 } 480 481 482 } 483 484 } // class NamespaceSupport 485