001    // NamespaceSupport.java - generic Namespace support for SAX.
002    // http://www.saxproject.org
003    // Written by David Megginson
004    // This class is in the Public Domain.  NO WARRANTY!
005    // $Id: NamespaceSupport.java,v 1.1 2004/12/23 22:38:42 mark Exp $
006    
007    package org.xml.sax.helpers;
008    
009    import java.util.EmptyStackException;
010    import java.util.Enumeration;
011    import java.util.Hashtable;
012    import java.util.Vector;
013    
014    
015    /**
016     * Encapsulate Namespace logic for use by applications using SAX,
017     * or internally by SAX drivers.
018     *
019     * <blockquote>
020     * <em>This module, both source code and documentation, is in the
021     * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
022     * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
023     * for further information.
024     * </blockquote>
025     *
026     * <p>This class encapsulates the logic of Namespace processing: it
027     * tracks the declarations currently in force for each context and
028     * automatically processes qualified XML names into their Namespace
029     * parts; it can also be used in reverse for generating XML qnames
030     * from Namespaces.</p>
031     *
032     * <p>Namespace support objects are reusable, but the reset method
033     * must be invoked between each session.</p>
034     *
035     * <p>Here is a simple session:</p>
036     *
037     * <pre>
038     * String parts[] = new String[3];
039     * NamespaceSupport support = new NamespaceSupport();
040     *
041     * support.pushContext();
042     * support.declarePrefix("", "http://www.w3.org/1999/xhtml");
043     * support.declarePrefix("dc", "http://www.purl.org/dc#");
044     *
045     * parts = support.processName("p", parts, false);
046     * System.out.println("Namespace URI: " + parts[0]);
047     * System.out.println("Local name: " + parts[1]);
048     * System.out.println("Raw name: " + parts[2]);
049     *
050     * parts = support.processName("dc:title", parts, false);
051     * System.out.println("Namespace URI: " + parts[0]);
052     * System.out.println("Local name: " + parts[1]);
053     * System.out.println("Raw name: " + parts[2]);
054     *
055     * support.popContext();
056     * </pre>
057     *
058     * <p>Note that this class is optimized for the use case where most
059     * elements do not contain Namespace declarations: if the same
060     * prefix/URI mapping is repeated for each context (for example), this
061     * class will be somewhat less efficient.</p>
062     *
063     * <p>Although SAX drivers (parsers) may choose to use this class to
064     * implement namespace handling, they are not required to do so.
065     * Applications must track namespace information themselves if they
066     * want to use namespace information.
067     *
068     * @since SAX 2.0
069     * @author David Megginson
070     * @version 2.0.1 (sax2r2)
071     */
072    public class NamespaceSupport
073    {
074    
075    
076        ////////////////////////////////////////////////////////////////////
077        // Constants.
078        ////////////////////////////////////////////////////////////////////
079    
080    
081        /**
082         * The XML Namespace URI as a constant.
083         * The value is <code>http://www.w3.org/XML/1998/namespace</code>
084         * as defined in the "Namespaces in XML" * recommendation.
085         *
086         * <p>This is the Namespace URI that is automatically mapped
087         * to the "xml" prefix.</p>
088         */
089        public final static String XMLNS =
090            "http://www.w3.org/XML/1998/namespace";
091    
092    
093        /**
094         * The namespace declaration URI as a constant.
095         * The value is <code>http://www.w3.org/xmlns/2000/</code>, as defined
096         * in a backwards-incompatible erratum to the "Namespaces in XML"
097         * recommendation.  Because that erratum postdated SAX2, SAX2 defaults 
098         * to the original recommendation, and does not normally use this URI.
099         * 
100         *
101         * <p>This is the Namespace URI that is optionally applied to
102         * <em>xmlns</em> and <em>xmlns:*</em> attributes, which are used to
103         * declare namespaces.  </p>
104         *
105         * @since SAX 2.1alpha
106         * @see #setNamespaceDeclUris
107         * @see #isNamespaceDeclUris
108         */
109        public final static String NSDECL =
110            "http://www.w3.org/xmlns/2000/";
111    
112    
113        /**
114         * An empty enumeration.
115         */
116        private final static Enumeration EMPTY_ENUMERATION =
117            new Vector().elements();
118    
119    
120        ////////////////////////////////////////////////////////////////////
121        // Constructor.
122        ////////////////////////////////////////////////////////////////////
123    
124    
125        /**
126         * Create a new Namespace support object.
127         */
128        public NamespaceSupport ()
129        {
130            reset();
131        }
132    
133    
134    
135        ////////////////////////////////////////////////////////////////////
136        // Context management.
137        ////////////////////////////////////////////////////////////////////
138    
139    
140        /**
141         * Reset this Namespace support object for reuse.
142         *
143         * <p>It is necessary to invoke this method before reusing the
144         * Namespace support object for a new session.  If namespace
145         * declaration URIs are to be supported, that flag must also
146         * be set to a non-default value.
147         * </p>
148         *
149         * @see #setNamespaceDeclUris
150         */
151        public void reset ()
152        {
153            contexts = new Context[32];
154            namespaceDeclUris = false;
155            contextPos = 0;
156            contexts[contextPos] = currentContext = new Context();
157            currentContext.declarePrefix("xml", XMLNS);
158        }
159    
160    
161        /**
162         * Start a new Namespace context.
163         * The new context will automatically inherit
164         * the declarations of its parent context, but it will also keep
165         * track of which declarations were made within this context.
166         *
167         * <p>Event callback code should start a new context once per element.
168         * This means being ready to call this in either of two places.
169         * For elements that don't include namespace declarations, the
170         * <em>ContentHandler.startElement()</em> callback is the right place.
171         * For elements with such a declaration, it'd done in the first
172         * <em>ContentHandler.startPrefixMapping()</em> callback.
173         * A boolean flag can be used to
174         * track whether a context has been started yet.  When either of
175         * those methods is called, it checks the flag to see if a new context
176         * needs to be started.  If so, it starts the context and sets the
177         * flag.  After <em>ContentHandler.startElement()</em>
178         * does that, it always clears the flag.
179         *
180         * <p>Normally, SAX drivers would push a new context at the beginning
181         * of each XML element.  Then they perform a first pass over the
182         * attributes to process all namespace declarations, making
183         * <em>ContentHandler.startPrefixMapping()</em> callbacks.
184         * Then a second pass is made, to determine the namespace-qualified
185         * names for all attributes and for the element name.
186         * Finally all the information for the
187         * <em>ContentHandler.startElement()</em> callback is available,
188         * so it can then be made.
189         *
190         * <p>The Namespace support object always starts with a base context
191         * already in force: in this context, only the "xml" prefix is
192         * declared.</p>
193         *
194         * @see org.xml.sax.ContentHandler
195         * @see #popContext
196         */
197        public void pushContext ()
198        {
199            int max = contexts.length;
200    
201            contexts [contextPos].declsOK = false;
202            contextPos++;
203    
204                                    // Extend the array if necessary
205            if (contextPos >= max) {
206                Context newContexts[] = new Context[max*2];
207                System.arraycopy(contexts, 0, newContexts, 0, max);
208                max *= 2;
209                contexts = newContexts;
210            }
211    
212                                    // Allocate the context if necessary.
213            currentContext = contexts[contextPos];
214            if (currentContext == null) {
215                contexts[contextPos] = currentContext = new Context();
216            }
217    
218                                    // Set the parent, if any.
219            if (contextPos > 0) {
220                currentContext.setParent(contexts[contextPos - 1]);
221            }
222        }
223    
224    
225        /**
226         * Revert to the previous Namespace context.
227         *
228         * <p>Normally, you should pop the context at the end of each
229         * XML element.  After popping the context, all Namespace prefix
230         * mappings that were previously in force are restored.</p>
231         *
232         * <p>You must not attempt to declare additional Namespace
233         * prefixes after popping a context, unless you push another
234         * context first.</p>
235         *
236         * @see #pushContext
237         */
238        public void popContext ()
239        {
240            contexts[contextPos].clear();
241            contextPos--;
242            if (contextPos < 0) {
243                throw new EmptyStackException();
244            }
245            currentContext = contexts[contextPos];
246        }
247    
248    
249    
250        ////////////////////////////////////////////////////////////////////
251        // Operations within a context.
252        ////////////////////////////////////////////////////////////////////
253    
254    
255        /**
256         * Declare a Namespace prefix.  All prefixes must be declared
257         * before they are referenced.  For example, a SAX driver (parser)
258         * would scan an element's attributes
259         * in two passes:  first for namespace declarations,
260         * then a second pass using {@link #processName processName()} to
261         * interpret prefixes against (potentially redefined) prefixes.
262         *
263         * <p>This method declares a prefix in the current Namespace
264         * context; the prefix will remain in force until this context
265         * is popped, unless it is shadowed in a descendant context.</p>
266         *
267         * <p>To declare the default element Namespace, use the empty string as
268         * the prefix.</p>
269         *
270         * <p>Note that you must <em>not</em> declare a prefix after
271         * you've pushed and popped another Namespace context, or
272         * treated the declarations phase as complete by processing
273         * a prefixed name.</p>
274         *
275         * <p>Note that there is an asymmetry in this library: {@link
276         * #getPrefix getPrefix} will not return the "" prefix,
277         * even if you have declared a default element namespace.
278         * To check for a default namespace,
279         * you have to look it up explicitly using {@link #getURI getURI}.
280         * This asymmetry exists to make it easier to look up prefixes
281         * for attribute names, where the default prefix is not allowed.</p>
282         *
283         * @param prefix The prefix to declare, or the empty string to
284         *  indicate the default element namespace.  This may never have
285         *  the value "xml" or "xmlns".
286         * @param uri The Namespace URI to associate with the prefix.
287         * @return true if the prefix was legal, false otherwise
288         *
289         * @see #processName
290         * @see #getURI
291         * @see #getPrefix
292         */
293        public boolean declarePrefix (String prefix, String uri)
294        {
295            if (prefix.equals("xml") || prefix.equals("xmlns")) {
296                return false;
297            } else {
298                currentContext.declarePrefix(prefix, uri);
299                return true;
300            }
301        }
302    
303    
304        /**
305         * Process a raw XML qualified name, after all declarations in the
306         * current context have been handled by {@link #declarePrefix
307         * declarePrefix()}.
308         *
309         * <p>This method processes a raw XML qualified name in the
310         * current context by removing the prefix and looking it up among
311         * the prefixes currently declared.  The return value will be the
312         * array supplied by the caller, filled in as follows:</p>
313         *
314         * <dl>
315         * <dt>parts[0]</dt>
316         * <dd>The Namespace URI, or an empty string if none is
317         *  in use.</dd>
318         * <dt>parts[1]</dt>
319         * <dd>The local name (without prefix).</dd>
320         * <dt>parts[2]</dt>
321         * <dd>The original raw name.</dd>
322         * </dl>
323         *
324         * <p>All of the strings in the array will be internalized.  If
325         * the raw name has a prefix that has not been declared, then
326         * the return value will be null.</p>
327         *
328         * <p>Note that attribute names are processed differently than
329         * element names: an unprefixed element name will receive the
330         * default Namespace (if any), while an unprefixed attribute name
331         * will not.</p>
332         *
333         * @param qName The XML qualified name to be processed.
334         * @param parts An array supplied by the caller, capable of
335         *        holding at least three members.
336         * @param isAttribute A flag indicating whether this is an
337         *        attribute name (true) or an element name (false).
338         * @return The supplied array holding three internalized strings 
339         *        representing the Namespace URI (or empty string), the
340         *        local name, and the XML qualified name; or null if there
341         *        is an undeclared prefix.
342         * @see #declarePrefix
343         * @see java.lang.String#intern */
344        public String [] processName (String qName, String parts[],
345                                      boolean isAttribute)
346        {
347            String myParts[] = currentContext.processName(qName, isAttribute);
348            if (myParts == null) {
349                return null;
350            } else {
351                parts[0] = myParts[0];
352                parts[1] = myParts[1];
353                parts[2] = myParts[2];
354                return parts;
355            }
356        }
357    
358    
359        /**
360         * Look up a prefix and get the currently-mapped Namespace URI.
361         *
362         * <p>This method looks up the prefix in the current context.
363         * Use the empty string ("") for the default Namespace.</p>
364         *
365         * @param prefix The prefix to look up.
366         * @return The associated Namespace URI, or null if the prefix
367         *         is undeclared in this context.
368         * @see #getPrefix
369         * @see #getPrefixes
370         */
371        public String getURI (String prefix)
372        {
373            return currentContext.getURI(prefix);
374        }
375    
376    
377        /**
378         * Return an enumeration of all prefixes whose declarations are
379         * active in the current context.
380         * This includes declarations from parent contexts that have
381         * not been overridden.
382         *
383         * <p><strong>Note:</strong> if there is a default prefix, it will not be
384         * returned in this enumeration; check for the default prefix
385         * using the {@link #getURI getURI} with an argument of "".</p>
386         *
387         * @return An enumeration of prefixes (never empty).
388         * @see #getDeclaredPrefixes
389         * @see #getURI
390         */
391        public Enumeration getPrefixes ()
392        {
393            return currentContext.getPrefixes();
394        }
395    
396    
397        /**
398         * Return one of the prefixes mapped to a Namespace URI.
399         *
400         * <p>If more than one prefix is currently mapped to the same
401         * URI, this method will make an arbitrary selection; if you
402         * want all of the prefixes, use the {@link #getPrefixes}
403         * method instead.</p>
404         *
405         * <p><strong>Note:</strong> this will never return the empty (default) prefix;
406         * to check for a default prefix, use the {@link #getURI getURI}
407         * method with an argument of "".</p>
408         *
409         * @param uri the namespace URI
410         * @return one of the prefixes currently mapped to the URI supplied,
411         *         or null if none is mapped or if the URI is assigned to
412         *         the default namespace
413         * @see #getPrefixes(java.lang.String)
414         * @see #getURI
415         */
416        public String getPrefix (String uri)
417        {
418            return currentContext.getPrefix(uri);
419        }
420    
421    
422        /**
423         * Return an enumeration of all prefixes for a given URI whose
424         * declarations are active in the current context.
425         * This includes declarations from parent contexts that have
426         * not been overridden.
427         *
428         * <p>This method returns prefixes mapped to a specific Namespace
429         * URI.  The xml: prefix will be included.  If you want only one
430         * prefix that's mapped to the Namespace URI, and you don't care 
431         * which one you get, use the {@link #getPrefix getPrefix}
432         *  method instead.</p>
433         *
434         * <p><strong>Note:</strong> the empty (default) prefix is <em>never</em> included
435         * in this enumeration; to check for the presence of a default
436         * Namespace, use the {@link #getURI getURI} method with an
437         * argument of "".</p>
438         *
439         * @param uri The Namespace URI.
440         * @return An enumeration of prefixes (never empty).
441         * @see #getPrefix
442         * @see #getDeclaredPrefixes
443         * @see #getURI
444         */
445        public Enumeration getPrefixes (String uri)
446        {
447            Vector prefixes = new Vector();
448            Enumeration allPrefixes = getPrefixes();
449            while (allPrefixes.hasMoreElements()) {
450                String prefix = (String)allPrefixes.nextElement();
451                if (uri.equals(getURI(prefix))) {
452                    prefixes.addElement(prefix);
453                }
454            }
455            return prefixes.elements();
456        }
457    
458    
459        /**
460         * Return an enumeration of all prefixes declared in this context.
461         *
462         * <p>The empty (default) prefix will be included in this 
463         * enumeration; note that this behaviour differs from that of
464         * {@link #getPrefix} and {@link #getPrefixes}.</p>
465         *
466         * @return An enumeration of all prefixes declared in this
467         *         context.
468         * @see #getPrefixes
469         * @see #getURI
470         */
471        public Enumeration getDeclaredPrefixes ()
472        {
473            return currentContext.getDeclaredPrefixes();
474        }
475    
476        /**
477         * Controls whether namespace declaration attributes are placed
478         * into the {@link #NSDECL NSDECL} namespace
479         * by {@link #processName processName()}.  This may only be
480         * changed before any contexts have been pushed.
481         *
482         * @since SAX 2.1alpha
483         *
484         * @exception IllegalStateException when attempting to set this
485         *  after any context has been pushed.
486         */
487        public void setNamespaceDeclUris (boolean value)
488        {
489            if (contextPos != 0)
490                throw new IllegalStateException ();
491            if (value == namespaceDeclUris)
492                return;
493            namespaceDeclUris = value;
494            if (value)
495                currentContext.declarePrefix ("xmlns", NSDECL);
496            else {
497                contexts[contextPos] = currentContext = new Context();
498                currentContext.declarePrefix("xml", XMLNS);
499            }
500        }
501    
502        /**
503         * Returns true if namespace declaration attributes are placed into
504         * a namespace.  This behavior is not the default.
505         *
506         * @since SAX 2.1alpha
507         */
508        public boolean isNamespaceDeclUris ()
509            { return namespaceDeclUris; }
510    
511    
512    
513        ////////////////////////////////////////////////////////////////////
514        // Internal state.
515        ////////////////////////////////////////////////////////////////////
516    
517        private Context contexts[];
518        private Context currentContext;
519        private int contextPos;
520        private boolean namespaceDeclUris;
521    
522    
523        ////////////////////////////////////////////////////////////////////
524        // Internal classes.
525        ////////////////////////////////////////////////////////////////////
526    
527        /**
528         * Internal class for a single Namespace context.
529         *
530         * <p>This module caches and reuses Namespace contexts,
531         * so the number allocated
532         * will be equal to the element depth of the document, not to the total
533         * number of elements (i.e. 5-10 rather than tens of thousands).
534         * Also, data structures used to represent contexts are shared when
535         * possible (child contexts without declarations) to further reduce
536         * the amount of memory that's consumed.
537         * </p>
538         */
539        final class Context {
540    
541            /**
542             * Create the root-level Namespace context.
543             */
544            Context ()
545            {
546                copyTables();
547            }
548            
549            
550            /**
551             * (Re)set the parent of this Namespace context.
552             * The context must either have been freshly constructed,
553             * or must have been cleared.
554             *
555             * @param context The parent Namespace context object.
556             */
557            void setParent (Context parent)
558            {
559                this.parent = parent;
560                declarations = null;
561                prefixTable = parent.prefixTable;
562                uriTable = parent.uriTable;
563                elementNameTable = parent.elementNameTable;
564                attributeNameTable = parent.attributeNameTable;
565                defaultNS = parent.defaultNS;
566                declSeen = false;
567                declsOK = true;
568            }
569    
570            /**
571             * Makes associated state become collectible,
572             * invalidating this context.
573             * {@link #setParent} must be called before
574             * this context may be used again.
575             */
576            void clear ()
577            {
578                parent = null;
579                prefixTable = null;
580                uriTable = null;
581                elementNameTable = null;
582                attributeNameTable = null;
583                defaultNS = null;
584            }
585            
586            
587            /**
588             * Declare a Namespace prefix for this context.
589             *
590             * @param prefix The prefix to declare.
591             * @param uri The associated Namespace URI.
592             * @see org.xml.sax.helpers.NamespaceSupport#declarePrefix
593             */
594            void declarePrefix (String prefix, String uri)
595            {
596                                    // Lazy processing...
597                if (!declsOK)
598                    throw new IllegalStateException (
599                        "can't declare any more prefixes in this context");
600                if (!declSeen) {
601                    copyTables();
602                }
603                if (declarations == null) {
604                    declarations = new Vector();
605                }
606                
607                prefix = prefix.intern();
608                uri = uri.intern();
609                if ("".equals(prefix)) {
610                    if ("".equals(uri)) {
611                        defaultNS = null;
612                    } else {
613                        defaultNS = uri;
614                    }
615                } else {
616                    prefixTable.put(prefix, uri);
617                    uriTable.put(uri, prefix); // may wipe out another prefix
618                }
619                declarations.addElement(prefix);
620            }
621    
622    
623            /**
624             * Process an XML qualified name in this context.
625             *
626             * @param qName The XML qualified name.
627             * @param isAttribute true if this is an attribute name.
628             * @return An array of three strings containing the
629             *         URI part (or empty string), the local part,
630             *         and the raw name, all internalized, or null
631             *         if there is an undeclared prefix.
632             * @see org.xml.sax.helpers.NamespaceSupport#processName
633             */
634            String [] processName (String qName, boolean isAttribute)
635            {
636                String name[];
637                Hashtable table;
638                
639                                    // detect errors in call sequence
640                declsOK = false;
641    
642                                    // Select the appropriate table.
643                if (isAttribute) {
644                    table = attributeNameTable;
645                } else {
646                    table = elementNameTable;
647                }
648                
649                                    // Start by looking in the cache, and
650                                    // return immediately if the name
651                                    // is already known in this content
652                name = (String[])table.get(qName);
653                if (name != null) {
654                    return name;
655                }
656                
657                                    // We haven't seen this name in this
658                                    // context before.  Maybe in the parent
659                                    // context, but we can't assume prefix
660                                    // bindings are the same.
661                name = new String[3];
662                name[2] = qName.intern();
663                int index = qName.indexOf(':');
664                
665                
666                                    // No prefix.
667                if (index == -1) {
668                    if (isAttribute) {
669                        if (qName == "xmlns" && namespaceDeclUris)
670                            name[0] = NSDECL;
671                        else
672                            name[0] = "";
673                    } else if (defaultNS == null) {
674                        name[0] = "";
675                    } else {
676                        name[0] = defaultNS;
677                    }
678                    name[1] = name[2];
679                }
680                
681                                    // Prefix
682                else {
683                    String prefix = qName.substring(0, index);
684                    String local = qName.substring(index+1);
685                    String uri;
686                    if ("".equals(prefix)) {
687                        uri = defaultNS;
688                    } else {
689                        uri = (String)prefixTable.get(prefix);
690                    }
691                    if (uri == null
692                            || (!isAttribute && "xmlns".equals (prefix))) {
693                        return null;
694                    }
695                    name[0] = uri;
696                    name[1] = local.intern();
697                }
698                
699                                    // Save in the cache for future use.
700                                    // (Could be shared with parent context...)
701                table.put(name[2], name);
702                return name;
703            }
704            
705    
706            /**
707             * Look up the URI associated with a prefix in this context.
708             *
709             * @param prefix The prefix to look up.
710             * @return The associated Namespace URI, or null if none is
711             *         declared.    
712             * @see org.xml.sax.helpers.NamespaceSupport#getURI
713             */
714            String getURI (String prefix)
715            {
716                if ("".equals(prefix)) {
717                    return defaultNS;
718                } else if (prefixTable == null) {
719                    return null;
720                } else {
721                    return (String)prefixTable.get(prefix);
722                }
723            }
724    
725    
726            /**
727             * Look up one of the prefixes associated with a URI in this context.
728             *
729             * <p>Since many prefixes may be mapped to the same URI,
730             * the return value may be unreliable.</p>
731             *
732             * @param uri The URI to look up.
733             * @return The associated prefix, or null if none is declared.
734             * @see org.xml.sax.helpers.NamespaceSupport#getPrefix
735             */
736            String getPrefix (String uri)
737            {
738                if (uriTable == null) {
739                    return null;
740                } else {
741                    return (String)uriTable.get(uri);
742                }
743            }
744            
745            
746            /**
747             * Return an enumeration of prefixes declared in this context.
748             *
749             * @return An enumeration of prefixes (possibly empty).
750             * @see org.xml.sax.helpers.NamespaceSupport#getDeclaredPrefixes
751             */
752            Enumeration getDeclaredPrefixes ()
753            {
754                if (declarations == null) {
755                    return EMPTY_ENUMERATION;
756                } else {
757                    return declarations.elements();
758                }
759            }
760            
761            
762            /**
763             * Return an enumeration of all prefixes currently in force.
764             *
765             * <p>The default prefix, if in force, is <em>not</em>
766             * returned, and will have to be checked for separately.</p>
767             *
768             * @return An enumeration of prefixes (never empty).
769             * @see org.xml.sax.helpers.NamespaceSupport#getPrefixes
770             */
771            Enumeration getPrefixes ()
772            {
773                if (prefixTable == null) {
774                    return EMPTY_ENUMERATION;
775                } else {
776                    return prefixTable.keys();
777                }
778            }
779            
780            
781    
782            ////////////////////////////////////////////////////////////////
783            // Internal methods.
784            ////////////////////////////////////////////////////////////////
785    
786    
787            /**
788             * Copy on write for the internal tables in this context.
789             *
790             * <p>This class is optimized for the normal case where most
791             * elements do not contain Namespace declarations.</p>
792             */     
793            private void copyTables ()
794            {
795                if (prefixTable != null) {
796                    prefixTable = (Hashtable)prefixTable.clone();
797                } else {
798                    prefixTable = new Hashtable();
799                }
800                if (uriTable != null) {
801                    uriTable = (Hashtable)uriTable.clone();
802                } else {
803                    uriTable = new Hashtable();
804                }
805                elementNameTable = new Hashtable();
806                attributeNameTable = new Hashtable();
807                declSeen = true;
808            }
809    
810    
811    
812            ////////////////////////////////////////////////////////////////
813            // Protected state.
814            ////////////////////////////////////////////////////////////////
815            
816            Hashtable prefixTable;
817            Hashtable uriTable;
818            Hashtable elementNameTable;
819            Hashtable attributeNameTable;
820            String defaultNS = null;
821            boolean declsOK = true;
822            
823    
824    
825            ////////////////////////////////////////////////////////////////
826            // Internal state.
827            ////////////////////////////////////////////////////////////////
828            
829            private Vector declarations = null;
830            private boolean declSeen = false;
831            private Context parent = null;
832        }
833    }
834    
835    // end of NamespaceSupport.java