KickJava   Java API By Example, From Geeks To Geeks.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

315                 if (systemId != null)
316                     entityStack.push (systemId);
317                 else // should no longer happen after MHK addition
318
entityStack.push ("illegal:unknown system ID");
319
320                 parser.doParse (systemId,
321                           source.getPublicId (),
322                           source.getCharacterStream (),
323                           source.getByteStream (),
324                           source.getEncoding ());
325             } catch (SAXException e) {
326                 throw e;
327             } catch (IOException JavaDoc e) {
328                 throw e;
329             } catch (RuntimeException JavaDoc e) {
330                 throw e;
331             } catch (Exception JavaDoc e) {
332                 throw new SAXException (e.getMessage (), e);
333             } finally {
334                 contentHandler.endDocument ();
335                 entityStack.removeAllElements ();
336             }
337         }
338     }
339
340
341     /**
342      * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a
343      * system identifier (URI).
344      */

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

363     public boolean getFeature (String JavaDoc featureId)
364     throws SAXNotRecognizedException
365     {
366     if ((FEATURE + "validation").equals (featureId))
367         return false;
368
369     // external entities (both types) are currently always included
370
if ((FEATURE + "external-general-entities").equals (featureId)
371         || (FEATURE + "external-parameter-entities")
372         .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     /**
571     * If a system ID can't be parsed as a URL, we'll try to expand it as a relative
572     * URI using the current directory as the base URI: MHK addition
573     */

574     private String JavaDoc tryToExpand(String JavaDoc systemId) {
575         if (systemId==null) {
576             systemId = "";
577         }
578         try {
579             URL JavaDoc u = new URL JavaDoc(systemId);
580             return systemId; // all is well
581
} catch (MalformedURLException JavaDoc err) {
582             String JavaDoc dir = System.getProperty("user.dir");
583             if (dir.startsWith("/")) {
584                 dir = "file://" + dir;
585             } else {
586                 dir = "file:///" + dir;
587             }
588             if (!(dir.endsWith("/") || systemId.startsWith("/"))) {
589                 dir = dir + "/";
590             }
591             String JavaDoc file = dir + systemId;
592             try {
593                 URL JavaDoc u2 = new URL JavaDoc(file);
594                 // System.err.println("URI Resolver: expanded " + systemId + " to " + file);
595
return file; // it seems to be OK
596
} catch (MalformedURLException JavaDoc err2) {
597                 // go with the original one
598
return systemId;
599             }
600         }
601     }
602
603     void startExternalEntity (String JavaDoc systemId)
604     throws SAXException
605     {
606         entityStack.push (systemId);
607     }
608
609     void endExternalEntity (String JavaDoc systemId)
610     throws SAXException
611     {
612         entityStack.pop ();
613     }
614
615     void doctypeDecl (String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
616     throws SAXException
617     {
618         lexicalHandler.startDTD (name, publicId, systemId);
619     
620         // ... the "name" is a declaration and should be given
621
// to the DeclHandler (but sax2 beta doesn't).
622

623         // the IDs for the external subset are lexical details,
624
// as are the contents of the internal subset; but sax2
625
// beta only provides the external subset "pre-parse"
626
}
627
628     void endDoctype () throws SAXException
629     {
630         // NOTE: some apps may care that comments and PIs,
631
// are stripped from their DTD declaration context,
632
// and that those declarations are themselves quite
633
// thoroughly reordered here.
634

635         deliverDTDEvents ();
636         lexicalHandler.endDTD ();
637     }
638
639
640     void attribute (String JavaDoc aname, String JavaDoc value, boolean isSpecified)
641     throws SAXException
642     {
643         // Code changed by MHK 16 April 2001.
644
// The only safe thing to do is to process all the namespace declarations
645
// first, then process the ordinary attributes. So if this is a namespace
646
// declaration, we deal with it now, otherwise we save it till we get the
647
// startElement call.
648

649         if (attributeCount++ == 0) {
650             if (namespaces) {
651                 prefixStack.pushContext ();
652             }
653         }
654
655         // set nsTemp [0] == namespace URI (or empty)
656
// set nsTemp [1] == local name (or empty)
657
if (value == null) {
658             // MHK: I think this can only happen on an error recovery path
659
// MHK: I was wrong: AElfred was notifying null values of attribute
660
// declared in the DTD as #IMPLIED. But I've now changed it so it doesn't.
661
return;
662         }
663         
664         if (namespaces && aname.startsWith("xmlns")) {
665             if (aname.length() == 5) {
666                 prefixStack.declarePrefix ("", value);
667                 //System.err.println("Declare default prefix = "+value);
668
contentHandler.startPrefixMapping ("", value);
669             
670             } else if (aname.charAt(5)==':' && !aname.equals("xmlns:xml")) {
671
672                 if (aname.length() == 6) {
673                     errorHandler.error (new SAXParseException (
674                         "Missing namespace prefix in namespace declaration: " + aname,
675                         this));
676                     return;
677                 }
678                 String JavaDoc prefix = aname.substring (6);
679                 if (value.length() == 0) {
680                     errorHandler.error (new SAXParseException (
681                         "Missing URI in namespace declaration: " + aname,
682                         this));
683                     return;
684                 }
685                 prefixStack.declarePrefix (prefix, value);
686                 //System.err.println("Declare prefix " +prefix+"="+value);
687
contentHandler.startPrefixMapping (prefix, value);
688             }
689
690             if (!xmlNames) {
691                 // if xmlNames option wasn't selected,
692
// we don't report xmlns:* declarations as attributes
693
return;
694             }
695         }
696
697         attributeNames.addElement (aname);
698         attributeValues.addElement (value);
699     }
700
701     void startElement (String JavaDoc elname)
702     throws SAXException
703     {
704         ContentHandler handler = contentHandler;
705
706         if (attributeCount == 0)
707             prefixStack.pushContext ();
708
709         // save element name so attribute callbacks work
710
elementName = elname;
711         if (namespaces) {
712
713             // Expand namespace prefix for all attributes
714
if (attributeCount > 0) {
715                 for (int i=0; i<attributeNames.size(); i++) {
716                     String JavaDoc aname = (String JavaDoc)attributeNames.elementAt(i);
717                     if (aname.indexOf(':')>0) {
718                         if (xmlNames && aname.startsWith("xmlns:")) {
719                             attributeNamespaces.addElement("");
720                             attributeLocalNames.addElement(aname);
721
722                         } else if (prefixStack.processName (aname, nsTemp, true) == null) {
723                             errorHandler.error (new SAXParseException (
724                                 "undeclared name prefix in: " + aname,
725                                 this));
726                             // recovery action: substitute a name in default namespace
727
attributeNamespaces.addElement("");
728                             attributeLocalNames.addElement(aname.substring(aname.indexOf(':')));
729                         } else {
730                             attributeNamespaces.addElement(nsTemp[0]);
731                             attributeLocalNames.addElement(nsTemp[1]);
732                         }
733                     } else {
734                         attributeNamespaces.addElement("");
735                         attributeLocalNames.addElement(aname);
736                     }
737                     // check uniquess of the attribute expanded name
738
for (int j=0; j<i; j++) {
739                         if (attributeNamespaces.elementAt(i) == attributeNamespaces.elementAt(j) &&
740                             attributeLocalNames.elementAt(i) == attributeLocalNames.elementAt(j)) {
741                                 errorHandler.error( new SAXParseException (
742                                     "duplicate attribute name: " + attributeLocalNames.elementAt(j),
743                                     this));
744                         }
745                     }
746                 }
747             }
748
749             if (prefixStack.processName (elname, nsTemp, false) == null) {
750                 errorHandler.error (new SAXParseException (
751                     "undeclared name prefix in: " + elname,
752                     this));
753                 nsTemp [0] = nsTemp [1] = "";
754                 // recovery action
755
elname = elname.substring(elname.indexOf(':'));
756             }
757             handler.startElement (nsTemp [0], nsTemp [1], elname, this);
758         } else
759             handler.startElement ("", "", elname, this);
760         // elementName = null;
761

762         // elements with no attributes are pretty common!
763
if (attributeCount != 0) {
764             attributeNames.removeAllElements ();
765             attributeNamespaces.removeAllElements ();
766             attributeLocalNames.removeAllElements ();
767             attributeValues.removeAllElements ();
768             attributeCount = 0;
769         }
770         nspending = false;
771     }
772
773     void endElement (String JavaDoc elname)
774     throws SAXException
775     {
776         ContentHandler handler = contentHandler;
777
778         if (!namespaces) {
779             handler.endElement("", "", elname);
780             return;
781         }
782         
783         // following code added by MHK to fix bug Saxon 6.1/013
784
if (prefixStack.processName (elname, nsTemp, false) == null) {
785             // shouldn't happen
786
errorHandler.error (new SAXParseException (
787                 "undeclared name prefix in: " + elname, this));
788             nsTemp [0] = nsTemp [1] = "";
789             elname = elname.substring(elname.indexOf(':'));
790         }
791
792         handler.endElement (nsTemp[0], nsTemp[1], elname);
793         
794         // previous code (clearly wrong): handler.endElement ("", "", elname);
795

796         // end of MHK addition
797

798
799         Enumeration JavaDoc prefixes = prefixStack.getDeclaredPrefixes ();
800
801         while (prefixes.hasMoreElements ())
802             handler.endPrefixMapping ((String JavaDoc) prefixes.nextElement ());
803         prefixStack.popContext ();
804     }
805
806     void startCDATA ()
807     throws SAXException
808     {
809         lexicalHandler.startCDATA ();
810     }
811
812     void charData (char ch[], int start, int length)
813     throws SAXException
814     {
815         contentHandler.characters (ch, start, length);
816     }
817
818     void endCDATA ()
819     throws SAXException
820     {
821         lexicalHandler.endCDATA ();
822     }
823
824     void ignorableWhitespace (char ch[], int start, int length)
825     throws SAXException
826     {
827         contentHandler.ignorableWhitespace (ch, start, length);
828     }
829
830     void processingInstruction (String JavaDoc target, String JavaDoc data)
831     throws SAXException
832     {
833         // XXX if within DTD, perhaps it's best to discard
834
// PIs since the decls to which they (usually)
835
// apply get significantly rearranged
836

837         contentHandler.processingInstruction (target, data);
838     }
839
840     void comment (char ch[], int start, int length)
841     throws SAXException
842     {
843         // XXX if within DTD, perhaps it's best to discard
844
// comments since the decls to which they (usually)
845
// apply get significantly rearranged
846

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

1045    /**
1046     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1047     * (don't invoke on parser);
1048     */

1049    public int getLength ()
1050    {
1051        return attributeNames.size ();
1052    }
1053
1054    /**
1055     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1056     */

1057    public String JavaDoc getURI (int index)
1058    {
1059        return (String JavaDoc) (attributeNamespaces.elementAt (index));
1060    }
1061
1062    /**
1063     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1064     */

1065    public String JavaDoc getLocalName (int index)
1066    {
1067        return (String JavaDoc) (attributeLocalNames.elementAt (index));
1068    }
1069
1070    /**
1071     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1072     */

1073    public String JavaDoc getQName (int i)
1074    {
1075        return (String JavaDoc) (attributeNames.elementAt (i));
1076    }
1077
1078    /**
1079     * <b>SAX1 AttributeList</b> method (don't invoke on parser);
1080     */

1081    public String JavaDoc getName (int i)
1082    {
1083        return (String JavaDoc) (attributeNames.elementAt (i));
1084    }
1085
1086    /**
1087     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1088     * (don't invoke on parser);
1089     */

1090    public String JavaDoc getType (int i)
1091    {
1092    switch (parser.getAttributeType (elementName, getQName (i))) {
1093
1094    case XmlParser.ATTRIBUTE_UNDECLARED:
1095    case XmlParser.ATTRIBUTE_CDATA:
1096        return "CDATA";
1097    case XmlParser.ATTRIBUTE_ID:
1098        return "ID";
1099    case XmlParser.ATTRIBUTE_IDREF:
1100        return "IDREF";
1101    case XmlParser.ATTRIBUTE_IDREFS:
1102        return "IDREFS";
1103    case XmlParser.ATTRIBUTE_ENTITY:
1104        return "ENTITY";
1105    case XmlParser.ATTRIBUTE_ENTITIES:
1106        return "ENTITIES";
1107    case XmlParser.ATTRIBUTE_ENUMERATED:
1108        // XXX doesn't have a way to return permitted enum values,
1109
// though they must each be a NMTOKEN
1110
case XmlParser.ATTRIBUTE_NMTOKEN:
1111        return "NMTOKEN";
1112    case XmlParser.ATTRIBUTE_NMTOKENS:
1113        return "NMTOKENS";
1114    case XmlParser.ATTRIBUTE_NOTATION:
1115        // XXX doesn't have a way to return the permitted values,
1116
// each of which must be name a declared notation
1117
return "NOTATION";
1118
1119    }
1120
1121    return null;
1122    }
1123
1124
1125    /**
1126     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1127     * (don't invoke on parser);
1128     */

1129    public String JavaDoc getValue (int i)
1130    {
1131        return (String JavaDoc) (attributeValues.elementAt (i));
1132    }
1133
1134
1135    /**
1136     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1137     */

1138    public int getIndex (String JavaDoc uri, String JavaDoc local)
1139    {
1140        int length = getLength ();
1141
1142        for (int i = 0; i < length; i++) {
1143            if (!getURI (i).equals (uri))
1144            continue;
1145            if (getLocalName (i).equals (local))
1146            return i;
1147        }
1148        return -1;
1149    }
1150
1151
1152    /**
1153     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1154     */

1155    public int getIndex (String JavaDoc xmlName)
1156    {
1157        int length = getLength ();
1158
1159        for (int i = 0; i < length; i++) {
1160            if (getQName (i).equals (xmlName))
1161            return i;
1162        }
1163        return -1;
1164    }
1165
1166
1167    /**
1168     * <b>SAX2 Attributes</b> method (don't invoke on parser);
1169     */

1170    public String JavaDoc getType (String JavaDoc uri, String JavaDoc local)
1171    {
1172        int index = getIndex (uri, local);
1173
1174        if (index < 0)
1175            return null;
1176        return getType (index);
1177    }
1178
1179
1180    /**
1181     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1182     * (don't invoke on parser);
1183     */

1184    public String JavaDoc getType (String JavaDoc xmlName)
1185    {
1186        int index = getIndex (xmlName);
1187
1188        if (index < 0)
1189            return null;
1190        return getType (index);
1191    }
1192
1193
1194    /**
1195     * <b>SAX Attributes</b> method (don't invoke on parser);
1196     */

1197    public String JavaDoc getValue (String JavaDoc uri, String JavaDoc local)
1198    {
1199        int index = getIndex (uri, local);
1200
1201        if (index < 0)
1202            return null;
1203        return getValue (index);
1204    }
1205
1206
1207    /**
1208     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1209     * (don't invoke on parser);
1210     */

1211    public String JavaDoc getValue (String JavaDoc xmlName)
1212    {
1213        int index = getIndex (xmlName);
1214
1215        if (index < 0)
1216            return null;
1217        return getValue (index);
1218    }
1219
1220
1221    //
1222
// Implementation of org.xml.sax.Locator.
1223
//
1224

1225    /**
1226     * <b>SAX Locator</b> method (don't invoke on parser);
1227     */

1228    public String JavaDoc getPublicId ()
1229    {
1230        return null; // XXX track public IDs too
1231
}
1232
1233    /**
1234     * <b>SAX Locator</b> method (don't invoke on parser);
1235     */

1236    public String JavaDoc getSystemId ()
1237    {
1238        return (String JavaDoc) entityStack.peek ();
1239    }
1240
1241    /**
1242     * <b>SAX Locator</b> method (don't invoke on parser);
1243     */

1244    public int getLineNumber ()
1245    {
1246        return parser.getLineNumber ();
1247    }
1248
1249    /**
1250     * <b>SAX Locator</b> method (don't invoke on parser);
1251     */

1252    public int getColumnNumber ()
1253    {
1254        return parser.getColumnNumber ();
1255    }
1256
1257    // adapter between content handler and document handler callbacks
1258

1259    private static class Adapter implements ContentHandler
1260    {
1261        private DocumentHandler docHandler;
1262
1263        Adapter (DocumentHandler dh)
1264            { docHandler = dh; }
1265
1266
1267        public void setDocumentLocator (Locator l)
1268            { docHandler.setDocumentLocator (l); }
1269    
1270        public void startDocument () throws SAXException
1271            { docHandler.startDocument (); }
1272    
1273        public void processingInstruction (String JavaDoc target, String JavaDoc data)
1274        throws SAXException
1275            { docHandler.processingInstruction (target, data); }
1276    
1277        public void startPrefixMapping (String JavaDoc prefix, String JavaDoc uri)
1278            { /* ignored */ }
1279
1280        public void startElement (
1281            String JavaDoc namespace,
1282            String JavaDoc local,
1283            String JavaDoc name,
1284            Attributes attrs ) throws SAXException
1285        {
1286            docHandler.startElement (name, (AttributeList) attrs);
1287        }
1288
1289        public void characters (char buf [], int offset, int len)
1290        throws SAXException
1291        {
1292            docHandler.characters (buf, offset, len);
1293        }
1294
1295        public void ignorableWhitespace (char buf [], int offset, int len)
1296        throws SAXException
1297        {
1298            docHandler.ignorableWhitespace (buf, offset, len);
1299        }
1300
1301        public void skippedEntity (String JavaDoc name)
1302            { /* ignored */ }
1303
1304        public void endElement (String JavaDoc u, String JavaDoc l, String JavaDoc name)
1305        throws SAXException
1306            { docHandler.endElement (name); }
1307
1308        public void endPrefixMapping (String JavaDoc prefix)
1309            { /* ignored */ }
1310
1311        public void endDocument () throws SAXException
1312            { docHandler.endDocument (); }
1313    }
1314}
1315
Popular Tags