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