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: NamespaceSupport.java 1225426 2011-12-29 04:13:08Z mrglavas $
020     */
021    
022    package org.apache.xml.serializer.dom3;
023    
024    import java.util.Enumeration;
025    import java.util.NoSuchElementException;
026    
027    /**
028     * Namespace support for XML document handlers. This class doesn't 
029     * perform any error checking and assumes that all strings passed
030     * as arguments to methods are unique symbols. The SymbolTable class
031     * can be used for this purpose.
032     * 
033     * Derived from org.apache.xerces.util.NamespaceSupport
034     *
035     * @author Andy Clark, IBM
036     *
037     * @version $Id: NamespaceSupport.java 1225426 2011-12-29 04:13:08Z mrglavas $
038     */
039    public class NamespaceSupport {
040    
041            static final String PREFIX_XML = "xml".intern();
042            
043            static final String PREFIX_XMLNS = "xmlns".intern(); 
044        
045        /**
046         * The XML Namespace ("http://www.w3.org/XML/1998/namespace"). This is
047         * the Namespace URI that is automatically mapped to the "xml" prefix.
048         */
049        public final static String XML_URI = "http://www.w3.org/XML/1998/namespace".intern();
050    
051        /**
052         * XML Information Set REC
053         * all namespace attributes (including those named xmlns, 
054         * whose [prefix] property has no value) have a namespace URI of http://www.w3.org/2000/xmlns/
055         */
056        public final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/".intern();
057    
058            //
059        // Data
060        //
061    
062        /** 
063         * Namespace binding information. This array is composed of a
064         * series of tuples containing the namespace binding information:
065         * <prefix, uri>. The default size can be set to anything
066         * as long as it is a power of 2 greater than 1.
067         *
068         * @see #fNamespaceSize
069         * @see #fContext
070         */
071        protected String[] fNamespace = new String[16 * 2];
072    
073        /** The top of the namespace information array. */
074        protected int fNamespaceSize;
075    
076        // NOTE: The constructor depends on the initial context size 
077        //       being at least 1. -Ac
078    
079        /** 
080         * Context indexes. This array contains indexes into the namespace
081         * information array. The index at the current context is the start
082         * index of declared namespace bindings and runs to the size of the
083         * namespace information array.
084         *
085         * @see #fNamespaceSize
086         */
087        protected int[] fContext = new int[8];
088    
089        /** The current context. */
090        protected int fCurrentContext;
091        
092        protected String[] fPrefixes = new String[16];
093        
094        //
095        // Constructors
096        //
097    
098        /** Default constructor. */
099        public NamespaceSupport() {
100        } // <init>()
101    
102        //
103        // Public methods
104        //
105        
106            /**
107             * @see org.apache.xerces.xni.NamespaceContext#reset()
108             */
109        public void reset() {
110    
111            // reset namespace and context info
112            fNamespaceSize = 0;
113            fCurrentContext = 0;
114            fContext[fCurrentContext] = fNamespaceSize;
115    
116            // bind "xml" prefix to the XML uri
117            fNamespace[fNamespaceSize++] = PREFIX_XML;
118            fNamespace[fNamespaceSize++] = XML_URI;
119            // bind "xmlns" prefix to the XMLNS uri
120            fNamespace[fNamespaceSize++] = PREFIX_XMLNS;
121            fNamespace[fNamespaceSize++] = XMLNS_URI;
122            ++fCurrentContext;
123    
124        } // reset(SymbolTable)
125    
126    
127            /**
128             * @see org.apache.xerces.xni.NamespaceContext#pushContext()
129             */
130        public void pushContext() {
131    
132            // extend the array, if necessary
133            if (fCurrentContext + 1 == fContext.length) {
134                int[] contextarray = new int[fContext.length * 2];
135                System.arraycopy(fContext, 0, contextarray, 0, fContext.length);
136                fContext = contextarray;
137            }
138    
139            // push context
140            fContext[++fCurrentContext] = fNamespaceSize;
141    
142        } // pushContext()
143    
144    
145            /**
146             * @see org.apache.xerces.xni.NamespaceContext#popContext()
147             */
148        public void popContext() {
149            fNamespaceSize = fContext[fCurrentContext--];
150        } // popContext()
151    
152            /**
153             * @see org.apache.xerces.xni.NamespaceContext#declarePrefix(String, String)
154             */
155        public boolean declarePrefix(String prefix, String uri) {
156            // ignore "xml" and "xmlns" prefixes
157            if (prefix == PREFIX_XML || prefix == PREFIX_XMLNS) {
158                return false;
159            }
160    
161            // see if prefix already exists in current context
162            for (int i = fNamespaceSize; i > fContext[fCurrentContext]; i -= 2) {
163                //if (fNamespace[i - 2] == prefix) {
164                    if (fNamespace[i - 2].equals(prefix) )  {
165                    // REVISIT: [Q] Should the new binding override the
166                    //          previously declared binding or should it
167                    //          it be ignored? -Ac
168                    // NOTE:    The SAX2 "NamespaceSupport" helper allows
169                    //          re-bindings with the new binding overwriting
170                    //          the previous binding. -Ac
171                    fNamespace[i - 1] = uri;
172                    return true;
173                }
174            }
175    
176            // resize array, if needed
177            if (fNamespaceSize == fNamespace.length) {
178                String[] namespacearray = new String[fNamespaceSize * 2];
179                System.arraycopy(fNamespace, 0, namespacearray, 0, fNamespaceSize);
180                fNamespace = namespacearray;
181            }
182    
183            // bind prefix to uri in current context
184            fNamespace[fNamespaceSize++] = prefix;
185            fNamespace[fNamespaceSize++] = uri;
186    
187            return true;
188    
189        } // declarePrefix(String,String):boolean
190    
191            /**
192             * @see org.apache.xerces.xni.NamespaceContext#getURI(String)
193             */
194        public String getURI(String prefix) {
195            
196            // find prefix in current context
197            for (int i = fNamespaceSize; i > 0; i -= 2) {
198                //if (fNamespace[i - 2] == prefix) {
199                    if (fNamespace[i - 2].equals(prefix) ) {
200                    return fNamespace[i - 1];
201                }
202            }
203    
204            // prefix not found
205            return null;
206    
207        } // getURI(String):String
208    
209    
210            /**
211             * @see org.apache.xerces.xni.NamespaceContext#getPrefix(String)
212             */
213        public String getPrefix(String uri) {
214    
215            // find uri in current context
216            for (int i = fNamespaceSize; i > 0; i -= 2) {
217                //if (fNamespace[i - 1] == uri) {
218                    if (fNamespace[i - 1].equals(uri) ) {
219                    //if (getURI(fNamespace[i - 2]) == uri)
220                            if (getURI(fNamespace[i - 2]).equals(uri) )
221                        return fNamespace[i - 2];
222                }
223            }
224    
225            // uri not found
226            return null;
227    
228        } // getPrefix(String):String
229    
230    
231            /**
232             * @see org.apache.xerces.xni.NamespaceContext#getDeclaredPrefixCount()
233             */
234        public int getDeclaredPrefixCount() {
235            return (fNamespaceSize - fContext[fCurrentContext]) / 2;
236        } // getDeclaredPrefixCount():int
237    
238            /**
239             * @see org.apache.xerces.xni.NamespaceContext#getDeclaredPrefixAt(int)
240             */
241        public String getDeclaredPrefixAt(int index) {
242            return fNamespace[fContext[fCurrentContext] + index * 2];
243        } // getDeclaredPrefixAt(int):String
244    
245            /**
246             * @see org.apache.xerces.xni.NamespaceContext#getAllPrefixes()
247             */
248            public Enumeration getAllPrefixes() {
249            int count = 0;
250            if (fPrefixes.length < (fNamespace.length/2)) {
251                // resize prefix array          
252                String[] prefixes = new String[fNamespaceSize];
253                fPrefixes = prefixes;
254            }
255            String prefix = null;
256            boolean unique = true;
257            for (int i = 2; i < (fNamespaceSize-2); i += 2) {
258                prefix = fNamespace[i + 2];            
259                for (int k=0;k<count;k++){
260                    if (fPrefixes[k]==prefix){
261                        unique = false;
262                        break;
263                    }               
264                }
265                if (unique){
266                    fPrefixes[count++] = prefix;
267                }
268                unique = true;
269            }
270                    return new Prefixes(fPrefixes, count);
271            }
272        
273        protected final class Prefixes implements Enumeration {
274            private String[] prefixes;
275            private int counter = 0;
276            private int size = 0;
277                   
278                    /**
279                     * Constructor for Prefixes.
280                     */
281                    public Prefixes(String [] prefixes, int size) {
282                            this.prefixes = prefixes;
283                this.size = size;
284                    }
285    
286           /**
287                     * @see java.util.Enumeration#hasMoreElements()
288                     */
289                    public boolean hasMoreElements() {           
290                            return (counter< size);
291                    }
292    
293                    /**
294                     * @see java.util.Enumeration#nextElement()
295                     */
296                    public Object nextElement() {
297                if (counter< size){
298                    return fPrefixes[counter++];
299                }
300                            throw new NoSuchElementException("Illegal access to Namespace prefixes enumeration.");
301                    }
302            
303            public String toString(){
304                StringBuffer buf = new StringBuffer();
305                for (int i=0;i<size;i++){
306                    buf.append(prefixes[i]);
307                    buf.append(" ");
308                }
309                    
310                return buf.toString(); 
311            }
312    
313    }
314    
315    } // class NamespaceSupport