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