001    // ParserAdapter.java - adapt a SAX1 Parser to a SAX2 XMLReader.
002    // http://www.saxproject.org
003    // Written by David Megginson
004    // NO WARRANTY!  This class is in the public domain.
005    // $Id: ParserAdapter.java,v 1.1 2004/12/23 22:38:42 mark Exp $
006    
007    package org.xml.sax.helpers;
008    
009    import java.io.IOException;
010    import java.util.Enumeration;
011    import java.util.Vector;
012    
013    import org.xml.sax.Parser;      // deprecated
014    import org.xml.sax.InputSource;
015    import org.xml.sax.Locator;
016    import org.xml.sax.AttributeList; // deprecated
017    import org.xml.sax.EntityResolver;
018    import org.xml.sax.DTDHandler;
019    import org.xml.sax.DocumentHandler; // deprecated
020    import org.xml.sax.ErrorHandler;
021    import org.xml.sax.SAXException;
022    import org.xml.sax.SAXParseException;
023    
024    import org.xml.sax.XMLReader;
025    import org.xml.sax.Attributes;
026    import org.xml.sax.ContentHandler;
027    import org.xml.sax.SAXNotRecognizedException;
028    import org.xml.sax.SAXNotSupportedException;
029    
030    
031    /**
032     * Adapt a SAX1 Parser as a SAX2 XMLReader.
033     *
034     * <blockquote>
035     * <em>This module, both source code and documentation, is in the
036     * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
037     * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
038     * for further information.
039     * </blockquote>
040     *
041     * <p>This class wraps a SAX1 {@link org.xml.sax.Parser Parser}
042     * and makes it act as a SAX2 {@link org.xml.sax.XMLReader XMLReader},
043     * with feature, property, and Namespace support.  Note
044     * that it is not possible to report {@link org.xml.sax.ContentHandler#skippedEntity
045     * skippedEntity} events, since SAX1 does not make that information available.</p>
046     *
047     * <p>This adapter does not test for duplicate Namespace-qualified
048     * attribute names.</p>
049     *
050     * @since SAX 2.0
051     * @author David Megginson
052     * @version 2.0.1 (sax2r2)
053     * @see org.xml.sax.helpers.XMLReaderAdapter
054     * @see org.xml.sax.XMLReader
055     * @see org.xml.sax.Parser
056     */
057    public class ParserAdapter implements XMLReader, DocumentHandler
058    {
059    
060    
061        ////////////////////////////////////////////////////////////////////
062        // Constructors.
063        ////////////////////////////////////////////////////////////////////
064    
065    
066        /**
067         * Construct a new parser adapter.
068         *
069         * <p>Use the "org.xml.sax.parser" property to locate the
070         * embedded SAX1 driver.</p>
071         *
072         * @exception SAXException If the embedded driver
073         *            cannot be instantiated or if the
074         *            org.xml.sax.parser property is not specified.
075         */
076        public ParserAdapter ()
077          throws SAXException
078        {
079            super();
080    
081            String driver = System.getProperty("org.xml.sax.parser");
082    
083            try {
084                setup(ParserFactory.makeParser());
085            } catch (ClassNotFoundException e1) {
086                throw new
087                    SAXException("Cannot find SAX1 driver class " +
088                                 driver, e1);
089            } catch (IllegalAccessException e2) {
090                throw new
091                    SAXException("SAX1 driver class " +
092                                 driver +
093                                 " found but cannot be loaded", e2);
094            } catch (InstantiationException e3) {
095                throw new
096                    SAXException("SAX1 driver class " +
097                                 driver +
098                                 " loaded but cannot be instantiated", e3);
099            } catch (ClassCastException e4) {
100                throw new
101                    SAXException("SAX1 driver class " +
102                                 driver +
103                                 " does not implement org.xml.sax.Parser");
104            } catch (NullPointerException e5) {
105                throw new
106                    SAXException("System property org.xml.sax.parser not specified");
107            }
108        }
109    
110    
111        /**
112         * Construct a new parser adapter.
113         *
114         * <p>Note that the embedded parser cannot be changed once the
115         * adapter is created; to embed a different parser, allocate
116         * a new ParserAdapter.</p>
117         *
118         * @param parser The SAX1 parser to embed.
119         * @exception java.lang.NullPointerException If the parser parameter
120         *            is null.
121         */
122        public ParserAdapter (Parser parser)
123        {
124            super();
125            setup(parser);
126        }
127    
128    
129        /**
130         * Internal setup method.
131         *
132         * @param parser The embedded parser.
133         * @exception java.lang.NullPointerException If the parser parameter
134         *            is null.
135         */
136        private void setup (Parser parser)
137        {
138            if (parser == null) {
139                throw new
140                    NullPointerException("Parser argument must not be null");
141            }
142            this.parser = parser;
143            atts = new AttributesImpl();
144            nsSupport = new NamespaceSupport();
145            attAdapter = new AttributeListAdapter();
146        }
147    
148    
149    
150        ////////////////////////////////////////////////////////////////////
151        // Implementation of org.xml.sax.XMLReader.
152        ////////////////////////////////////////////////////////////////////
153    
154    
155        //
156        // Internal constants for the sake of convenience.
157        //
158        private final static String FEATURES = "http://xml.org/sax/features/";
159        private final static String NAMESPACES = FEATURES + "namespaces";
160        private final static String NAMESPACE_PREFIXES = FEATURES + "namespace-prefixes";
161        private final static String XMLNS_URIs = FEATURES + "xmlns-uris";
162    
163    
164        /**
165         * Set a feature flag for the parser.
166         *
167         * <p>The only features recognized are namespaces and
168         * namespace-prefixes.</p>
169         *
170         * @param name The feature name, as a complete URI.
171         * @param value The requested feature value.
172         * @exception SAXNotRecognizedException If the feature
173         *            can't be assigned or retrieved.
174         * @exception SAXNotSupportedException If the feature
175         *            can't be assigned that value.
176         * @see org.xml.sax.XMLReader#setFeature
177         */
178        public void setFeature (String name, boolean value)
179            throws SAXNotRecognizedException, SAXNotSupportedException
180        {
181            if (name.equals(NAMESPACES)) {
182                checkNotParsing("feature", name);
183                namespaces = value;
184                if (!namespaces && !prefixes) {
185                    prefixes = true;
186                }
187            } else if (name.equals(NAMESPACE_PREFIXES)) {
188                checkNotParsing("feature", name);
189                prefixes = value;
190                if (!prefixes && !namespaces) {
191                    namespaces = true;
192                }
193            } else if (name.equals(XMLNS_URIs)) {
194                checkNotParsing("feature", name);
195                uris = value;
196            } else {
197                throw new SAXNotRecognizedException("Feature: " + name);
198            }
199        }
200    
201    
202        /**
203         * Check a parser feature flag.
204         *
205         * <p>The only features recognized are namespaces and
206         * namespace-prefixes.</p>
207         *
208         * @param name The feature name, as a complete URI.
209         * @return The current feature value.
210         * @exception SAXNotRecognizedException If the feature
211         *            value can't be assigned or retrieved.
212         * @exception SAXNotSupportedException If the
213         *            feature is not currently readable.
214         * @see org.xml.sax.XMLReader#setFeature
215         */
216        public boolean getFeature (String name)
217            throws SAXNotRecognizedException, SAXNotSupportedException
218        {
219            if (name.equals(NAMESPACES)) {
220                return namespaces;
221            } else if (name.equals(NAMESPACE_PREFIXES)) {
222                return prefixes;
223            } else if (name.equals(XMLNS_URIs)) {
224                return uris;
225            } else {
226                throw new SAXNotRecognizedException("Feature: " + name);
227            }
228        }
229    
230    
231        /**
232         * Set a parser property.
233         *
234         * <p>No properties are currently recognized.</p>
235         *
236         * @param name The property name.
237         * @param value The property value.
238         * @exception SAXNotRecognizedException If the property
239         *            value can't be assigned or retrieved.
240         * @exception SAXNotSupportedException If the property
241         *            can't be assigned that value.
242         * @see org.xml.sax.XMLReader#setProperty
243         */
244        public void setProperty (String name, Object value)
245            throws SAXNotRecognizedException, SAXNotSupportedException
246        {
247            throw new SAXNotRecognizedException("Property: " + name);
248        }
249    
250    
251        /**
252         * Get a parser property.
253         *
254         * <p>No properties are currently recognized.</p>
255         *
256         * @param name The property name.
257         * @return The property value.
258         * @exception SAXNotRecognizedException If the property
259         *            value can't be assigned or retrieved.
260         * @exception SAXNotSupportedException If the property
261         *            value is not currently readable.
262         * @see org.xml.sax.XMLReader#getProperty
263         */
264        public Object getProperty (String name)
265            throws SAXNotRecognizedException, SAXNotSupportedException
266        {
267            throw new SAXNotRecognizedException("Property: " + name);
268        }
269    
270    
271        /**
272         * Set the entity resolver.
273         *
274         * @param resolver The new entity resolver.
275         * @see org.xml.sax.XMLReader#setEntityResolver
276         */
277        public void setEntityResolver (EntityResolver resolver)
278        {
279            entityResolver = resolver;
280        }
281    
282    
283        /**
284         * Return the current entity resolver.
285         *
286         * @return The current entity resolver, or null if none was supplied.
287         * @see org.xml.sax.XMLReader#getEntityResolver
288         */
289        public EntityResolver getEntityResolver ()
290        {
291            return entityResolver;
292        }
293    
294    
295        /**
296         * Set the DTD handler.
297         *
298         * @param handler the new DTD handler
299         * @see org.xml.sax.XMLReader#setEntityResolver
300         */
301        public void setDTDHandler (DTDHandler handler)
302        {
303            dtdHandler = handler;
304        }
305    
306    
307        /**
308         * Return the current DTD handler.
309         *
310         * @return the current DTD handler, or null if none was supplied
311         * @see org.xml.sax.XMLReader#getEntityResolver
312         */
313        public DTDHandler getDTDHandler ()
314        {
315            return dtdHandler;
316        }
317    
318    
319        /**
320         * Set the content handler.
321         *
322         * @param handler the new content handler
323         * @see org.xml.sax.XMLReader#setEntityResolver
324         */
325        public void setContentHandler (ContentHandler handler)
326        {
327            contentHandler = handler;
328        }
329    
330    
331        /**
332         * Return the current content handler.
333         *
334         * @return The current content handler, or null if none was supplied.
335         * @see org.xml.sax.XMLReader#getEntityResolver
336         */
337        public ContentHandler getContentHandler ()
338        {
339            return contentHandler;
340        }
341    
342    
343        /**
344         * Set the error handler.
345         *
346         * @param handler The new error handler.
347         * @see org.xml.sax.XMLReader#setEntityResolver
348         */
349        public void setErrorHandler (ErrorHandler handler)
350        {
351            errorHandler = handler;
352        }
353    
354    
355        /**
356         * Return the current error handler.
357         *
358         * @return The current error handler, or null if none was supplied.
359         * @see org.xml.sax.XMLReader#getEntityResolver
360         */
361        public ErrorHandler getErrorHandler ()
362        {
363            return errorHandler;
364        }
365    
366    
367        /**
368         * Parse an XML document.
369         *
370         * @param systemId The absolute URL of the document.
371         * @exception java.io.IOException If there is a problem reading
372         *            the raw content of the document.
373         * @exception SAXException If there is a problem
374         *            processing the document.
375         * @see #parse(org.xml.sax.InputSource)
376         * @see org.xml.sax.Parser#parse(java.lang.String)
377         */
378        public void parse (String systemId)
379            throws IOException, SAXException
380        {
381            parse(new InputSource(systemId));
382        }
383    
384    
385        /**
386         * Parse an XML document.
387         *
388         * @param input An input source for the document.
389         * @exception java.io.IOException If there is a problem reading
390         *            the raw content of the document.
391         * @exception SAXException If there is a problem
392         *            processing the document.
393         * @see #parse(java.lang.String)
394         * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
395         */
396        public void parse (InputSource input)
397            throws IOException, SAXException
398        {
399            if (parsing) {
400                throw new SAXException("Parser is already in use");
401            }
402            setupParser();
403            parsing = true;
404            try {
405                parser.parse(input);
406            } finally {
407                parsing = false;
408            }
409            parsing = false;
410        }
411    
412    
413    
414        ////////////////////////////////////////////////////////////////////
415        // Implementation of org.xml.sax.DocumentHandler.
416        ////////////////////////////////////////////////////////////////////
417    
418    
419        /**
420         * Adapter implementation method; do not call.
421         * Adapt a SAX1 document locator event.
422         *
423         * @param locator A document locator.
424         * @see org.xml.sax.ContentHandler#setDocumentLocator
425         */
426        public void setDocumentLocator (Locator locator)
427        {
428            this.locator = locator;
429            if (contentHandler != null) {
430                contentHandler.setDocumentLocator(locator);
431            }
432        }
433    
434    
435        /**
436         * Adapter implementation method; do not call.
437         * Adapt a SAX1 start document event.
438         *
439         * @exception SAXException The client may raise a
440         *            processing exception.
441         * @see org.xml.sax.DocumentHandler#startDocument
442         */
443        public void startDocument ()
444            throws SAXException
445        {
446            if (contentHandler != null) {
447                contentHandler.startDocument();
448            }
449        }
450    
451    
452        /**
453         * Adapter implementation method; do not call.
454         * Adapt a SAX1 end document event.
455         *
456         * @exception SAXException The client may raise a
457         *            processing exception.
458         * @see org.xml.sax.DocumentHandler#endDocument
459         */
460        public void endDocument ()
461            throws SAXException
462        {
463            if (contentHandler != null) {
464                contentHandler.endDocument();
465            }
466        }
467    
468    
469        /**
470         * Adapter implementation method; do not call.
471         * Adapt a SAX1 startElement event.
472         *
473         * <p>If necessary, perform Namespace processing.</p>
474         *
475         * @param qName The qualified (prefixed) name.
476         * @param qAtts The XML attribute list (with qnames).
477         * @exception SAXException The client may raise a
478         *            processing exception.
479         */
480        public void startElement (String qName, AttributeList qAtts)
481            throws SAXException
482        {
483                                    // These are exceptions from the
484                                    // first pass; they should be
485                                    // ignored if there's a second pass,
486                                    // but reported otherwise.
487            Vector exceptions = null;
488    
489                                    // If we're not doing Namespace
490                                    // processing, dispatch this quickly.
491            if (!namespaces) {
492                if (contentHandler != null) {
493                    attAdapter.setAttributeList(qAtts);
494                    contentHandler.startElement("", "", qName.intern(),
495                                                attAdapter);
496                }
497                return;
498            }
499    
500    
501                                    // OK, we're doing Namespace processing.
502            nsSupport.pushContext();
503            int length = qAtts.getLength();
504    
505                                    // First pass:  handle NS decls
506            for (int i = 0; i < length; i++) {
507                String attQName = qAtts.getName(i);
508    
509                if (!attQName.startsWith("xmlns"))
510                    continue;
511                                    // Could be a declaration...
512                String prefix;
513                int n = attQName.indexOf(':');
514    
515                                    // xmlns=...
516                if (n == -1 && attQName.length () == 5) {
517                    prefix = "";
518                } else if (n != 5) {
519                    // XML namespaces spec doesn't discuss "xmlnsf:oo"
520                    // (and similarly named) attributes ... at most, warn
521                    continue;
522                } else              // xmlns:foo=...
523                    prefix = attQName.substring(n+1);
524    
525                String value = qAtts.getValue(i);
526                if (!nsSupport.declarePrefix(prefix, value)) {
527                    reportError("Illegal Namespace prefix: " + prefix);
528                    continue;
529                }
530                if (contentHandler != null)
531                    contentHandler.startPrefixMapping(prefix, value);
532            }
533    
534                                    // Second pass: copy all relevant
535                                    // attributes into the SAX2 AttributeList
536                                    // using updated prefix bindings
537            atts.clear();
538            for (int i = 0; i < length; i++) {
539                String attQName = qAtts.getName(i);
540                String type = qAtts.getType(i);
541                String value = qAtts.getValue(i);
542    
543                                    // Declaration?
544                if (attQName.startsWith("xmlns")) {
545                    String prefix;
546                    int n = attQName.indexOf(':');
547    
548                    if (n == -1 && attQName.length () == 5) {
549                        prefix = "";
550                    } else if (n != 5) {
551                        // XML namespaces spec doesn't discuss "xmlnsf:oo"
552                        // (and similarly named) attributes ... ignore
553                        prefix = null;
554                    } else {
555                        prefix = attQName.substring(6);
556                    }
557                                    // Yes, decl:  report or prune
558                    if (prefix != null) {
559                        if (prefixes) {
560                            if (uris)
561                                // note funky case:  localname can be null
562                                // when declaring the default prefix, and
563                                // yet the uri isn't null.
564                                atts.addAttribute (nsSupport.XMLNS, prefix,
565                                        attQName.intern(), type, value);
566                            else
567                                atts.addAttribute ("", "",
568                                        attQName.intern(), type, value);
569                        }
570                        continue;
571                    }
572                }
573    
574                                    // Not a declaration -- report
575                try {
576                    String attName[] = processName(attQName, true, true);
577                    atts.addAttribute(attName[0], attName[1], attName[2],
578                                      type, value);
579                } catch (SAXException e) {
580                    if (exceptions == null)
581                        exceptions = new Vector();
582                    exceptions.addElement(e);
583                    atts.addAttribute("", attQName, attQName, type, value);
584                }
585            }
586    
587            // now handle the deferred exception reports
588            if (exceptions != null && errorHandler != null) {
589                for (int i = 0; i < exceptions.size(); i++)
590                    errorHandler.error((SAXParseException)
591                                    (exceptions.elementAt(i)));
592            }
593    
594                                    // OK, finally report the event.
595            if (contentHandler != null) {
596                String name[] = processName(qName, false, false);
597                contentHandler.startElement(name[0], name[1], name[2], atts);
598            }
599        }
600    
601    
602        /**
603         * Adapter implementation method; do not call.
604         * Adapt a SAX1 end element event.
605         *
606         * @param qName The qualified (prefixed) name.
607         * @exception SAXException The client may raise a
608         *            processing exception.
609         * @see org.xml.sax.DocumentHandler#endElement
610         */
611        public void endElement (String qName)
612            throws SAXException
613        {
614                                    // If we're not doing Namespace
615                                    // processing, dispatch this quickly.
616            if (!namespaces) {
617                if (contentHandler != null) {
618                    contentHandler.endElement("", "", qName.intern());
619                }
620                return;
621            }
622    
623                                    // Split the name.
624            String names[] = processName(qName, false, false);
625            if (contentHandler != null) {
626                contentHandler.endElement(names[0], names[1], names[2]);
627                Enumeration prefixes = nsSupport.getDeclaredPrefixes();
628                while (prefixes.hasMoreElements()) {
629                    String prefix = (String)prefixes.nextElement();
630                    contentHandler.endPrefixMapping(prefix);
631                }
632            }
633            nsSupport.popContext();
634        }
635    
636    
637        /**
638         * Adapter implementation method; do not call.
639         * Adapt a SAX1 characters event.
640         *
641         * @param ch An array of characters.
642         * @param start The starting position in the array.
643         * @param length The number of characters to use.
644         * @exception SAXException The client may raise a
645         *            processing exception.
646         * @see org.xml.sax.DocumentHandler#characters
647         */
648        public void characters (char ch[], int start, int length)
649            throws SAXException
650        {
651            if (contentHandler != null) {
652                contentHandler.characters(ch, start, length);
653            }
654        }
655    
656    
657        /**
658         * Adapter implementation method; do not call.
659         * Adapt a SAX1 ignorable whitespace event.
660         *
661         * @param ch An array of characters.
662         * @param start The starting position in the array.
663         * @param length The number of characters to use.
664         * @exception SAXException The client may raise a
665         *            processing exception.
666         * @see org.xml.sax.DocumentHandler#ignorableWhitespace
667         */
668        public void ignorableWhitespace (char ch[], int start, int length)
669            throws SAXException
670        {
671            if (contentHandler != null) {
672                contentHandler.ignorableWhitespace(ch, start, length);
673            }
674        }
675    
676    
677        /**
678         * Adapter implementation method; do not call.
679         * Adapt a SAX1 processing instruction event.
680         *
681         * @param target The processing instruction target.
682         * @param data The remainder of the processing instruction
683         * @exception SAXException The client may raise a
684         *            processing exception.
685         * @see org.xml.sax.DocumentHandler#processingInstruction
686         */
687        public void processingInstruction (String target, String data)
688            throws SAXException
689        {
690            if (contentHandler != null) {
691                contentHandler.processingInstruction(target, data);
692            }
693        }
694    
695    
696    
697        ////////////////////////////////////////////////////////////////////
698        // Internal utility methods.
699        ////////////////////////////////////////////////////////////////////
700    
701    
702        /**
703         * Initialize the parser before each run.
704         */
705        private void setupParser ()
706        {
707            // catch an illegal "nonsense" state.
708            if (!prefixes && !namespaces)
709                throw new IllegalStateException ();
710    
711            nsSupport.reset();
712            if (uris)
713                nsSupport.setNamespaceDeclUris (true);
714    
715            if (entityResolver != null) {
716                parser.setEntityResolver(entityResolver);
717            }
718            if (dtdHandler != null) {
719                parser.setDTDHandler(dtdHandler);
720            }
721            if (errorHandler != null) {
722                parser.setErrorHandler(errorHandler);
723            }
724            parser.setDocumentHandler(this);
725            locator = null;
726        }
727    
728    
729        /**
730         * Process a qualified (prefixed) name.
731         *
732         * <p>If the name has an undeclared prefix, use only the qname
733         * and make an ErrorHandler.error callback in case the app is
734         * interested.</p>
735         *
736         * @param qName The qualified (prefixed) name.
737         * @param isAttribute true if this is an attribute name.
738         * @return The name split into three parts.
739         * @exception SAXException The client may throw
740         *            an exception if there is an error callback.
741         */
742        private String [] processName (String qName, boolean isAttribute,
743                                       boolean useException)
744            throws SAXException
745        {
746            String parts[] = nsSupport.processName(qName, nameParts,
747                                                   isAttribute);
748            if (parts == null) {
749                if (useException)
750                    throw makeException("Undeclared prefix: " + qName);
751                reportError("Undeclared prefix: " + qName);
752                parts = new String[3];
753                parts[0] = parts[1] = "";
754                parts[2] = qName.intern();
755            }
756            return parts;
757        }
758    
759    
760        /**
761         * Report a non-fatal error.
762         *
763         * @param message The error message.
764         * @exception SAXException The client may throw
765         *            an exception.
766         */
767        void reportError (String message)
768            throws SAXException
769        {
770            if (errorHandler != null)
771                errorHandler.error(makeException(message));
772        }
773    
774    
775        /**
776         * Construct an exception for the current context.
777         *
778         * @param message The error message.
779         */
780        private SAXParseException makeException (String message)
781        {
782            if (locator != null) {
783                return new SAXParseException(message, locator);
784            } else {
785                return new SAXParseException(message, null, null, -1, -1);
786            }
787        }
788    
789    
790        /**
791         * Throw an exception if we are parsing.
792         *
793         * <p>Use this method to detect illegal feature or
794         * property changes.</p>
795         *
796         * @param type The type of thing (feature or property).
797         * @param name The feature or property name.
798         * @exception SAXNotSupportedException If a
799         *            document is currently being parsed.
800         */
801        private void checkNotParsing (String type, String name)
802            throws SAXNotSupportedException
803        {
804            if (parsing) {
805                throw new SAXNotSupportedException("Cannot change " +
806                                                   type + ' ' +
807                                                   name + " while parsing");
808    
809            }
810        }
811    
812    
813    
814        ////////////////////////////////////////////////////////////////////
815        // Internal state.
816        ////////////////////////////////////////////////////////////////////
817    
818        private NamespaceSupport nsSupport;
819        private AttributeListAdapter attAdapter;
820    
821        private boolean parsing = false;
822        private String nameParts[] = new String[3];
823    
824        private Parser parser = null;
825    
826        private AttributesImpl atts = null;
827    
828                                    // Features
829        private boolean namespaces = true;
830        private boolean prefixes = false;
831        private boolean uris = false;
832    
833                                    // Properties
834    
835                                    // Handlers
836        Locator locator;
837    
838        EntityResolver entityResolver = null;
839        DTDHandler dtdHandler = null;
840        ContentHandler contentHandler = null;
841        ErrorHandler errorHandler = null;
842    
843    
844    
845        ////////////////////////////////////////////////////////////////////
846        // Inner class to wrap an AttributeList when not doing NS proc.
847        ////////////////////////////////////////////////////////////////////
848    
849    
850        /**
851         * Adapt a SAX1 AttributeList as a SAX2 Attributes object.
852         *
853         * <p>This class is in the Public Domain, and comes with NO
854         * WARRANTY of any kind.</p>
855         *
856         * <p>This wrapper class is used only when Namespace support
857         * is disabled -- it provides pretty much a direct mapping
858         * from SAX1 to SAX2, except that names and types are
859         * interned whenever requested.</p>
860         */
861        final class AttributeListAdapter implements Attributes
862        {
863    
864            /**
865             * Construct a new adapter.
866             */
867            AttributeListAdapter ()
868            {
869            }
870    
871    
872            /**
873             * Set the embedded AttributeList.
874             *
875             * <p>This method must be invoked before any of the others
876             * can be used.</p>
877             *
878             * @param The SAX1 attribute list (with qnames).
879             */
880            void setAttributeList (AttributeList qAtts)
881            {
882                this.qAtts = qAtts;
883            }
884    
885    
886            /**
887             * Return the length of the attribute list.
888             *
889             * @return The number of attributes in the list.
890             * @see org.xml.sax.Attributes#getLength
891             */
892            public int getLength ()
893            {
894                return qAtts.getLength();
895            }
896    
897    
898            /**
899             * Return the Namespace URI of the specified attribute.
900             *
901             * @param The attribute's index.
902             * @return Always the empty string.
903             * @see org.xml.sax.Attributes#getURI
904             */
905            public String getURI (int i)
906            {
907                return "";
908            }
909    
910    
911            /**
912             * Return the local name of the specified attribute.
913             *
914             * @param The attribute's index.
915             * @return Always the empty string.
916             * @see org.xml.sax.Attributes#getLocalName
917             */
918            public String getLocalName (int i)
919            {
920                return "";
921            }
922    
923    
924            /**
925             * Return the qualified (prefixed) name of the specified attribute.
926             *
927             * @param The attribute's index.
928             * @return The attribute's qualified name, internalized.
929             */
930            public String getQName (int i)
931            {
932                return qAtts.getName(i).intern();
933            }
934    
935    
936            /**
937             * Return the type of the specified attribute.
938             *
939             * @param The attribute's index.
940             * @return The attribute's type as an internalized string.
941             */
942            public String getType (int i)
943            {
944                return qAtts.getType(i).intern();
945            }
946    
947    
948            /**
949             * Return the value of the specified attribute.
950             *
951             * @param The attribute's index.
952             * @return The attribute's value.
953             */
954            public String getValue (int i)
955            {
956                return qAtts.getValue(i);
957            }
958    
959    
960            /**
961             * Look up an attribute index by Namespace name.
962             *
963             * @param uri The Namespace URI or the empty string.
964             * @param localName The local name.
965             * @return The attributes index, or -1 if none was found.
966             * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
967             */
968            public int getIndex (String uri, String localName)
969            {
970                return -1;
971            }
972    
973    
974            /**
975             * Look up an attribute index by qualified (prefixed) name.
976             *
977             * @param qName The qualified name.
978             * @return The attributes index, or -1 if none was found.
979             * @see org.xml.sax.Attributes#getIndex(java.lang.String)
980             */
981            public int getIndex (String qName)
982            {
983                int max = atts.getLength();
984                for (int i = 0; i < max; i++) {
985                    if (qAtts.getName(i).equals(qName)) {
986                        return i;
987                    }
988                }
989                return -1;
990            }
991    
992    
993            /**
994             * Look up the type of an attribute by Namespace name.
995             *
996             * @param uri The Namespace URI
997             * @param localName The local name.
998             * @return The attribute's type as an internalized string.
999             */
1000            public String getType (String uri, String localName)
1001            {
1002                return null;
1003            }
1004    
1005    
1006            /**
1007             * Look up the type of an attribute by qualified (prefixed) name.
1008             *
1009             * @param qName The qualified name.
1010             * @return The attribute's type as an internalized string.
1011             */
1012            public String getType (String qName)
1013            {
1014                return qAtts.getType(qName).intern();
1015            }
1016    
1017    
1018            /**
1019             * Look up the value of an attribute by Namespace name.
1020             *
1021             * @param uri The Namespace URI
1022             * @param localName The local name.
1023             * @return The attribute's value.
1024             */
1025            public String getValue (String uri, String localName)
1026            {
1027                return null;
1028            }
1029    
1030    
1031            /**
1032             * Look up the value of an attribute by qualified (prefixed) name.
1033             *
1034             * @param qName The qualified name.
1035             * @return The attribute's value.
1036             */
1037            public String getValue (String qName)
1038            {
1039                return qAtts.getValue(qName);
1040            }
1041    
1042            private AttributeList qAtts;
1043        }
1044    }
1045    
1046    // end of ParserAdapter.java