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
007package org.xml.sax.helpers;
008
009import java.io.IOException;
010import java.util.Enumeration;
011import java.util.Vector;
012
013import org.xml.sax.Parser;      // deprecated
014import org.xml.sax.InputSource;
015import org.xml.sax.Locator;
016import org.xml.sax.AttributeList; // deprecated
017import org.xml.sax.EntityResolver;
018import org.xml.sax.DTDHandler;
019import org.xml.sax.DocumentHandler; // deprecated
020import org.xml.sax.ErrorHandler;
021import org.xml.sax.SAXException;
022import org.xml.sax.SAXParseException;
023
024import org.xml.sax.XMLReader;
025import org.xml.sax.Attributes;
026import org.xml.sax.ContentHandler;
027import org.xml.sax.SAXNotRecognizedException;
028import 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 */
057public 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