KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > 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 net.sf.saxon.aelfred;
32
33 import java.io.InputStreamReader JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.Reader JavaDoc;
36 import java.io.File JavaDoc;
37 import java.util.Enumeration JavaDoc;
38 import java.util.Hashtable JavaDoc;
39 import java.util.Locale JavaDoc;
40 import java.util.Stack JavaDoc;
41 import java.util.Vector JavaDoc;
42 import java.net.URL JavaDoc;
43 import java.net.MalformedURLException JavaDoc;
44
45 import org.xml.sax.*;
46 import org.xml.sax.ext.*;
47 import org.xml.sax.helpers.NamespaceSupport JavaDoc;
48
49 //import org.brownell.xml.DefaultHandler;
50
import net.sf.saxon.aelfred.DefaultHandler;
51
52
53 // $Id: SAXDriver.java,v 1.21 2000/02/29 00:23:50 mojo Exp $
54

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

117 public class SAXDriver
118     implements Locator, Attributes, XMLReader, Parser, AttributeList
119 {
120     private final DefaultHandler base = new DefaultHandler ();
121     private XmlParser parser;
122
123     private EntityResolver entityResolver = base;
124     private ContentHandler contentHandler = base;
125     private DTDHandler dtdHandler = base;
126     private ErrorHandler errorHandler = base;
127     private DeclHandler declHandler = base;
128     private LexicalHandler lexicalHandler = base;
129
130     private String JavaDoc elementName = null;
131     private Stack JavaDoc entityStack = new Stack JavaDoc ();
132
133     private Vector JavaDoc attributeNames = new Vector JavaDoc ();
134     private Vector JavaDoc attributeNamespaces = new Vector JavaDoc ();
135     private Vector JavaDoc attributeLocalNames = new Vector JavaDoc ();
136     private Vector JavaDoc attributeValues = new Vector JavaDoc ();
137
138     private boolean namespaces = true;
139     private boolean xmlNames = false;
140     private boolean nspending = false; // indicates an attribute was read before its
141
// namespace declaration
142

143     private int attributeCount = 0;
144     private String JavaDoc nsTemp [] = new String JavaDoc [3];
145     private NamespaceSupport JavaDoc prefixStack = new NamespaceSupport JavaDoc ();
146
147     private Hashtable JavaDoc features;
148     private Hashtable JavaDoc properties;
149
150
151     //
152
// Constructor.
153
//
154

155     /** Constructs a SAX Parser. */
156     public SAXDriver () {}
157
158
159     //
160
// Implementation of org.xml.sax.Parser.
161
//
162

163     /**
164      * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
165      * only locales using the English language are supported.
166      * @param locale The locale for which diagnostics will be generated
167      */

168     public void setLocale (Locale JavaDoc locale)
169     throws SAXException
170     {
171     if ("en".equals (locale.getLanguage ()))
172         return ;
173
174     throw new SAXException ("AElfred only supports English locales.");
175     }
176
177
178     /**
179      * <b>SAX2</b>: Returns the object used when resolving external
180      * entities during parsing (both general and parameter entities).
181      */

182     public EntityResolver getEntityResolver ()
183     {
184     return entityResolver;
185     }
186
187     /**
188      * <b>SAX1, SAX2</b>: Set the entity resolver for this parser.
189      * @param handler The object to receive entity events.
190      */

191     public void setEntityResolver (EntityResolver resolver)
192     {
193     if (resolver == null)
194         resolver = base;
195     this.entityResolver = resolver;
196     }
197
198
199     /**
200      * <b>SAX2</b>: Returns the object used to process declarations related
201      * to notations and unparsed entities.
202      */

203     public DTDHandler getDTDHandler ()
204     {
205     return dtdHandler;
206     }
207
208     /**
209      * <b>SAX1, SAX2</b>: Set the DTD handler for this parser.
210      * @param handler The object to receive DTD events.
211      */

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

232     public void setDocumentHandler (DocumentHandler handler)
233     {
234     contentHandler = new Adapter (handler);
235     xmlNames = true;
236     }
237
238     /**
239      * <b>SAX2</b>: Returns the object used to report the logical
240      * content of an XML document.
241      */

242     public ContentHandler getContentHandler ()
243     {
244     return contentHandler;
245     }
246
247     /**
248      * <b>SAX2</b>: Assigns the object used to report the logical
249      * content of an XML document. If a document handler was set,
250      * this content handler will supplant it (but XML 1.0 style name
251      * reporting may remain enabled).
252      */

253     public void setContentHandler (ContentHandler handler)
254     {
255         if (handler == null)
256             handler = base;
257         contentHandler = handler;
258     }
259
260     /**
261      * <b>SAX1, SAX2</b>: Set the error handler for this parser.
262      * @param handler The object to receive error events.
263      */

264     public void setErrorHandler (ErrorHandler handler)
265     {
266         if (handler == null)
267             handler = base;
268         this.errorHandler = handler;
269     }
270
271     /**
272      * <b>SAX2</b>: Returns the object used to receive callbacks for XML
273      * errors of all levels (fatal, nonfatal, warning); this is never null;
274      */

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

297      
298     public void parse (InputSource source) throws SAXException, IOException JavaDoc
299     {
300         synchronized (base) {
301             parser = new XmlParser ();
302             parser.setHandler (this);
303
304             try {
305                 String JavaDoc systemId = source.getSystemId ();
306                 // MHK addition. SAX2 says the systemId supplied must be absolute.
307
// But often it isn't. This code tries, if necessary, to expand it
308
// relative to the current working directory
309

310                 systemId = tryToExpand(systemId);
311
312                 // duplicate first entry, in case startDocument handler
313
// needs to use Locator.getSystemId(), before entities
314
// start to get reported by the parser
315

316                 //if (systemId != null)
317
entityStack.push (systemId);
318                 //else // can't happen after tryToExpand()
319
// entityStack.push ("illegal:unknown system ID");
320

321                 parser.doParse (systemId,
322                           source.getPublicId (),
323                           source.getCharacterStream (),
324                           source.getByteStream (),
325                           source.getEncoding ());
326             } catch (SAXException e) {
327                 throw e;
328             } catch (IOException JavaDoc e) {
329                 throw e;
330             } catch (RuntimeException JavaDoc e) {
331                 throw e;
332             } catch (Exception JavaDoc e) {
333                 throw new SAXException (e.getMessage (), e);
334             } finally {
335                 contentHandler.endDocument ();
336                 entityStack.removeAllElements ();
337             }
338         }
339     }
340
341
342     /**
343      * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a
344      * system identifier (URI).
345      */

346      
347     public void parse (String JavaDoc systemId) throws SAXException, IOException JavaDoc
348     {
349         parse (new InputSource (systemId));
350     }
351
352     //
353
// Implementation of SAX2 "XMLReader" interface
354
//
355
static final String JavaDoc FEATURE = "http://xml.org/sax/features/";
356     static final String JavaDoc HANDLER = "http://xml.org/sax/properties/";
357
358     /**
359      * <b>SAX2</b>: Tells the value of the specified feature flag.
360      *
361      * @exception SAXNotRecognizedException thrown if the feature flag
362      * is neither built in, nor yet assigned.
363      */

364     public boolean getFeature (String JavaDoc featureId)
365     throws SAXNotRecognizedException
366     {
367     if ((FEATURE + "validation").equals (featureId))
368         return false;
369
370     // external entities (both types) are currently always included
371
if ((FEATURE + "external-general-entities").equals (featureId)
372         || (FEATURE + "external-parameter-entities").equals (featureId))
373         return true;
374
375     // element/attribute names are as written in document; no mangling
376
if ((FEATURE + "namespace-prefixes").equals (featureId))
377         return xmlNames;
378
379     // report element/attribute namespaces?
380
if ((FEATURE + "namespaces").equals (featureId))
381         return namespaces;
382
383     // XXX always provides a locator ... removed in beta
384

385     // always interns
386
if ((FEATURE + "string-interning").equals (featureId))
387         return true;
388
389     if (features != null && features.containsKey (featureId))
390         return ((Boolean JavaDoc)features.get (featureId)).booleanValue ();
391
392     throw new SAXNotRecognizedException (featureId);
393     }
394
395     /**
396      * <b>SAX2</b>: Returns the specified property.
397      *
398      * @exception SAXNotRecognizedException thrown if the property value
399      * is neither built in, nor yet stored.
400      */

401     public Object JavaDoc getProperty (String JavaDoc propertyId)
402     throws SAXNotRecognizedException
403     {
404     if ((HANDLER + "declaration-handler").equals (propertyId))
405         return declHandler;
406
407     if ((HANDLER + "lexical-handler").equals (propertyId))
408         return lexicalHandler;
409     
410     if (properties != null && properties.containsKey (propertyId))
411         return properties.get (propertyId);
412
413     // unknown properties
414
throw new SAXNotRecognizedException (propertyId);
415     }
416
417     /**
418      * <b>SAX2</b>: Sets the state of feature flags in this parser. Some
419      * built-in feature flags are mutable; all flags not built-in are
420      * motable.
421      */

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

470     public void setProperty (String JavaDoc propertyId, Object JavaDoc property)
471     throws SAXNotRecognizedException, SAXNotSupportedException
472     {
473     Object JavaDoc value;
474     
475     try {
476         // Properties with a defined value, we just change it if we can.
477
value = getProperty (propertyId);
478
479         if ((HANDLER + "declaration-handler").equals (propertyId)) {
480             if (property == null)
481                 declHandler = base;
482             else if (! (property instanceof DeclHandler))
483                 throw new SAXNotSupportedException (propertyId);
484             else
485                 declHandler = (DeclHandler) property;
486             return ;
487         }
488
489         if ((HANDLER + "lexical-handler").equals (propertyId) ||
490              "http://xml.org/sax/handlers/LexicalHandler".equals(propertyId)) {
491                     // the latter name is used in some SAX2 beta software
492
if (property == null)
493                 lexicalHandler = base;
494             else if (! (property instanceof LexicalHandler))
495                 throw new SAXNotSupportedException (propertyId);
496             else
497                 lexicalHandler = (LexicalHandler) property;
498             return ;
499         }
500
501         // can't change builtins
502
if (properties == null || !properties.containsKey (propertyId))
503         throw new SAXNotSupportedException (propertyId);
504
505     } catch (SAXNotRecognizedException e) {
506         // as-yet unknown properties
507
if (properties == null)
508         properties = new Hashtable JavaDoc (5);
509     }
510
511     // record first value, or modify existing one
512
properties.put (propertyId, property);
513     }
514
515
516     //
517
// This is where the driver receives AElfred callbacks and translates
518
// them into SAX callbacks. Some more callbacks have been added for
519
// SAX2 support.
520
//
521

522     // NOTE: in some cases, local copies of handlers are
523
// created and used, to work around codegen bugs in at
524
// least one snapshot version of GCJ.
525

526     void startDocument () throws SAXException
527     {
528         contentHandler.setDocumentLocator (this);
529         contentHandler.startDocument ();
530         attributeNames.removeAllElements ();
531         attributeValues.removeAllElements ();
532     }
533
534     void endDocument () throws SAXException
535     {
536         // SAX says endDocument _must_ be called (handy to close
537
// files etc) so it's in a "finally" clause
538
}
539
540     Object JavaDoc resolveEntity (String JavaDoc publicId, String JavaDoc systemId)
541     throws SAXException, IOException JavaDoc
542     {
543         InputSource source = entityResolver.resolveEntity (publicId,
544                      systemId);
545
546         if (source == null) {
547             return null;
548         } else if (source.getCharacterStream () != null) {
549             return source.getCharacterStream ();
550         } else if (source.getByteStream () != null) {
551             if (source.getEncoding () == null)
552             return source.getByteStream ();
553             else try {
554             return new InputStreamReader JavaDoc (
555                 source.getByteStream (),
556                 source.getEncoding ()
557                 );
558             } catch (IOException JavaDoc e) {
559             return source.getByteStream ();
560             }
561         } else {
562             String JavaDoc sysId = source.getSystemId ();
563             return tryToExpand(sysId); // MHK addition
564
}
565         // XXX no way to tell AElfred about new public
566
// or system ids ... so relative URL resolution
567
// through that entity could be less than reliable.
568
}
569
570     void startExternalEntity (String JavaDoc systemId)
571     throws SAXException
572     {
573         entityStack.push (systemId);
574     }
575
576     void endExternalEntity (String JavaDoc systemId)
577     throws SAXException
578     {
579         entityStack.pop ();
580     }
581
582     void doctypeDecl (String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
583     throws SAXException
584     {
585         lexicalHandler.startDTD (name, publicId, systemId);
586     
587         // ... the "name" is a declaration and should be given
588
// to the DeclHandler (but sax2 beta doesn't).
589

590         // the IDs for the external subset are lexical details,
591
// as are the contents of the internal subset; but sax2
592
// beta only provides the external subset "pre-parse"
593
}
594
595     void endDoctype () throws SAXException
596     {
597         // NOTE: some apps may care that comments and PIs,
598
// are stripped from their DTD declaration context,
599
// and that those declarations are themselves quite
600
// thoroughly reordered here.
601

602         deliverDTDEvents ();
603         lexicalHandler.endDTD ();
604     }
605
606
607     void attribute (String JavaDoc aname, String JavaDoc value, boolean isSpecified)
608     throws SAXException
609     {
610         // Code changed by MHK 16 April 2001.
611
// The only safe thing to do is to process all the namespace declarations
612
// first, then process the ordinary attributes. So if this is a namespace
613
// declaration, we deal with it now, otherwise we save it till we get the
614
// startElement call.
615

616         if (attributeCount++ == 0) {
617             if (namespaces) {
618                 prefixStack.pushContext ();
619             }
620         }
621
622         // set nsTemp [0] == namespace URI (or empty)
623
// set nsTemp [1] == local name (or empty)
624
if (value == null) {
625             // MHK: I think this can only happen on an error recovery path
626
// MHK: I was wrong: AElfred was notifying null values of attribute
627
// declared in the DTD as #IMPLIED. But I've now changed it so it doesn't.
628
return;
629         }
630         
631         if (namespaces && aname.startsWith("xmlns")) {
632             if (aname.length() == 5) {
633                 prefixStack.declarePrefix ("", value);
634                 //System.err.println("Declare default prefix = "+value);
635
contentHandler.startPrefixMapping ("", value);
636             
637             } else if (aname.charAt(5)==':' && !aname.equals("xmlns:xml")) {
638
639                 if (aname.length() == 6) {
640                     errorHandler.error (new SAXParseException (
641                         "Missing namespace prefix in namespace declaration: " + aname,
642                         this));
643                     return;
644                 }
645                 String JavaDoc prefix = aname.substring (6);
646
647                 if (value.length() == 0) {
648                     errorHandler.error (new SAXParseException (
649                         "Missing URI in namespace declaration: " + aname,
650                         this));
651                     return;
652                 }
653                 prefixStack.declarePrefix (prefix, value);
654                 //System.err.println("Declare prefix " +prefix+"="+value);
655
contentHandler.startPrefixMapping (prefix, value);
656             }
657
658             if (!xmlNames) {
659                 // if xmlNames option wasn't selected,
660
// we don't report xmlns:* declarations as attributes
661
return;
662             }
663         }
664
665         attributeNames.addElement (aname);
666         attributeValues.addElement (value);
667     }
668
669     void startElement (String JavaDoc elname)
670     throws SAXException
671     {
672         ContentHandler handler = contentHandler;
673
674         if (attributeCount == 0)
675             prefixStack.pushContext ();
676
677         // save element name so attribute callbacks work
678
elementName = elname;
679         if (namespaces) {
680
681             // Expand namespace prefix for all attributes
682
if (attributeCount > 0) {
683                 for (int i=0; i<attributeNames.size(); i++) {
684                     String JavaDoc aname = (String JavaDoc)attributeNames.elementAt(i);
685                     if (aname.indexOf(':')>0) {
686                         if (xmlNames && aname.startsWith("xmlns:")) {
687                             attributeNamespaces.addElement("");
688                             attributeLocalNames.addElement(aname);
689
690                         } else if (prefixStack.processName (aname, nsTemp, true) == null) {
691                             errorHandler.error (new SAXParseException (
692                                 "undeclared name prefix in: " + aname,
693                                 this));
694                             // recovery action: substitute a name in default namespace
695
attributeNamespaces.addElement("");
696                             attributeLocalNames.addElement(aname.substring(aname.indexOf(':')));
697                         } else {
698                             attributeNamespaces.addElement(nsTemp[0]);
699                             attributeLocalNames.addElement(nsTemp[1]);
700                         }
701                     } else {
702                         attributeNamespaces.addElement("");
703                         attributeLocalNames.addElement(aname);
704                     }
705                     // check uniquess of the attribute expanded name
706
for (int j=0; j<i; j++) {
707                         if (attributeNamespaces.elementAt(i) == attributeNamespaces.elementAt(j) &&
708                             attributeLocalNames.elementAt(i) == attributeLocalNames.elementAt(j)) {
709                                 errorHandler.error( new SAXParseException (
710                                     "duplicate attribute name: " + attributeLocalNames.elementAt(j),
711                                     this));
712                         }
713                     }
714                 }
715             }
716
717             if (prefixStack.processName (elname, nsTemp, false) == null) {
718                 errorHandler.error (new SAXParseException (
719                     "undeclared name prefix in: " + elname,
720                     this));
721                 nsTemp [0] = nsTemp [1] = "";
722                 // recovery action
723
elname = elname.substring(elname.indexOf(':'));
724             }
725             handler.startElement (nsTemp [0], nsTemp [1], elname, this);
726         } else
727             handler.startElement ("", "", elname, this);
728         // elementName = null;
729

730         // elements with no attributes are pretty common!
731
if (attributeCount != 0) {
732             attributeNames.removeAllElements ();
733             attributeNamespaces.removeAllElements ();
734             attributeLocalNames.removeAllElements ();
735             attributeValues.removeAllElements ();
736             attributeCount = 0;
737         }
738         nspending = false;
739     }
740
741     void endElement (String JavaDoc elname)
742     throws SAXException
743     {
744         ContentHandler handler = contentHandler;
745
746         if (!namespaces) {
747             handler.endElement("", "", elname);
748             return;
749         }
750         
751         // following code added by MHK to fix bug Saxon 6.1/013
752
if (prefixStack.processName (elname, nsTemp, false) == null) {
753             // shouldn't happen
754
errorHandler.error (new SAXParseException (
755                 "undeclared name prefix in: " + elname, this));
756             nsTemp [0] = nsTemp [1] = "";
757             elname = elname.substring(elname.indexOf(':'));
758         }
759
760         handler.endElement (nsTemp[0], nsTemp[1], elname);
761         
762         // previous code (clearly wrong): handler.endElement ("", "", elname);
763

764         // end of MHK addition
765

766
767         Enumeration JavaDoc prefixes = prefixStack.getDeclaredPrefixes ();
768
769         while (prefixes.hasMoreElements ())
770             handler.endPrefixMapping ((String JavaDoc) prefixes.nextElement ());
771         prefixStack.popContext ();
772     }
773
774     void startCDATA ()
775     throws SAXException
776     {
777         lexicalHandler.startCDATA ();
778     }
779
780     void charData (char ch[], int start, int length)
781     throws SAXException
782     {
783         contentHandler.characters (ch, start, length);
784     }
785
786     void endCDATA ()
787     throws SAXException
788     {
789         lexicalHandler.endCDATA ();
790     }
791
792     void ignorableWhitespace (char ch[], int start, int length)
793     throws SAXException
794     {
795         contentHandler.ignorableWhitespace (ch, start, length);
796     }
797
798     void processingInstruction (String JavaDoc target, String JavaDoc data)
799     throws SAXException
800     {
801         // XXX if within DTD, perhaps it's best to discard
802
// PIs since the decls to which they (usually)
803
// apply get significantly rearranged
804

805         contentHandler.processingInstruction (target, data);
806     }
807
808     void comment (char ch[], int start, int length)
809     throws SAXException
810     {
811         // XXX if within DTD, perhaps it's best to discard
812
// comments since the decls to which they (usually)
813
// apply get significantly rearranged
814

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

1013    /**
1014     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1015     * (don't invoke on parser);
1016     */

1017    public int getLength ()
1018    {
1019        return attributeNames.size ();
1020    }
1021
1022    /**
1023     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1024     */

1025    public String JavaDoc getURI (int index)
1026    {
1027        return (String JavaDoc) (attributeNamespaces.elementAt (index));
1028    }
1029
1030    /**
1031     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1032     */

1033    public String JavaDoc getLocalName (int index)
1034    {
1035        return (String JavaDoc) (attributeLocalNames.elementAt (index));
1036    }
1037
1038    /**
1039     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1040     */

1041    public String JavaDoc getQName (int i)
1042    {
1043        return (String JavaDoc) (attributeNames.elementAt (i));
1044    }
1045
1046    /**
1047     * <b>SAX1 AttributeList</b> method (don't invoke on parser);
1048     */

1049    public String JavaDoc getName (int i)
1050    {
1051        return (String JavaDoc) (attributeNames.elementAt (i));
1052    }
1053
1054    /**
1055     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1056     * (don't invoke on parser);
1057     */

1058    public String JavaDoc getType (int i)
1059    {
1060    switch (parser.getAttributeType (elementName, getQName (i))) {
1061
1062    case XmlParser.ATTRIBUTE_UNDECLARED:
1063    case XmlParser.ATTRIBUTE_CDATA:
1064        return "CDATA";
1065    case XmlParser.ATTRIBUTE_ID:
1066        return "ID";
1067    case XmlParser.ATTRIBUTE_IDREF:
1068        return "IDREF";
1069    case XmlParser.ATTRIBUTE_IDREFS:
1070        return "IDREFS";
1071    case XmlParser.ATTRIBUTE_ENTITY:
1072        return "ENTITY";
1073    case XmlParser.ATTRIBUTE_ENTITIES:
1074        return "ENTITIES";
1075    case XmlParser.ATTRIBUTE_ENUMERATED:
1076        // XXX doesn't have a way to return permitted enum values,
1077
// though they must each be a NMTOKEN
1078
case XmlParser.ATTRIBUTE_NMTOKEN:
1079        return "NMTOKEN";
1080    case XmlParser.ATTRIBUTE_NMTOKENS:
1081        return "NMTOKENS";
1082    case XmlParser.ATTRIBUTE_NOTATION:
1083        // XXX doesn't have a way to return the permitted values,
1084
// each of which must be name a declared notation
1085
return "NOTATION";
1086
1087    }
1088
1089    return null;
1090    }
1091
1092
1093    /**
1094     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1095     * (don't invoke on parser);
1096     */

1097    public String JavaDoc getValue (int i)
1098    {
1099        return (String JavaDoc) (attributeValues.elementAt (i));
1100    }
1101
1102
1103    /**
1104     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1105     */

1106    public int getIndex (String JavaDoc uri, String JavaDoc local)
1107    {
1108        int length = getLength ();
1109
1110        for (int i = 0; i < length; i++) {
1111            if (!getURI (i).equals (uri))
1112            continue;
1113            if (getLocalName (i).equals (local))
1114            return i;
1115        }
1116        return -1;
1117    }
1118
1119
1120    /**
1121     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1122     */

1123    public int getIndex (String JavaDoc xmlName)
1124    {
1125        int length = getLength ();
1126
1127        for (int i = 0; i < length; i++) {
1128            if (getQName (i).equals (xmlName))
1129            return i;
1130        }
1131        return -1;
1132    }
1133
1134
1135    /**
1136     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1137     */

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

1152    public String JavaDoc getType (String JavaDoc xmlName)
1153    {
1154        int index = getIndex (xmlName);
1155
1156        if (index < 0)
1157            return null;
1158        return getType (index);
1159    }
1160
1161
1162    /**
1163     * <b>SAX Attributes</b> method (don't invoke on parser);
1164     */

1165    public String JavaDoc getValue (String JavaDoc uri, String JavaDoc local)
1166    {
1167        int index = getIndex (uri, local);
1168
1169        if (index < 0)
1170            return null;
1171        return getValue (index);
1172    }
1173
1174
1175    /**
1176     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1177     * (don't invoke on parser);
1178     */

1179    public String JavaDoc getValue (String JavaDoc xmlName)
1180    {
1181        int index = getIndex (xmlName);
1182
1183        if (index < 0)
1184            return null;
1185        return getValue (index);
1186    }
1187
1188
1189    //
1190
// Implementation of org.xml.sax.Locator.
1191
//
1192

1193    /**
1194     * <b>SAX Locator</b> method (don't invoke on parser);
1195     */

1196    public String JavaDoc getPublicId ()
1197    {
1198        return null; // XXX track public IDs too
1199
}
1200
1201    /**
1202     * <b>SAX Locator</b> method (don't invoke on parser);
1203     */

1204    public String JavaDoc getSystemId ()
1205    {
1206        return (String JavaDoc) entityStack.peek ();
1207    }
1208
1209    /**
1210     * <b>SAX Locator</b> method (don't invoke on parser);
1211     */

1212    public int getLineNumber ()
1213    {
1214        return parser.getLineNumber ();
1215    }
1216
1217    /**
1218     * <b>SAX Locator</b> method (don't invoke on parser);
1219     */

1220    public int getColumnNumber ()
1221    {
1222        return parser.getColumnNumber ();
1223    }
1224
1225    // adapter between content handler and document handler callbacks
1226

1227    private static class Adapter implements ContentHandler
1228    {
1229        private DocumentHandler docHandler;
1230
1231        Adapter (DocumentHandler dh)
1232            { docHandler = dh; }
1233
1234
1235        public void setDocumentLocator (Locator l)
1236            { docHandler.setDocumentLocator (l); }
1237    
1238        public void startDocument () throws SAXException
1239            { docHandler.startDocument (); }
1240    
1241        public void processingInstruction (String JavaDoc target, String JavaDoc data)
1242        throws SAXException
1243            { docHandler.processingInstruction (target, data); }
1244    
1245        public void startPrefixMapping (String JavaDoc prefix, String JavaDoc uri)
1246            { /* ignored */ }
1247
1248        public void startElement (
1249            String JavaDoc namespace,
1250            String JavaDoc local,
1251            String JavaDoc name,
1252            Attributes attrs ) throws SAXException
1253        {
1254            docHandler.startElement (name, (AttributeList) attrs);
1255        }
1256
1257        public void characters (char buf [], int offset, int len)
1258        throws SAXException
1259        {
1260            docHandler.characters (buf, offset, len);
1261        }
1262
1263        public void ignorableWhitespace (char buf [], int offset, int len)
1264        throws SAXException
1265        {
1266            docHandler.ignorableWhitespace (buf, offset, len);
1267        }
1268
1269        public void skippedEntity (String JavaDoc name)
1270            { /* ignored */ }
1271
1272        public void endElement (String JavaDoc u, String JavaDoc l, String JavaDoc name)
1273        throws SAXException
1274            { docHandler.endElement (name); }
1275
1276        public void endPrefixMapping (String JavaDoc prefix)
1277            { /* ignored */ }
1278
1279        public void endDocument () throws SAXException
1280            { docHandler.endDocument (); }
1281    }
1282
1283    public static String JavaDoc tryToExpand(String JavaDoc systemId) {
1284        if (systemId==null) {
1285            systemId = "";
1286        }
1287        try {
1288            URL JavaDoc u = new URL JavaDoc(systemId);
1289            return systemId; // all is well
1290
} catch (MalformedURLException JavaDoc err) {
1291            String JavaDoc dir;
1292            try {
1293                dir = System.getProperty("user.dir");
1294            } catch (Exception JavaDoc geterr) {
1295                // this doesn't work when running an applet
1296
return systemId;
1297            }
1298            if (!(dir.endsWith("/") || systemId.startsWith("/"))) {
1299                dir = dir + "/";
1300            }
1301
1302            try {
1303                URL JavaDoc currentDirectoryURL = new File JavaDoc(dir).toURL(); // needs JDK 1.2
1304
URL JavaDoc baseURL = new URL JavaDoc(currentDirectoryURL, systemId);
1305                // System.err.println("SAX Driver: expanded " + systemId + " to " + baseURL);
1306
return baseURL.toString();
1307            } catch (MalformedURLException JavaDoc err2) {
1308                // go with the original one
1309
return systemId;
1310            }
1311        }
1312    }
1313
1314}
1315
Popular Tags