KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dom4j > io > aelfred > SAXDriver


1 /*
2  * Copyright (c) 1999-2000 by David Brownell. All Rights Reserved.
3  *
4  * This program is open source software; you may use, copy, modify, and
5  * redistribute it under the terms of the LICENSE with which it was
6  * originally distributed.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * LICENSE for more details.
12  */

13
14 //
15
// Copyright (c) 1998 by Microstar Software Ltd.
16
// From Microstar's README (the entire original license):
17
//
18
// AElfred is free for both commercial and non-commercial use and
19
// redistribution, provided that Microstar's copyright and disclaimer are
20
// retained intact. You are free to modify AElfred for your own use and
21
// to redistribute AElfred with your modifications, provided that the
22
// modifications are clearly documented.
23
//
24
// This program is distributed in the hope that it will be useful, but
25
// WITHOUT ANY WARRANTY; without even the implied warranty of
26
// merchantability or fitness for a particular purpose. Please use it AT
27
// YOUR OWN RISK.
28
//
29

30
31 package org.dom4j.io.aelfred;
32
33 import org.xml.sax.*;
34 import org.xml.sax.ext.DeclHandler JavaDoc;
35 import org.xml.sax.ext.LexicalHandler JavaDoc;
36 import org.xml.sax.helpers.NamespaceSupport JavaDoc;
37
38 import java.io.IOException JavaDoc;
39 import java.io.InputStreamReader JavaDoc;
40 import java.util.*;
41
42
43 // $Id: SAXDriver.java,v 1.2 2003/06/10 16:18:34 per_nyfelt Exp $
44

45 /**
46  * An enhanced SAX2 version of Microstar's Ælfred XML parser.
47  * The enhancements primarily relate to significant improvements in
48  * conformance to the XML specification, and SAX2 support. Performance
49  * has been improved. However, the Ælfred proprietary APIs are
50  * no longer public. See the package level documentation for more
51  * information.
52  *
53  * <table border="1" width='100%' cellpadding='3' cellspacing='0'>
54  * <tr bgcolor='#ccccff'>
55  * <th><font size='+1'>Name</font></th>
56  * <th><font size='+1'>Notes</font></th></tr>
57  *
58  * <tr><td colspan=2><center><em>Features ... URL prefix is
59  * <b>http://xml.org/sax/features/</b></em></center></td></tr>
60  *
61  * <tr><td>(URL)/external-general-entities</td>
62  * <td>Value is fixed at <em>true</em></td></tr>
63  * <tr><td>(URL)/external-parameter-entities</td>
64  * <td>Value is fixed at <em>true</em></td></tr>
65  * <tr><td>(URL)/namespace-prefixes</td>
66  * <td>Value defaults to <em>false</em> (but XML 1.0 names are
67  * always reported)</td></tr>
68  * <tr><td>(URL)/namespaces</td>
69  * <td>Value defaults to <em>true</em></td></tr>
70  * <tr><td>(URL)/string-interning</td>
71  * <td>Value is fixed at <em>true</em></td></tr>
72  * <tr><td>(URL)/validation</td>
73  * <td>Value is fixed at <em>false</em></td></tr>
74  *
75  * <tr><td colspan=2><center><em>Handler Properties ... URL prefix is
76  * <b>http://xml.org/sax/properties/</b></em></center></td></tr>
77  *
78  * <tr><td>(URL)/declaration-handler</td>
79  * <td>A declaration handler may be provided. Declaration of general
80  * entities is exposed, but not parameter entities; none of the entity
81  * names reported here will begin with "%". </td></tr>
82  * <tr><td>(URL)/lexical-handler</td>
83  * <td>A lexical handler may be provided. Entity boundaries and
84  * comments are not exposed; only CDATA sections and the start/end of
85  * the DTD (the internal subset is not detectible). </td></tr>
86  * </table>
87  *
88  * <p> Note that the declaration handler doesn't suffice for showing all
89  * the logical structure
90  * of the DTD; it doesn't expose the name of the root element, or the values
91  * that are permitted in a NOTATIONS attribute. (The former is exposed as
92  * lexical data, and SAX2 beta doesn't expose the latter.)
93  *
94  * <p> Although support for several features and properties is "built in"
95  * to this parser, it support all others by storing the assigned values
96  * and returning them.
97  *
98  * <p>This parser currently implements the SAX1 Parser API, but
99  * it may not continue to do so in the future.
100  *
101  * @author Written by David Megginson &lt;dmeggins@microstar.com&gt;
102  * (version 1.2a from Microstar)
103  * @author Updated by David Brownell &lt;david-b@pacbell.net&gt;
104  * @version $Date: 2003/06/10 16:18:34 $
105  * @see org.xml.sax.Parser
106  */

107 final public class SAXDriver
108     implements Locator, Attributes, XMLReader, Parser, AttributeList
109 {
110     private final DefaultHandler base = new DefaultHandler ();
111     private XmlParser parser;
112
113     private EntityResolver entityResolver = base;
114     private ContentHandler contentHandler = base;
115     private DTDHandler dtdHandler = base;
116     private ErrorHandler errorHandler = base;
117     private DeclHandler JavaDoc declHandler = base;
118     private LexicalHandler JavaDoc lexicalHandler = base;
119
120     private String JavaDoc elementName = null;
121     private ArrayList entityStack = new ArrayList ();
122
123     private ArrayList attributeNames = new ArrayList ();
124     private ArrayList attributeNamespaces = new ArrayList ();
125     private ArrayList attributeLocalNames = new ArrayList ();
126     private ArrayList attributeValues = new ArrayList ();
127
128     private boolean namespaces = true;
129     private boolean xmlNames = false;
130     private boolean nspending = false; // indicates an attribute was read before its
131
// namespace declaration
132

133     private int attributeCount = 0;
134     private String JavaDoc nsTemp [] = new String JavaDoc [3];
135     private NamespaceSupport JavaDoc prefixStack = new NamespaceSupport JavaDoc ();
136
137     private HashMap features;
138     private HashMap properties;
139
140
141     //
142
// Constructor.
143
//
144

145     /** Constructs a SAX Parser. */
146     public SAXDriver () {}
147
148
149     //
150
// Implementation of org.xml.sax.Parser.
151
//
152

153     /**
154      * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
155      * only locales using the English language are supported.
156      * @param locale The locale for which diagnostics will be generated
157      */

158     public void setLocale (Locale locale)
159     throws SAXException
160     {
161     if ("en".equals (locale.getLanguage ()))
162         return ;
163
164     throw new SAXException ("AElfred only supports English locales.");
165     }
166
167
168     /**
169      * <b>SAX2</b>: Returns the object used when resolving external
170      * entities during parsing (both general and parameter entities).
171      */

172     public EntityResolver getEntityResolver ()
173     {
174     return entityResolver;
175     }
176
177     /**
178      * <b>SAX1, SAX2</b>: Set the entity resolver for this parser.
179      * @param resolver The object to receive entity events.
180      */

181     public void setEntityResolver (EntityResolver resolver)
182     {
183     if (resolver == null)
184         resolver = base;
185     this.entityResolver = resolver;
186     }
187
188
189     /**
190      * <b>SAX2</b>: Returns the object used to process declarations related
191      * to notations and unparsed entities.
192      */

193     public DTDHandler getDTDHandler ()
194     {
195     return dtdHandler;
196     }
197
198     /**
199      * <b>SAX1, SAX2</b>: Set the DTD handler for this parser.
200      * @param handler The object to receive DTD events.
201      */

202     public void setDTDHandler (DTDHandler handler)
203     {
204     if (handler == null)
205         handler = base;
206     this.dtdHandler = handler;
207     }
208
209
210     /**
211      * <b>SAX1</b>: Set the document handler for this parser. If a
212      * content handler was set, this document handler will supplant it.
213      * The parser is set to report all XML 1.0 names rather than to
214      * filter out "xmlns" attributes (the "namespace-prefixes" feature
215      * is set to true).
216      *
217      * @deprecated SAX2 programs should use the XMLReader interface
218      * and a ContentHandler.
219      *
220      * @param handler The object to receive document events.
221      */

222     public void setDocumentHandler (DocumentHandler handler)
223     {
224     contentHandler = new Adapter (handler);
225     xmlNames = true;
226     }
227
228     /**
229      * <b>SAX2</b>: Returns the object used to report the logical
230      * content of an XML document.
231      */

232     public ContentHandler getContentHandler ()
233     {
234     return contentHandler;
235     }
236
237     /**
238      * <b>SAX2</b>: Assigns the object used to report the logical
239      * content of an XML document. If a document handler was set,
240      * this content handler will supplant it (but XML 1.0 style name
241      * reporting may remain enabled).
242      */

243     public void setContentHandler (ContentHandler handler)
244     {
245         if (handler == null)
246             handler = base;
247         contentHandler = handler;
248     }
249
250     /**
251      * <b>SAX1, SAX2</b>: Set the error handler for this parser.
252      * @param handler The object to receive error events.
253      */

254     public void setErrorHandler (ErrorHandler handler)
255     {
256         if (handler == null)
257             handler = base;
258         this.errorHandler = handler;
259     }
260
261     /**
262      * <b>SAX2</b>: Returns the object used to receive callbacks for XML
263      * errors of all levels (fatal, nonfatal, warning); this is never null;
264      */

265     public ErrorHandler getErrorHandler ()
266     {
267         return errorHandler;
268     }
269
270
271     /**
272      * <b>SAX1, SAX2</b>: Auxiliary API to parse an XML document, used mostly
273      * when no URI is available.
274      * If you want anything useful to happen, you should set
275      * at least one type of handler.
276      * @param source The XML input source. Don't set 'encoding' unless
277      * you know for a fact that it's correct.
278      * @see #setEntityResolver
279      * @see #setDTDHandler
280      * @see #setContentHandler
281      * @see #setErrorHandler
282      * @exception SAXException The handlers may throw any SAXException,
283      * and the parser normally throws SAXParseException objects.
284      * @exception IOException IOExceptions are normally through through
285      * the parser if there are problems reading the source document.
286      */

287      
288     public void parse (InputSource source) throws SAXException, IOException JavaDoc
289     {
290         synchronized (base) {
291             parser = new XmlParser ();
292             parser.setHandler (this);
293
294             try {
295                 String JavaDoc systemId = source.getSystemId ();
296
297                 // duplicate first entry, in case startDocument handler
298
// needs to use Locator.getSystemId(), before entities
299
// start to get reported by the parser
300

301                 if (systemId != null)
302                     entityStack.add (systemId);
303                 else
304                     entityStack.add ("illegal:unknown system ID");
305
306                 parser.doParse (systemId,
307                           source.getPublicId (),
308                           source.getCharacterStream (),
309                           source.getByteStream (),
310                           source.getEncoding ());
311             } catch (SAXException e) {
312                 throw e;
313             } catch (IOException JavaDoc e) {
314                 throw e;
315             } catch (RuntimeException JavaDoc e) {
316                 throw e;
317             } catch (Exception JavaDoc e) {
318                 throw new SAXException (e.getMessage (), e);
319             } finally {
320                 contentHandler.endDocument ();
321                 entityStack.clear ();
322             }
323         }
324     }
325
326
327     /**
328      * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a
329      * system identifier (URI).
330      */

331      
332     public void parse (String JavaDoc systemId) throws SAXException, IOException JavaDoc
333     {
334         parse (new InputSource (systemId));
335     }
336
337     //
338
// Implementation of SAX2 "XMLReader" interface
339
//
340
static final String JavaDoc FEATURE = "http://xml.org/sax/features/";
341     static final String JavaDoc HANDLER = "http://xml.org/sax/properties/";
342
343     /**
344      * <b>SAX2</b>: Tells the value of the specified feature flag.
345      *
346      * @exception SAXNotRecognizedException thrown if the feature flag
347      * is neither built in, nor yet assigned.
348      */

349     public boolean getFeature (String JavaDoc featureId)
350     throws SAXNotRecognizedException
351     {
352     if ((FEATURE + "validation").equals (featureId))
353         return false;
354
355     // external entities (both types) are currently always included
356
if ((FEATURE + "external-general-entities").equals (featureId)
357         || (FEATURE + "external-parameter-entities")
358         .equals (featureId))
359         return true;
360
361     // element/attribute names are as written in document; no mangling
362
if ((FEATURE + "namespace-prefixes").equals (featureId))
363         return xmlNames;
364
365     // report element/attribute namespaces?
366
if ((FEATURE + "namespaces").equals (featureId))
367         return namespaces;
368
369     // XXX always provides a locator ... removed in beta
370

371     // always interns
372
if ((FEATURE + "string-interning").equals (featureId))
373         return true;
374
375     if (features != null && features.containsKey (featureId))
376         return ((Boolean JavaDoc)features.get (featureId)).booleanValue ();
377
378     throw new SAXNotRecognizedException (featureId);
379     }
380
381     /**
382      * <b>SAX2</b>: Returns the specified property.
383      *
384      * @exception SAXNotRecognizedException thrown if the property value
385      * is neither built in, nor yet stored.
386      */

387     public Object JavaDoc getProperty (String JavaDoc propertyId)
388     throws SAXNotRecognizedException
389     {
390     if ((HANDLER + "declaration-handler").equals (propertyId))
391         return declHandler;
392
393     if ((HANDLER + "lexical-handler").equals (propertyId))
394         return lexicalHandler;
395     
396     if (properties != null && properties.containsKey (propertyId))
397         return properties.get (propertyId);
398
399     // unknown properties
400
throw new SAXNotRecognizedException (propertyId);
401     }
402
403     /**
404      * <b>SAX2</b>: Sets the state of feature flags in this parser. Some
405      * built-in feature flags are mutable; all flags not built-in are
406      * motable.
407      */

408     public void setFeature (String JavaDoc featureId, boolean state)
409     throws SAXNotRecognizedException, SAXNotSupportedException
410     {
411     boolean value;
412     
413     try {
414         // Features with a defined value, we just change it if we can.
415
value = getFeature (featureId);
416
417         if (state == value)
418         return;
419
420         if ((FEATURE + "namespace-prefixes").equals (featureId)) {
421         // in this implementation, this only affects xmlns reporting
422
xmlNames = state;
423         return;
424         }
425
426         if ((FEATURE + "namespaces").equals (featureId)) {
427         // XXX if not currently parsing ...
428
if (true) {
429             namespaces = state;
430             return;
431         }
432         // if in mid-parse, critical info hasn't been computed/saved
433
}
434
435         // can't change builtins
436
if (features == null || !features.containsKey (featureId))
437         throw new SAXNotSupportedException (featureId);
438
439     } catch (SAXNotRecognizedException e) {
440         // as-yet unknown features
441
if (features == null)
442         features = new HashMap (5);
443     }
444
445     // record first value, or modify existing one
446
features.put (featureId,
447         state
448         ? Boolean.TRUE
449         : Boolean.FALSE);
450     }
451
452     /**
453      * <b>SAX2</b>: Assigns the specified property. Like SAX1 handlers,
454      * these may be changed at any time.
455      */

456     public void setProperty (String JavaDoc propertyId, Object JavaDoc property)
457     throws SAXNotRecognizedException, SAXNotSupportedException
458     {
459     Object JavaDoc value;
460     
461     try {
462         // Properties with a defined value, we just change it if we can.
463
value = getProperty (propertyId);
464
465         if ((HANDLER + "declaration-handler").equals (propertyId)) {
466             if (property == null)
467                 declHandler = base;
468             else if (! (property instanceof DeclHandler JavaDoc))
469                 throw new SAXNotSupportedException (propertyId);
470             else
471                 declHandler = (DeclHandler JavaDoc) property;
472             return ;
473         }
474
475         if ((HANDLER + "lexical-handler").equals (propertyId)) {
476             if (property == null)
477                 lexicalHandler = base;
478             else if (! (property instanceof LexicalHandler JavaDoc))
479                 throw new SAXNotSupportedException (propertyId);
480             else
481                 lexicalHandler = (LexicalHandler JavaDoc) property;
482             return ;
483         }
484
485         // can't change builtins
486
if (properties == null || !properties.containsKey (propertyId))
487         throw new SAXNotSupportedException (propertyId);
488
489     } catch (SAXNotRecognizedException e) {
490         // as-yet unknown properties
491
if (properties == null)
492         properties = new HashMap (5);
493     }
494
495     // record first value, or modify existing one
496
properties.put (propertyId, property);
497     }
498
499
500     //
501
// This is where the driver receives AElfred callbacks and translates
502
// them into SAX callbacks. Some more callbacks have been added for
503
// SAX2 support.
504
//
505

506     // NOTE: in some cases, local copies of handlers are
507
// created and used, to work around codegen bugs in at
508
// least one snapshot version of GCJ.
509

510     void startDocument () throws SAXException
511     {
512         contentHandler.setDocumentLocator (this);
513         contentHandler.startDocument ();
514         attributeNames.clear ();
515         attributeValues.clear ();
516     }
517
518     void endDocument () throws SAXException
519     {
520         // SAX says endDocument _must_ be called (handy to close
521
// files etc) so it's in a "finally" clause
522
}
523
524     Object JavaDoc resolveEntity (String JavaDoc publicId, String JavaDoc systemId)
525     throws SAXException, IOException JavaDoc
526     {
527         InputSource source = entityResolver.resolveEntity (publicId,
528                      systemId);
529
530         if (source == null) {
531             return null;
532         } else if (source.getCharacterStream () != null) {
533             return source.getCharacterStream ();
534         } else if (source.getByteStream () != null) {
535             if (source.getEncoding () == null)
536             return source.getByteStream ();
537             else try {
538             return new InputStreamReader JavaDoc (
539                 source.getByteStream (),
540                 source.getEncoding ()
541                 );
542             } catch (IOException JavaDoc e) {
543             return source.getByteStream ();
544             }
545         } else {
546             return source.getSystemId ();
547         }
548         // XXX no way to tell AElfred about new public
549
// or system ids ... so relative URL resolution
550
// through that entity could be less than reliable.
551
}
552
553
554     void startExternalEntity (String JavaDoc systemId)
555     throws SAXException
556     {
557         entityStack.add (systemId);
558     }
559
560     void endExternalEntity (String JavaDoc systemId)
561     throws SAXException
562     {
563         entityStack.remove ( entityStack.size() - 1 );
564     }
565
566     void doctypeDecl (String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
567     throws SAXException
568     {
569         lexicalHandler.startDTD (name, publicId, systemId);
570     
571         // ... the "name" is a declaration and should be given
572
// to the DeclHandler (but sax2 beta doesn't).
573

574         // the IDs for the external subset are lexical details,
575
// as are the contents of the internal subset; but sax2
576
// beta only provides the external subset "pre-parse"
577
}
578
579     void endDoctype () throws SAXException
580     {
581         // NOTE: some apps may care that comments and PIs,
582
// are stripped from their DTD declaration context,
583
// and that those declarations are themselves quite
584
// thoroughly reordered here.
585

586         deliverDTDEvents ();
587         lexicalHandler.endDTD ();
588     }
589
590
591     void attribute (String JavaDoc aname, String JavaDoc value, boolean isSpecified)
592     throws SAXException
593     {
594         if (attributeCount++ == 0) {
595             if (namespaces)
596                 prefixStack.pushContext ();
597         }
598
599         // set nsTemp [0] == namespace URI (or empty)
600
// set nsTemp [1] == local name (or empty)
601
if (value != null) {
602             if (namespaces) {
603                 int index = aname.indexOf (':');
604
605                 // prefixed name?
606
if (index > 0) {
607                     // prefix declaration?
608
if (index == 5 && aname.startsWith ("xmlns")) {
609                         String JavaDoc prefix = aname.substring (index + 1);
610
611                         if (value.length () == 0) {
612                             errorHandler.error (new SAXParseException (
613                                 "missing URI in namespace decl attribute: "
614                                 + aname,
615                                 this));
616                         } else {
617                             prefixStack.declarePrefix (prefix, value);
618                             contentHandler.startPrefixMapping (prefix, value);
619                         }
620                         if (!xmlNames)
621                             return;
622                         nsTemp [0] = "";
623                         nsTemp [1] = aname;
624
625                     // prefix reference
626
} else {
627                         if (prefixStack.processName (aname, nsTemp, true)
628                             == null) {
629                             // start of MHK code
630
nsTemp[0] = "";
631                                 nsTemp[1] = aname; // defer checking till later
632
nspending = true;
633                             // end of MHK code
634
// start of previous code
635
// errorHandler.error (new SAXParseException (
636
// "undeclared name prefix in: " + aname,
637
// this));
638
// nsTemp [0] = nsTemp [1] = "";
639
// end of previous code
640
} // else nsTemp [0, 1] received { uri, local }
641
}
642
643                 // no prefix
644
} else {
645                     // default declaration?
646
if ("xmlns".equals (aname)) {
647                     prefixStack.declarePrefix ("", value);
648                     contentHandler.startPrefixMapping ("", value);
649                     if (!xmlNames)
650                         return;
651                     }
652                     nsTemp [0] = "";
653                     nsTemp [1] = aname;
654                 }
655             } else
656                 nsTemp [0] = nsTemp [1] = "";
657
658             attributeNamespaces.add (nsTemp [0]);
659             attributeLocalNames.add (nsTemp [1]);
660             attributeNames.add (aname);
661             // attribute type comes from querying parser's DTD records
662
attributeValues.add (value);
663         }
664     }
665
666     void startElement (String JavaDoc elname)
667     throws SAXException
668     {
669         ContentHandler handler = contentHandler;
670
671         //
672
// NOTE: this implementation of namespace support adds something
673
// like six percent to parsing CPU time, in a large (~50 MB)
674
// document that doesn't use namespaces at all. (Measured by PC
675
// sampling.)
676
//
677
// It ought to become notably faster in such cases. Most
678
// costs are the prefix stack calling Hashtable.get() (2%),
679
// String.hashCode() (1.5%) and about 1.3% each for pushing
680
// the context, and two chunks of name processing.
681
//
682

683         if (attributeCount == 0)
684             prefixStack.pushContext ();
685
686         // save element name so attribute callbacks work
687
elementName = elname;
688         if (namespaces) {
689             // START MHK CODE
690
// Check that namespace prefixes for attributes are valid
691
if (attributeCount > 0 && nspending) {
692                 for (int i=0; i<attributeLocalNames.size(); i++) {
693                     String JavaDoc aname = (String JavaDoc)attributeLocalNames.get(i);
694                     if (aname.indexOf(':')>0) {
695
696                         if (prefixStack.processName (aname, nsTemp, true) == null) {
697                             errorHandler.error (new SAXParseException (
698                                 "undeclared name prefix in: " + aname,
699                                 this));
700                         } else {
701                             attributeNamespaces.set(i, nsTemp[0]);
702                             attributeLocalNames.set(i, nsTemp[1]);
703                         }
704                     }
705                 }
706             }
707             // END MHK CODE
708

709             if (prefixStack.processName (elname, nsTemp, false) == null) {
710             errorHandler.error (new SAXParseException (
711                 "undeclared name prefix in: " + elname,
712                 this));
713             nsTemp [0] = nsTemp [1] = "";
714             }
715
716             handler.startElement (nsTemp [0], nsTemp [1], elname, this);
717         } else
718             handler.startElement ("", "", elname, this);
719         // elementName = null;
720

721         // elements with no attributes are pretty common!
722
if (attributeCount != 0) {
723             attributeNames.clear ();
724             attributeNamespaces.clear ();
725             attributeLocalNames.clear ();
726             attributeValues.clear ();
727             attributeCount = 0;
728         }
729         nspending = false;
730     }
731
732     void endElement (String JavaDoc elname)
733     throws SAXException
734     {
735         ContentHandler handler = contentHandler;
736
737         handler.endElement ("", "", elname);
738
739         if (!namespaces)
740             return;
741
742         Enumeration prefixes = prefixStack.getDeclaredPrefixes ();
743
744         while (prefixes.hasMoreElements ())
745             handler.endPrefixMapping ((String JavaDoc) prefixes.nextElement ());
746         prefixStack.popContext ();
747     }
748
749     void startCDATA ()
750     throws SAXException
751     {
752         lexicalHandler.startCDATA ();
753     }
754
755     void charData (char ch[], int start, int length)
756     throws SAXException
757     {
758         contentHandler.characters (ch, start, length);
759     }
760
761     void endCDATA ()
762     throws SAXException
763     {
764         lexicalHandler.endCDATA ();
765     }
766
767     void ignorableWhitespace (char ch[], int start, int length)
768     throws SAXException
769     {
770         contentHandler.ignorableWhitespace (ch, start, length);
771     }
772
773     void processingInstruction (String JavaDoc target, String JavaDoc data)
774     throws SAXException
775     {
776         // XXX if within DTD, perhaps it's best to discard
777
// PIs since the decls to which they (usually)
778
// apply get significantly rearranged
779

780         contentHandler.processingInstruction (target, data);
781     }
782
783     void comment (char ch[], int start, int length)
784     throws SAXException
785     {
786         // XXX if within DTD, perhaps it's best to discard
787
// comments since the decls to which they (usually)
788
// apply get significantly rearranged
789

790         if (lexicalHandler != base)
791             lexicalHandler.comment (ch, start, length);
792     }
793
794         // AElfred only has fatal errors
795
void error (String JavaDoc message, String JavaDoc url, int line, int column)
796         throws SAXException
797         {
798         SAXParseException fatal;
799     
800         fatal = new SAXParseException (message, null, url, line, column);
801         errorHandler.fatalError (fatal);
802
803         // Even if the application can continue ... we can't!
804
throw fatal;
805     }
806
807
808     //
809
// Before the endDtd event, deliver all non-PE declarations.
810
//
811
private void deliverDTDEvents ()
812     throws SAXException
813     {
814     String JavaDoc ename;
815     String JavaDoc nname;
816     String JavaDoc publicId;
817     String JavaDoc systemId;
818
819     // First, report all notations.
820
if (dtdHandler != base) {
821         Iterator notationNames = parser.declaredNotations ();
822
823         while (notationNames.hasNext ()) {
824         nname = (String JavaDoc) notationNames.next ();
825         publicId = parser.getNotationPublicId (nname);
826         systemId = parser.getNotationSystemId (nname);
827         dtdHandler.notationDecl (nname, publicId, systemId);
828         }
829     }
830
831     // Next, report all entities.
832
if (dtdHandler != base || declHandler != base) {
833         Iterator entityNames = parser.declaredEntities ();
834         int type;
835
836         while (entityNames.hasNext ()) {
837         ename = (String JavaDoc) entityNames.next ();
838         type = parser.getEntityType (ename);
839
840         if (ename.charAt (0) == '%')
841             continue;
842
843         // unparsed
844
if (type == XmlParser.ENTITY_NDATA) {
845             publicId = parser.getEntityPublicId (ename);
846             systemId = parser.getEntitySystemId (ename);
847             nname = parser.getEntityNotationName (ename);
848             dtdHandler.unparsedEntityDecl (ename,
849                             publicId, systemId, nname);
850
851             // external parsed
852
}
853         else if (type == XmlParser.ENTITY_TEXT) {
854             publicId = parser.getEntityPublicId (ename);
855             systemId = parser.getEntitySystemId (ename);
856             declHandler.externalEntityDecl (ename,
857                              publicId, systemId);
858
859             // internal parsed
860
}
861         else if (type == XmlParser.ENTITY_INTERNAL) {
862             // filter out the built-ins; even if they were
863
// declared, they didn't need to be.
864
if ("lt".equals (ename) || "gt".equals (ename)
865                 || "quot".equals (ename)
866                 || "apos".equals (ename)
867                 || "amp".equals (ename))
868             continue;
869             declHandler.internalEntityDecl (ename,
870                  parser.getEntityValue (ename));
871         }
872         }
873     }
874
875     // elements, attributes
876
if (declHandler != base) {
877         Iterator elementNames = parser.declaredElements ();
878         Iterator attNames;
879
880         while (elementNames.hasNext ()) {
881         String JavaDoc model = null;
882
883         ename = (String JavaDoc) elementNames.next ();
884         switch (parser.getElementContentType (ename)) {
885             case XmlParser.CONTENT_ANY:
886             model = "ANY";
887             break;
888             case XmlParser.CONTENT_EMPTY:
889             model = "EMPTY";
890             break;
891             case XmlParser.CONTENT_MIXED:
892             case XmlParser.CONTENT_ELEMENTS:
893             model = parser.getElementContentModel (ename);
894             break;
895             case XmlParser.CONTENT_UNDECLARED:
896             default:
897             model = null;
898             break;
899         }
900         if (model != null)
901             declHandler.elementDecl (ename, model);
902
903         attNames = parser.declaredAttributes (ename);
904         while (attNames != null && attNames.hasNext ()) {
905             String JavaDoc aname = (String JavaDoc) attNames.next ();
906             String JavaDoc type;
907             String JavaDoc valueDefault;
908             String JavaDoc value;
909
910             switch (parser.getAttributeType (ename, aname)) {
911             case XmlParser.ATTRIBUTE_CDATA:
912             type = "CDATA";
913             break;
914             case XmlParser.ATTRIBUTE_ENTITY:
915             type = "ENTITY";
916             break;
917             case XmlParser.ATTRIBUTE_ENTITIES:
918             type = "ENTITIES";
919             break;
920             case XmlParser.ATTRIBUTE_ENUMERATED:
921             type = parser.getAttributeIterator (ename, aname);
922             break;
923             case XmlParser.ATTRIBUTE_ID:
924             type = "ID";
925             break;
926             case XmlParser.ATTRIBUTE_IDREF:
927             type = "IDREF";
928             break;
929             case XmlParser.ATTRIBUTE_IDREFS:
930             type = "IDREFS";
931             break;
932             case XmlParser.ATTRIBUTE_NMTOKEN:
933             type = "NMTOKEN";
934             break;
935             case XmlParser.ATTRIBUTE_NMTOKENS:
936             type = "NMTOKENS";
937             break;
938
939             // XXX SAX2 beta doesn't have a way to return the
940
// enumerated list of permitted notations ... SAX1
941
// kluged it as NMTOKEN, but that won't work for
942
// the sort of apps that really use the DTD info
943
case XmlParser.ATTRIBUTE_NOTATION:
944             type = "NOTATION";
945             break;
946
947             default:
948             errorHandler.fatalError (new SAXParseException (
949                   "internal error, att type", this));
950             type = null;
951             }
952
953             switch (parser.getAttributeDefaultValueType (
954                  ename, aname)) {
955             case XmlParser.ATTRIBUTE_DEFAULT_IMPLIED:
956             valueDefault = "#IMPLIED";
957             break;
958             case XmlParser.ATTRIBUTE_DEFAULT_REQUIRED:
959             valueDefault = "#REQUIRED";
960             break;
961             case XmlParser.ATTRIBUTE_DEFAULT_FIXED:
962             valueDefault = "#FIXED";
963             break;
964             case XmlParser.ATTRIBUTE_DEFAULT_SPECIFIED:
965             valueDefault = null;
966             break;
967
968             default:
969             errorHandler.fatalError (new SAXParseException (
970                     "internal error, att default", this));
971             valueDefault = null;
972             }
973
974             value = parser.getAttributeDefaultValue (ename, aname);
975
976             declHandler.attributeDecl (ename, aname,
977                         type, valueDefault, value);
978         }
979         }
980     }
981     }
982
983
984     //
985
// Implementation of org.xml.sax.Attributes.
986
//
987

988     /**
989      * <b>SAX1 AttributeList, SAX2 Attributes</b> method
990      * (don't invoke on parser);
991      */

992     public int getLength ()
993     {
994         return attributeNames.size ();
995     }
996
997     /**
998      * <b>SAX2 Attributes</b> method (don't invoke on parser);
999      */

1000    public String JavaDoc getURI (int index)
1001    {
1002        return (String JavaDoc) (attributeNamespaces.get (index));
1003    }
1004
1005    /**
1006     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1007     */

1008    public String JavaDoc getLocalName (int index)
1009    {
1010        return (String JavaDoc) (attributeLocalNames.get (index));
1011    }
1012
1013    /**
1014     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1015     */

1016    public String JavaDoc getQName (int i)
1017    {
1018        return (String JavaDoc) (attributeNames.get (i));
1019    }
1020
1021    /**
1022     * <b>SAX1 AttributeList</b> method (don't invoke on parser);
1023     */

1024    public String JavaDoc getName (int i)
1025    {
1026        return (String JavaDoc) (attributeNames.get (i));
1027    }
1028
1029    /**
1030     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1031     * (don't invoke on parser);
1032     */

1033    public String JavaDoc getType (int i)
1034    {
1035    switch (parser.getAttributeType (elementName, getQName (i))) {
1036
1037    case XmlParser.ATTRIBUTE_UNDECLARED:
1038    case XmlParser.ATTRIBUTE_CDATA:
1039        return "CDATA";
1040    case XmlParser.ATTRIBUTE_ID:
1041        return "ID";
1042    case XmlParser.ATTRIBUTE_IDREF:
1043        return "IDREF";
1044    case XmlParser.ATTRIBUTE_IDREFS:
1045        return "IDREFS";
1046    case XmlParser.ATTRIBUTE_ENTITY:
1047        return "ENTITY";
1048    case XmlParser.ATTRIBUTE_ENTITIES:
1049        return "ENTITIES";
1050    case XmlParser.ATTRIBUTE_ENUMERATED:
1051        // XXX doesn't have a way to return permitted enum values,
1052
// though they must each be a NMTOKEN
1053
case XmlParser.ATTRIBUTE_NMTOKEN:
1054        return "NMTOKEN";
1055    case XmlParser.ATTRIBUTE_NMTOKENS:
1056        return "NMTOKENS";
1057    case XmlParser.ATTRIBUTE_NOTATION:
1058        // XXX doesn't have a way to return the permitted values,
1059
// each of which must be name a declared notation
1060
return "NOTATION";
1061
1062    }
1063
1064    return null;
1065    }
1066
1067
1068    /**
1069     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1070     * (don't invoke on parser);
1071     */

1072    public String JavaDoc getValue (int i)
1073    {
1074        return (String JavaDoc) (attributeValues.get (i));
1075    }
1076
1077
1078    /**
1079     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1080     */

1081    public int getIndex (String JavaDoc uri, String JavaDoc local)
1082    {
1083        int length = getLength ();
1084
1085        for (int i = 0; i < length; i++) {
1086            if (!getURI (i).equals (uri))
1087            continue;
1088            if (getLocalName (i).equals (local))
1089            return i;
1090        }
1091        return -1;
1092    }
1093
1094
1095    /**
1096     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1097     */

1098    public int getIndex (String JavaDoc xmlName)
1099    {
1100        int length = getLength ();
1101
1102        for (int i = 0; i < length; i++) {
1103            if (getQName (i).equals (xmlName))
1104            return i;
1105        }
1106        return -1;
1107    }
1108
1109
1110    /**
1111     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1112     */

1113    public String JavaDoc getType (String JavaDoc uri, String JavaDoc local)
1114    {
1115        int index = getIndex (uri, local);
1116
1117        if (index < 0)
1118            return null;
1119        return getType (index);
1120    }
1121
1122
1123    /**
1124     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1125     * (don't invoke on parser);
1126     */

1127    public String JavaDoc getType (String JavaDoc xmlName)
1128    {
1129        int index = getIndex (xmlName);
1130
1131        if (index < 0)
1132            return null;
1133        return getType (index);
1134    }
1135
1136
1137    /**
1138     * <b>SAX Attributes</b> method (don't invoke on parser);
1139     */

1140    public String JavaDoc getValue (String JavaDoc uri, String JavaDoc local)
1141    {
1142        int index = getIndex (uri, local);
1143
1144        if (index < 0)
1145            return null;
1146        return getValue (index);
1147    }
1148
1149
1150    /**
1151     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1152     * (don't invoke on parser);
1153     */

1154    public String JavaDoc getValue (String JavaDoc xmlName)
1155    {
1156        int index = getIndex (xmlName);
1157
1158        if (index < 0)
1159            return null;
1160        return getValue (index);
1161    }
1162
1163
1164    //
1165
// Implementation of org.xml.sax.Locator.
1166
//
1167

1168    /**
1169     * <b>SAX Locator</b> method (don't invoke on parser);
1170     */

1171    public String JavaDoc getPublicId ()
1172    {
1173        return null; // XXX track public IDs too
1174
}
1175
1176    /**
1177     * <b>SAX Locator</b> method (don't invoke on parser);
1178     */

1179    public String JavaDoc getSystemId ()
1180    {
1181        return (String JavaDoc) entityStack.get ( entityStack.size() - 1 );
1182    }
1183
1184    /**
1185     * <b>SAX Locator</b> method (don't invoke on parser);
1186     */

1187    public int getLineNumber ()
1188    {
1189        return parser.getLineNumber ();
1190    }
1191
1192    /**
1193     * <b>SAX Locator</b> method (don't invoke on parser);
1194     */

1195    public int getColumnNumber ()
1196    {
1197        return parser.getColumnNumber ();
1198    }
1199
1200    // adapter between content handler and document handler callbacks
1201

1202    private static class Adapter implements ContentHandler
1203    {
1204        private DocumentHandler docHandler;
1205
1206        Adapter (DocumentHandler dh)
1207            { docHandler = dh; }
1208
1209
1210        public void setDocumentLocator (Locator l)
1211            { docHandler.setDocumentLocator (l); }
1212    
1213        public void startDocument () throws SAXException
1214            { docHandler.startDocument (); }
1215    
1216        public void processingInstruction (String JavaDoc target, String JavaDoc data)
1217        throws SAXException
1218            { docHandler.processingInstruction (target, data); }
1219    
1220        public void startPrefixMapping (String JavaDoc prefix, String JavaDoc uri)
1221            { /* ignored */ }
1222
1223        public void startElement (
1224            String JavaDoc namespace,
1225            String JavaDoc local,
1226            String JavaDoc name,
1227            Attributes attrs ) throws SAXException
1228        {
1229            docHandler.startElement (name, (AttributeList) attrs);
1230        }
1231
1232        public void characters (char buf [], int offset, int len)
1233        throws SAXException
1234        {
1235            docHandler.characters (buf, offset, len);
1236        }
1237
1238        public void ignorableWhitespace (char buf [], int offset, int len)
1239        throws SAXException
1240        {
1241            docHandler.ignorableWhitespace (buf, offset, len);
1242        }
1243
1244        public void skippedEntity (String JavaDoc name)
1245            { /* ignored */ }
1246
1247        public void endElement (String JavaDoc u, String JavaDoc l, String JavaDoc name)
1248        throws SAXException
1249            { docHandler.endElement (name); }
1250
1251        public void endPrefixMapping (String JavaDoc prefix)
1252            { /* ignored */ }
1253
1254        public void endDocument () throws SAXException
1255            { docHandler.endDocument (); }
1256    }
1257}
1258
1259
Popular Tags