View Javadoc
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       * &lt;prefix, uri&gt;. 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. */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
279     public String getDeclaredPrefixAt(int index) {
280         return fNamespace[fContext[fCurrentContext] + index * 2];
281     } // getDeclaredPrefixAt(int):String
282 
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      */
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 
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      */
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      */
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          */
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          */
411         public boolean hasNext() {
412             return (counter < size);
413         }
414 
415         /**
416          * @see java.util.Enumeration#nextElement()
417          */
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 
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 
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          */
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          */
457         public boolean hasMoreElements() {
458             return (counter< size);
459         }
460 
461         /**
462          * @see java.util.Enumeration#nextElement()
463          */
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 
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