1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.xerces.parsers;
19
20 import java.io.CharConversionException;
21 import java.io.IOException;
22 import java.util.Locale;
23
24 import org.apache.xerces.impl.Constants;
25 import org.apache.xerces.util.EntityResolver2Wrapper;
26 import org.apache.xerces.util.EntityResolverWrapper;
27 import org.apache.xerces.util.ErrorHandlerWrapper;
28 import org.apache.xerces.util.SAXMessageFormatter;
29 import org.apache.xerces.util.SymbolHash;
30 import org.apache.xerces.util.XMLSymbols;
31 import org.apache.xerces.xni.Augmentations;
32 import org.apache.xerces.xni.NamespaceContext;
33 import org.apache.xerces.xni.QName;
34 import org.apache.xerces.xni.XMLAttributes;
35 import org.apache.xerces.xni.XMLLocator;
36 import org.apache.xerces.xni.XMLResourceIdentifier;
37 import org.apache.xerces.xni.XMLString;
38 import org.apache.xerces.xni.XNIException;
39 import org.apache.xerces.xni.parser.XMLConfigurationException;
40 import org.apache.xerces.xni.parser.XMLEntityResolver;
41 import org.apache.xerces.xni.parser.XMLErrorHandler;
42 import org.apache.xerces.xni.parser.XMLInputSource;
43 import org.apache.xerces.xni.parser.XMLParseException;
44 import org.apache.xerces.xni.parser.XMLParserConfiguration;
45 import org.apache.xerces.xs.AttributePSVI;
46 import org.apache.xerces.xs.ElementPSVI;
47 import org.apache.xerces.xs.PSVIProvider;
48 import org.xml.sax.AttributeList;
49 import org.xml.sax.ContentHandler;
50 import org.xml.sax.DTDHandler;
51 import org.xml.sax.DocumentHandler;
52 import org.xml.sax.EntityResolver;
53 import org.xml.sax.ErrorHandler;
54 import org.xml.sax.InputSource;
55 import org.xml.sax.Parser;
56 import org.xml.sax.SAXException;
57 import org.xml.sax.SAXNotRecognizedException;
58 import org.xml.sax.SAXNotSupportedException;
59 import org.xml.sax.SAXParseException;
60 import org.xml.sax.XMLReader;
61 import org.xml.sax.ext.Attributes2;
62 import org.xml.sax.ext.DeclHandler;
63 import org.xml.sax.ext.EntityResolver2;
64 import org.xml.sax.ext.LexicalHandler;
65 import org.xml.sax.ext.Locator2;
66 import org.xml.sax.ext.Locator2Impl;
67
68 /**
69 * This is the base class of all SAX parsers. It implements both the
70 * SAX1 and SAX2 parser functionality, while the actual pipeline is
71 * defined in the parser configuration.
72 *
73 * @author Arnaud Le Hors, IBM
74 * @author Andy Clark, IBM
75 *
76 * @version $Id: AbstractSAXParser.java 548086 2007-06-17 18:17:43Z mrglavas $
77 */
78 public abstract class AbstractSAXParser
79 extends AbstractXMLDocumentParser
80 implements PSVIProvider, // PSVI
81 Parser, XMLReader // SAX1, SAX2
82 {
83
84 //
85 // Constants
86 //
87
88 // features
89
90 /** Feature identifier: namespaces. */
91 protected static final String NAMESPACES =
92 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
93
94 /** Feature id: string interning. */
95 protected static final String STRING_INTERNING =
96 Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE;
97
98 /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */
99 // this is not meant to be a recognized feature, but we need it here to use
100 // if it is already a recognized feature for the pipeline
101 protected static final String ALLOW_UE_AND_NOTATION_EVENTS =
102 Constants.SAX_FEATURE_PREFIX + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE;
103
104 /** Recognized features. */
105 private static final String[] RECOGNIZED_FEATURES = {
106 NAMESPACES,
107 STRING_INTERNING,
108 };
109
110 // properties
111
112 /** Property id: lexical handler. */
113 protected static final String LEXICAL_HANDLER =
114 Constants.SAX_PROPERTY_PREFIX + Constants.LEXICAL_HANDLER_PROPERTY;
115
116 /** Property id: declaration handler. */
117 protected static final String DECLARATION_HANDLER =
118 Constants.SAX_PROPERTY_PREFIX + Constants.DECLARATION_HANDLER_PROPERTY;
119
120 /** Property id: DOM node. */
121 protected static final String DOM_NODE =
122 Constants.SAX_PROPERTY_PREFIX + Constants.DOM_NODE_PROPERTY;
123
124 /** Recognized properties. */
125 private static final String[] RECOGNIZED_PROPERTIES = {
126 LEXICAL_HANDLER,
127 DECLARATION_HANDLER,
128 DOM_NODE,
129 };
130
131 //
132 // Data
133 //
134
135 // features
136
137 /** Namespaces. */
138 protected boolean fNamespaces;
139
140 /** Namespace prefixes. */
141 protected boolean fNamespacePrefixes = false;
142
143 /** Lexical handler parameter entities. */
144 protected boolean fLexicalHandlerParameterEntities = true;
145
146 /** Standalone document declaration. */
147 protected boolean fStandalone;
148
149 /** Resolve DTD URIs. */
150 protected boolean fResolveDTDURIs = true;
151
152 /** Use EntityResolver2. */
153 protected boolean fUseEntityResolver2 = true;
154
155 /**
156 * XMLNS URIs: Namespace declarations in the
157 * http://www.w3.org/2000/xmlns/ namespace.
158 */
159 protected boolean fXMLNSURIs = false;
160
161 // parser handlers
162
163 /** Content handler. */
164 protected ContentHandler fContentHandler;
165
166 /** Document handler. */
167 protected DocumentHandler fDocumentHandler;
168
169 /** Namespace context */
170 protected NamespaceContext fNamespaceContext;
171
172 /** DTD handler. */
173 protected org.xml.sax.DTDHandler fDTDHandler;
174
175 /** Decl handler. */
176 protected DeclHandler fDeclHandler;
177
178 /** Lexical handler. */
179 protected LexicalHandler fLexicalHandler;
180
181 protected QName fQName = new QName();
182
183 // state
184
185 /**
186 * True if a parse is in progress. This state is needed because
187 * some features/properties cannot be set while parsing (e.g.
188 * validation and namespaces).
189 */
190 protected boolean fParseInProgress = false;
191
192 // track the version of the document being parsed
193 protected String fVersion;
194
195 // temp vars
196 private final AttributesProxy fAttributesProxy = new AttributesProxy();
197 private Augmentations fAugmentations = null;
198
199
200 // temporary buffer for sending normalized values
201 // REVISIT: what should be the size of the buffer?
202 private static final int BUFFER_SIZE = 20;
203 private char[] fCharBuffer = new char[BUFFER_SIZE];
204
205 // allows us to keep track of whether an attribute has
206 // been declared twice, so that we can avoid exposing the
207 // second declaration to any registered DeclHandler
208 protected SymbolHash fDeclaredAttrs = null;
209
210 //
211 // Constructors
212 //
213
214 /** Default constructor. */
215 protected AbstractSAXParser(XMLParserConfiguration config) {
216 super(config);
217
218 config.addRecognizedFeatures(RECOGNIZED_FEATURES);
219 config.addRecognizedProperties(RECOGNIZED_PROPERTIES);
220
221 try {
222 config.setFeature(ALLOW_UE_AND_NOTATION_EVENTS, false);
223 }
224 catch (XMLConfigurationException e) {
225 // it wasn't a recognized feature, so we don't worry about it
226 }
227 } // <init>(XMLParserConfiguration)
228
229 //
230 // XMLDocumentHandler methods
231 //
232
233 /**
234 * The start of the document.
235 *
236 * @param locator The document locator, or null if the document
237 * location cannot be reported during the parsing
238 * of this document. However, it is <em>strongly</em>
239 * recommended that a locator be supplied that can
240 * at least report the system identifier of the
241 * document.
242 * @param encoding The auto-detected IANA encoding name of the entity
243 * stream. This value will be null in those situations
244 * where the entity encoding is not auto-detected (e.g.
245 * internal entities or a document entity that is
246 * parsed from a java.io.Reader).
247 * @param namespaceContext
248 * The namespace context in effect at the
249 * start of this document.
250 * This object represents the current context.
251 * Implementors of this class are responsible
252 * for copying the namespace bindings from the
253 * the current context (and its parent contexts)
254 * if that information is important.
255 * @param augs Additional information that may include infoset augmentations
256 *
257 * @throws XNIException Thrown by handler to signal an error.
258 */
259 public void startDocument(XMLLocator locator, String encoding,
260 NamespaceContext namespaceContext, Augmentations augs)
261 throws XNIException {
262
263 fNamespaceContext = namespaceContext;
264
265 try {
266 // SAX1
267 if (fDocumentHandler != null) {
268 if (locator != null) {
269 fDocumentHandler.setDocumentLocator(new LocatorProxy(locator));
270 }
271 fDocumentHandler.startDocument();
272 }
273
274 // SAX2
275 if (fContentHandler != null) {
276 if (locator != null) {
277 fContentHandler.setDocumentLocator(new LocatorProxy(locator));
278 }
279 fContentHandler.startDocument();
280 }
281 }
282 catch (SAXException e) {
283 throw new XNIException(e);
284 }
285
286 } // startDocument(locator,encoding,augs)
287
288 /**
289 * Notifies of the presence of an XMLDecl line in the document. If
290 * present, this method will be called immediately following the
291 * startDocument call.
292 *
293 * @param version The XML version.
294 * @param encoding The IANA encoding name of the document, or null if
295 * not specified.
296 * @param standalone The standalone value, or null if not specified.
297 * @param augs Additional information that may include infoset augmentations
298 *
299 * @throws XNIException Thrown by handler to signal an error.
300 */
301 public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
302 throws XNIException {
303 // the version need only be set once; if
304 // document's XML 1.0|1.1, that's how it'll stay
305 fVersion = version;
306 fStandalone = "yes".equals(standalone);
307 } // xmlDecl(String,String,String)
308
309 /**
310 * Notifies of the presence of the DOCTYPE line in the document.
311 *
312 * @param rootElement The name of the root element.
313 * @param publicId The public identifier if an external DTD or null
314 * if the external DTD is specified using SYSTEM.
315 * @param systemId The system identifier if an external DTD, null
316 * otherwise.
317 * @param augs Additional information that may include infoset augmentations
318 *
319 * @throws XNIException Thrown by handler to signal an error.
320 */
321 public void doctypeDecl(String rootElement,
322 String publicId, String systemId, Augmentations augs)
323 throws XNIException {
324 fInDTD = true;
325
326 try {
327 // SAX2 extension
328 if (fLexicalHandler != null) {
329 fLexicalHandler.startDTD(rootElement, publicId, systemId);
330 }
331 }
332 catch (SAXException e) {
333 throw new XNIException(e);
334 }
335
336 // is there a DeclHandler?
337 if(fDeclHandler != null) {
338 fDeclaredAttrs = new SymbolHash();
339 }
340
341 } // doctypeDecl(String,String,String)
342
343 /**
344 * This method notifies of the start of an entity. The DTD has the
345 * pseudo-name of "[dtd]" parameter entity names start with '%'; and
346 * general entity names are just the entity name.
347 * <p>
348 * <strong>Note:</strong> Since the document is an entity, the handler
349 * will be notified of the start of the document entity by calling the
350 * startEntity method with the entity name "[xml]" <em>before</em> calling
351 * the startDocument method. When exposing entity boundaries through the
352 * SAX API, the document entity is never reported, however.
353 * <p>
354 * <strong>Note:</strong> This method is not called for entity references
355 * appearing as part of attribute values.
356 *
357 * @param name The name of the entity.
358 * @param identifier The resource identifier.
359 * @param encoding The auto-detected IANA encoding name of the entity
360 * stream. This value will be null in those situations
361 * where the entity encoding is not auto-detected (e.g.
362 * internal parameter entities).
363 * @param augs Additional information that may include infoset augmentations
364 *
365 * @throws XNIException Thrown by handler to signal an error.
366 */
367 public void startGeneralEntity(String name, XMLResourceIdentifier identifier,
368 String encoding, Augmentations augs)
369 throws XNIException {
370
371 try {
372 // Only report startEntity if this entity was actually read.
373 if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
374 // report skipped entity to content handler
375 if (fContentHandler != null) {
376 fContentHandler.skippedEntity(name);
377 }
378 }
379 else {
380 // SAX2 extension
381 if (fLexicalHandler != null) {
382 fLexicalHandler.startEntity(name);
383 }
384 }
385 }
386 catch (SAXException e) {
387 throw new XNIException(e);
388 }
389
390 } // startGeneralEntity(String,String,String,String,String)
391
392 /**
393 * This method notifies the end of an entity. The DTD has the pseudo-name
394 * of "[dtd]" parameter entity names start with '%'; and general entity
395 * names are just the entity name.
396 * <p>
397 * <strong>Note:</strong> Since the document is an entity, the handler
398 * will be notified of the end of the document entity by calling the
399 * endEntity method with the entity name "[xml]" <em>after</em> calling
400 * the endDocument method. When exposing entity boundaries through the
401 * SAX API, the document entity is never reported, however.
402 * <p>
403 * <strong>Note:</strong> This method is not called for entity references
404 * appearing as part of attribute values.
405 *
406 * @param name The name of the entity.
407 * @param augs Additional information that may include infoset augmentations
408 *
409 * @throws XNIException Thrown by handler to signal an error.
410 */
411 public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
412
413 try {
414 // Only report endEntity if this entity was actually read.
415 if (augs == null || !Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
416 // SAX2 extension
417 if (fLexicalHandler != null) {
418 fLexicalHandler.endEntity(name);
419 }
420 }
421 }
422 catch (SAXException e) {
423 throw new XNIException(e);
424 }
425
426 } // endEntity(String)
427
428 /**
429 * The start of an element. If the document specifies the start element
430 * by using an empty tag, then the startElement method will immediately
431 * be followed by the endElement method, with no intervening methods.
432 *
433 * @param element The name of the element.
434 * @param attributes The element attributes.
435 * @param augs Additional information that may include infoset augmentations
436 *
437 * @throws XNIException Thrown by handler to signal an error.
438 */
439 public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
440 throws XNIException {
441
442 try {
443 // SAX1
444 if (fDocumentHandler != null) {
445 // REVISIT: should we support schema-normalized-value for SAX1 events
446 //
447 fAttributesProxy.setAttributes(attributes);
448 fDocumentHandler.startElement(element.rawname, fAttributesProxy);
449 }
450
451 // SAX2
452 if (fContentHandler != null) {
453
454 if (fNamespaces) {
455 // send prefix mapping events
456 startNamespaceMapping();
457
458 // REVISIT: It should not be necessary to iterate over the attribute
459 // list when the set of [namespace attributes] is empty for this
460 // element. This should be computable from the NamespaceContext, but
461 // since we currently don't report the mappings for the xml prefix
462 // we cannot use the declared prefix count for the current context
463 // to skip this section. -- mrglavas
464 int len = attributes.getLength();
465 if (!fNamespacePrefixes) {
466 for (int i = len - 1; i >= 0; --i) {
467 attributes.getName(i, fQName);
468 if ((fQName.prefix == XMLSymbols.PREFIX_XMLNS) ||
469 (fQName.rawname == XMLSymbols.PREFIX_XMLNS)) {
470 // remove namespace declaration attributes
471 attributes.removeAttributeAt(i);
472 }
473 }
474 }
475 else if (!fXMLNSURIs) {
476 for (int i = len - 1; i >= 0; --i) {
477 attributes.getName(i, fQName);
478 if ((fQName.prefix == XMLSymbols.PREFIX_XMLNS) ||
479 (fQName.rawname == XMLSymbols.PREFIX_XMLNS)) {
480 // localpart should be empty string as per SAX documentation:
481 // http://www.saxproject.org/?selected=namespaces
482 fQName.prefix = "";
483 fQName.uri = "";
484 fQName.localpart = "";
485 attributes.setName(i, fQName);
486 }
487 }
488 }
489 }
490
491 fAugmentations = augs;
492
493 String uri = element.uri != null ? element.uri : "";
494 String localpart = fNamespaces ? element.localpart : "";
495 fAttributesProxy.setAttributes(attributes);
496 fContentHandler.startElement(uri, localpart, element.rawname,
497 fAttributesProxy);
498 }
499 }
500 catch (SAXException e) {
501 throw new XNIException(e);
502 }
503
504 } // startElement(QName,XMLAttributes)
505
506 /**
507 * Character content.
508 *
509 * @param text The content.
510 * @param augs Additional information that may include infoset augmentations
511 *
512 * @throws XNIException Thrown by handler to signal an error.
513 */
514 public void characters(XMLString text, Augmentations augs) throws XNIException {
515
516 // if type is union (XML Schema) it is possible that we receive
517 // character call with empty data
518 if (text.length == 0) {
519 return;
520 }
521
522
523 try {
524 // SAX1
525 if (fDocumentHandler != null) {
526 // REVISIT: should we support schema-normalized-value for SAX1 events
527 //
528 fDocumentHandler.characters(text.ch, text.offset, text.length);
529 }
530
531 // SAX2
532 if (fContentHandler != null) {
533 fContentHandler.characters(text.ch, text.offset, text.length);
534 }
535 }
536 catch (SAXException e) {
537 throw new XNIException(e);
538 }
539
540 } // characters(XMLString)
541
542 /**
543 * Ignorable whitespace. For this method to be called, the document
544 * source must have some way of determining that the text containing
545 * only whitespace characters should be considered ignorable. For
546 * example, the validator can determine if a length of whitespace
547 * characters in the document are ignorable based on the element
548 * content model.
549 *
550 * @param text The ignorable whitespace.
551 * @param augs Additional information that may include infoset augmentations
552 *
553 * @throws XNIException Thrown by handler to signal an error.
554 */
555 public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
556
557 try {
558 // SAX1
559 if (fDocumentHandler != null) {
560 fDocumentHandler.ignorableWhitespace(text.ch, text.offset, text.length);
561 }
562
563 // SAX2
564 if (fContentHandler != null) {
565 fContentHandler.ignorableWhitespace(text.ch, text.offset, text.length);
566 }
567 }
568 catch (SAXException e) {
569 throw new XNIException(e);
570 }
571
572 } // ignorableWhitespace(XMLString)
573
574 /**
575 * The end of an element.
576 *
577 * @param element The name of the element.
578 * @param augs Additional information that may include infoset augmentations
579 *
580 * @throws XNIException Thrown by handler to signal an error.
581 */
582 public void endElement(QName element, Augmentations augs) throws XNIException {
583
584
585 try {
586 // SAX1
587 if (fDocumentHandler != null) {
588 fDocumentHandler.endElement(element.rawname);
589 }
590
591 // SAX2
592 if (fContentHandler != null) {
593 fAugmentations = augs;
594 String uri = element.uri != null ? element.uri : "";
595 String localpart = fNamespaces ? element.localpart : "";
596 fContentHandler.endElement(uri, localpart,
597 element.rawname);
598 if (fNamespaces) {
599 endNamespaceMapping();
600 }
601 }
602 }
603 catch (SAXException e) {
604 throw new XNIException(e);
605 }
606
607 } // endElement(QName)
608
609 /**
610 * The start of a CDATA section.
611 * @param augs Additional information that may include infoset augmentations
612 *
613 * @throws XNIException Thrown by handler to signal an error.
614 */
615 public void startCDATA(Augmentations augs) throws XNIException {
616
617 try {
618 // SAX2 extension
619 if (fLexicalHandler != null) {
620 fLexicalHandler.startCDATA();
621 }
622 }
623 catch (SAXException e) {
624 throw new XNIException(e);
625 }
626
627 } // startCDATA()
628
629 /**
630 * The end of a CDATA section.
631 * @param augs Additional information that may include infoset augmentations
632 *
633 * @throws XNIException Thrown by handler to signal an error.
634 */
635 public void endCDATA(Augmentations augs) throws XNIException {
636
637 try {
638 // SAX2 extension
639 if (fLexicalHandler != null) {
640 fLexicalHandler.endCDATA();
641 }
642 }
643 catch (SAXException e) {
644 throw new XNIException(e);
645 }
646
647 } // endCDATA()
648
649 /**
650 * A comment.
651 *
652 * @param text The text in the comment.
653 * @param augs Additional information that may include infoset augmentations
654 *
655 * @throws XNIException Thrown by application to signal an error.
656 */
657 public void comment(XMLString text, Augmentations augs) throws XNIException {
658
659 try {
660 // SAX2 extension
661 if (fLexicalHandler != null) {
662 fLexicalHandler.comment(text.ch, 0, text.length);
663 }
664 }
665 catch (SAXException e) {
666 throw new XNIException(e);
667 }
668
669 } // comment(XMLString)
670
671 /**
672 * A processing instruction. Processing instructions consist of a
673 * target name and, optionally, text data. The data is only meaningful
674 * to the application.
675 * <p>
676 * Typically, a processing instruction's data will contain a series
677 * of pseudo-attributes. These pseudo-attributes follow the form of
678 * element attributes but are <strong>not</strong> parsed or presented
679 * to the application as anything other than text. The application is
680 * responsible for parsing the data.
681 *
682 * @param target The target.
683 * @param data The data or null if none specified.
684 * @param augs Additional information that may include infoset augmentations
685 *
686 * @throws XNIException Thrown by handler to signal an error.
687 */
688 public void processingInstruction(String target, XMLString data, Augmentations augs)
689 throws XNIException {
690
691 //
692 // REVISIT - I keep running into SAX apps that expect
693 // null data to be an empty string, which is contrary
694 // to the comment for this method in the SAX API.
695 //
696
697 try {
698 // SAX1
699 if (fDocumentHandler != null) {
700 fDocumentHandler.processingInstruction(target,
701 data.toString());
702 }
703
704 // SAX2
705 if (fContentHandler != null) {
706 fContentHandler.processingInstruction(target, data.toString());
707 }
708 }
709 catch (SAXException e) {
710 throw new XNIException(e);
711 }
712
713 } // processingInstruction(String,XMLString)
714
715
716 /**
717 * The end of the document.
718 * @param augs Additional information that may include infoset augmentations
719 *
720 * @throws XNIException Thrown by handler to signal an error.
721 */
722 public void endDocument(Augmentations augs) throws XNIException {
723
724 try {
725 // SAX1
726 if (fDocumentHandler != null) {
727 fDocumentHandler.endDocument();
728 }
729
730 // SAX2
731 if (fContentHandler != null) {
732 fContentHandler.endDocument();
733 }
734 }
735 catch (SAXException e) {
736 throw new XNIException(e);
737 }
738
739 } // endDocument()
740
741 //
742 // XMLDTDHandler methods
743 //
744
745 /**
746 * The start of the DTD external subset.
747 *
748 * @param augs Additional information that may include infoset
749 * augmentations.
750 *
751 * @throws XNIException Thrown by handler to signal an error.
752 */
753 public void startExternalSubset(XMLResourceIdentifier identifier,
754 Augmentations augs) throws XNIException {
755 startParameterEntity("[dtd]", null, null, augs);
756 }
757
758 /**
759 * The end of the DTD external subset.
760 *
761 * @param augs Additional information that may include infoset
762 * augmentations.
763 *
764 * @throws XNIException Thrown by handler to signal an error.
765 */
766 public void endExternalSubset(Augmentations augs) throws XNIException {
767 endParameterEntity("[dtd]", augs);
768 }
769
770 /**
771 * This method notifies of the start of parameter entity. The DTD has the
772 * pseudo-name of "[dtd]" parameter entity names start with '%'; and
773 * general entity names are just the entity name.
774 * <p>
775 * <strong>Note:</strong> Since the document is an entity, the handler
776 * will be notified of the start of the document entity by calling the
777 * startEntity method with the entity name "[xml]" <em>before</em> calling
778 * the startDocument method. When exposing entity boundaries through the
779 * SAX API, the document entity is never reported, however.
780 * <p>
781 * <strong>Note:</strong> This method is not called for entity references
782 * appearing as part of attribute values.
783 *
784 * @param name The name of the parameter entity.
785 * @param identifier The resource identifier.
786 * @param encoding The auto-detected IANA encoding name of the entity
787 * stream. This value will be null in those situations
788 * where the entity encoding is not auto-detected (e.g.
789 * internal parameter entities).
790 * @param augs Additional information that may include infoset
791 * augmentations.
792 *
793 * @throws XNIException Thrown by handler to signal an error.
794 */
795 public void startParameterEntity(String name,
796 XMLResourceIdentifier identifier,
797 String encoding, Augmentations augs)
798 throws XNIException {
799
800 try {
801 // Only report startEntity if this entity was actually read.
802 if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
803 // report skipped entity to content handler
804 if (fContentHandler != null) {
805 fContentHandler.skippedEntity(name);
806 }
807 }
808 else {
809 // SAX2 extension
810 if (fLexicalHandler != null && fLexicalHandlerParameterEntities) {
811 fLexicalHandler.startEntity(name);
812 }
813 }
814 }
815 catch (SAXException e) {
816 throw new XNIException(e);
817 }
818
819 } // startParameterEntity(String,identifier,String,Augmentation)
820
821 /**
822 * This method notifies the end of an entity. The DTD has the pseudo-name
823 * of "[dtd]" parameter entity names start with '%'; and general entity
824 * names are just the entity name.
825 * <p>
826 * <strong>Note:</strong> Since the document is an entity, the handler
827 * will be notified of the end of the document entity by calling the
828 * endEntity method with the entity name "[xml]" <em>after</em> calling
829 * the endDocument method. When exposing entity boundaries through the
830 * SAX API, the document entity is never reported, however.
831 * <p>
832 * <strong>Note:</strong> This method is not called for entity references
833 * appearing as part of attribute values.
834 *
835 * @param name The name of the parameter entity.
836 * @param augs Additional information that may include infoset
837 * augmentations.
838 *
839 * @throws XNIException Thrown by handler to signal an error.
840 */
841 public void endParameterEntity(String name, Augmentations augs) throws XNIException {
842
843 try {
844 // Only report endEntity if this entity was actually read.
845 if (augs == null || !Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
846 // SAX2 extension
847 if (fLexicalHandler != null && fLexicalHandlerParameterEntities) {
848 fLexicalHandler.endEntity(name);
849 }
850 }
851 }
852 catch (SAXException e) {
853 throw new XNIException(e);
854 }
855
856 } // endEntity(String)
857
858 /**
859 * An element declaration.
860 *
861 * @param name The name of the element.
862 * @param contentModel The element content model.
863 *
864 * @param augs Additional information that may include infoset
865 * augmentations.
866 *
867 * @throws XNIException Thrown by handler to signal an error.
868 */
869 public void elementDecl(String name, String contentModel, Augmentations augs)
870 throws XNIException {
871
872 try {
873 // SAX2 extension
874 if (fDeclHandler != null) {
875 fDeclHandler.elementDecl(name, contentModel);
876 }
877 }
878 catch (SAXException e) {
879 throw new XNIException(e);
880 }
881
882 } // elementDecl(String,String, Augmentations)
883
884 /**
885 * An attribute declaration.
886 *
887 * @param elementName The name of the element that this attribute
888 * is associated with.
889 * @param attributeName The name of the attribute.
890 * @param type The attribute type. This value will be one of
891 * the following: "CDATA", "ENTITY", "ENTITIES",
892 * "ENUMERATION", "ID", "IDREF", "IDREFS",
893 * "NMTOKEN", "NMTOKENS", or "NOTATION".
894 * @param enumeration If the type has the value "ENUMERATION" or
895 * "NOTATION", this array holds the allowed attribute
896 * values; otherwise, this array is null.
897 * @param defaultType The attribute default type. This value will be
898 * one of the following: "#FIXED", "#IMPLIED",
899 * "#REQUIRED", or null.
900 * @param defaultValue The attribute default value, or null if no
901 * default value is specified.
902 *
903 * @param nonNormalizedDefaultValue The attribute default value with no normalization
904 * performed, or null if no default value is specified.
905 * @param augs Additional information that may include infoset
906 * augmentations.
907 *
908 * @throws XNIException Thrown by handler to signal an error.
909 */
910 public void attributeDecl(String elementName, String attributeName,
911 String type, String[] enumeration,
912 String defaultType, XMLString defaultValue,
913 XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {
914
915 try {
916 // SAX2 extension
917 if (fDeclHandler != null) {
918 // used as a key to detect duplicate attribute definitions.
919 String elemAttr = new StringBuffer(elementName).append("<").append(attributeName).toString();
920 if(fDeclaredAttrs.get(elemAttr) != null) {
921 // we aren't permitted to return duplicate attribute definitions
922 return;
923 }
924 fDeclaredAttrs.put(elemAttr, Boolean.TRUE);
925 if (type.equals("NOTATION") ||
926 type.equals("ENUMERATION")) {
927
928 StringBuffer str = new StringBuffer();
929 if (type.equals("NOTATION")) {
930 str.append(type);
931 str.append(" (");
932 }
933 else {
934 str.append("(");
935 }
936 for (int i = 0; i < enumeration.length; i++) {
937 str.append(enumeration[i]);
938 if (i < enumeration.length - 1) {
939 str.append('|');
940 }
941 }
942 str.append(')');
943 type = str.toString();
944 }
945 String value = (defaultValue==null) ? null : defaultValue.toString();
946 fDeclHandler.attributeDecl(elementName, attributeName,
947 type, defaultType, value);
948 }
949 }
950 catch (SAXException e) {
951 throw new XNIException(e);
952 }
953
954 } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations)
955
956 /**
957 * An internal entity declaration.
958 *
959 * @param name The name of the entity. Parameter entity names start with
960 * '%', whereas the name of a general entity is just the
961 * entity name.
962 * @param text The value of the entity.
963 * @param nonNormalizedText The non-normalized value of the entity. This
964 * value contains the same sequence of characters that was in
965 * the internal entity declaration, without any entity
966 * references expanded.
967 *
968 * @param augs Additional information that may include infoset
969 * augmentations.
970 *
971 * @throws XNIException Thrown by handler to signal an error.
972 */
973 public void internalEntityDecl(String name, XMLString text,
974 XMLString nonNormalizedText,
975 Augmentations augs) throws XNIException {
976
977 try {
978 // SAX2 extensions
979 if (fDeclHandler != null) {
980 fDeclHandler.internalEntityDecl(name, text.toString());
981 }
982 }
983 catch (SAXException e) {
984 throw new XNIException(e);
985 }
986
987 } // internalEntityDecl(String,XMLString,XMLString)
988
989 /**
990 * An external entity declaration.
991 *
992 * @param name The name of the entity. Parameter entity names start
993 * with '%', whereas the name of a general entity is just
994 * the entity name.
995 * @param identifier An object containing all location information
996 * pertinent to this entity.
997 * @param augs Additional information that may include infoset
998 * augmentations.
999 *
1000 * @throws XNIException Thrown by handler to signal an error.
1001 */
1002 public void externalEntityDecl(String name, XMLResourceIdentifier identifier,
1003 Augmentations augs) throws XNIException {
1004 try {
1005 // SAX2 extension
1006 if (fDeclHandler != null) {
1007 String publicId = identifier.getPublicId();
1008 String systemId = fResolveDTDURIs ?
1009 identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
1010 fDeclHandler.externalEntityDecl(name, publicId, systemId);
1011 }
1012 }
1013 catch (SAXException e) {
1014 throw new XNIException(e);
1015 }
1016
1017 } // externalEntityDecl(String,,XMLResourceIdentifier, Augmentations)
1018
1019 /**
1020 * An unparsed entity declaration.
1021 *
1022 * @param name The name of the entity.
1023 * @param identifier An object containing all location information
1024 * pertinent to this entity.
1025 * @param notation The name of the notation.
1026 *
1027 * @param augs Additional information that may include infoset
1028 * augmentations.
1029 *
1030 * @throws XNIException Thrown by handler to signal an error.
1031 */
1032 public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier,
1033 String notation,
1034 Augmentations augs) throws XNIException {
1035 try {
1036 // SAX2 extension
1037 if (fDTDHandler != null) {
1038 String publicId = identifier.getPublicId();
1039 String systemId = fResolveDTDURIs ?
1040 identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
1041 fDTDHandler.unparsedEntityDecl(name, publicId, systemId, notation);
1042 }
1043 }
1044 catch (SAXException e) {
1045 throw new XNIException(e);
1046 }
1047
1048 } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations)
1049
1050 /**
1051 * A notation declaration
1052 *
1053 * @param name The name of the notation.
1054 * @param identifier An object containing all location information
1055 * pertinent to this notation.
1056 * @param augs Additional information that may include infoset
1057 * augmentations.
1058 *
1059 * @throws XNIException Thrown by handler to signal an error.
1060 */
1061 public void notationDecl(String name, XMLResourceIdentifier identifier,
1062 Augmentations augs) throws XNIException {
1063 try {
1064 // SAX1 and SAX2
1065 if (fDTDHandler != null) {
1066 String publicId = identifier.getPublicId();
1067 String systemId = fResolveDTDURIs ?
1068 identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
1069 fDTDHandler.notationDecl(name, publicId, systemId);
1070 }
1071 }
1072 catch (SAXException e) {
1073 throw new XNIException(e);
1074 }
1075
1076 } // notationDecl(String,XMLResourceIdentifier, Augmentations)
1077
1078 /**
1079 * The end of the DTD.
1080 *
1081 * @param augs Additional information that may include infoset
1082 * augmentations.
1083 *
1084 * @throws XNIException Thrown by handler to signal an error.
1085 */
1086 public void endDTD(Augmentations augs) throws XNIException {
1087 fInDTD = false;
1088
1089 try {
1090 // SAX2 extension
1091 if (fLexicalHandler != null) {
1092 fLexicalHandler.endDTD();
1093 }
1094 }
1095 catch (SAXException e) {
1096 throw new XNIException(e);
1097 }
1098 if(fDeclaredAttrs != null) {
1099 // help out the GC
1100 fDeclaredAttrs.clear();
1101 }
1102
1103 } // endDTD()
1104
1105 //
1106 // Parser and XMLReader methods
1107 //
1108
1109 /**
1110 * Parses the input source specified by the given system identifier.
1111 * <p>
1112 * This method is equivalent to the following:
1113 * <pre>
1114 * parse(new InputSource(systemId));
1115 * </pre>
1116 *
1117 * @param systemId The system identifier (URI).
1118 *
1119 * @exception org.xml.sax.SAXException Throws exception on SAX error.
1120 * @exception java.io.IOException Throws exception on i/o error.
1121 */
1122 public void parse(String systemId) throws SAXException, IOException {
1123
1124 // parse document
1125 XMLInputSource source = new XMLInputSource(null, systemId, null);
1126 try {
1127 parse(source);
1128 }
1129
1130 // wrap XNI exceptions as SAX exceptions
1131 catch (XMLParseException e) {
1132 Exception ex = e.getException();
1133 if (ex == null || ex instanceof CharConversionException) {
1134 // must be a parser exception; mine it for locator info
1135 // and throw a SAXParseException
1136 Locator2Impl locatorImpl = new Locator2Impl();
1137 // since XMLParseExceptions know nothing about encoding,
1138 // we cannot return anything meaningful in this context.
1139 // We *could* consult the LocatorProxy, but the
1140 // application can do this itself if it wishes to possibly
1141 // be mislead.
1142 locatorImpl.setXMLVersion(fVersion);
1143 locatorImpl.setPublicId(e.getPublicId());
1144 locatorImpl.setSystemId(e.getExpandedSystemId());
1145 locatorImpl.setLineNumber(e.getLineNumber());
1146 locatorImpl.setColumnNumber(e.getColumnNumber());
1147 throw (ex == null) ?
1148 new SAXParseException(e.getMessage(), locatorImpl) :
1149 new SAXParseException(e.getMessage(), locatorImpl, ex);
1150 }
1151 if (ex instanceof SAXException) {
1152 // why did we create an XMLParseException?
1153 throw (SAXException)ex;
1154 }
1155 if (ex instanceof IOException) {
1156 throw (IOException)ex;
1157 }
1158 throw new SAXException(ex);
1159 }
1160 catch (XNIException e) {
1161 Exception ex = e.getException();
1162 if (ex == null) {
1163 throw new SAXException(e.getMessage());
1164 }
1165 if (ex instanceof SAXException) {
1166 throw (SAXException)ex;
1167 }
1168 if (ex instanceof IOException) {
1169 throw (IOException)ex;
1170 }
1171 throw new SAXException(ex);
1172 }
1173
1174 } // parse(String)
1175
1176 /**
1177 * parse
1178 *
1179 * @param inputSource
1180 *
1181 * @exception org.xml.sax.SAXException
1182 * @exception java.io.IOException
1183 */
1184 public void parse(InputSource inputSource)
1185 throws SAXException, IOException {
1186
1187 // parse document
1188 try {
1189 XMLInputSource xmlInputSource =
1190 new XMLInputSource(inputSource.getPublicId(),
1191 inputSource.getSystemId(),
1192 null);
1193 xmlInputSource.setByteStream(inputSource.getByteStream());
1194 xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
1195 xmlInputSource.setEncoding(inputSource.getEncoding());
1196 parse(xmlInputSource);
1197 }
1198
1199 // wrap XNI exceptions as SAX exceptions
1200 catch (XMLParseException e) {
1201 Exception ex = e.getException();
1202 if (ex == null || ex instanceof CharConversionException) {
1203 // must be a parser exception; mine it for locator info
1204 // and throw a SAXParseException
1205 Locator2Impl locatorImpl = new Locator2Impl();
1206 // since XMLParseExceptions know nothing about encoding,
1207 // we cannot return anything meaningful in this context.
1208 // We *could* consult the LocatorProxy, but the
1209 // application can do this itself if it wishes to possibly
1210 // be mislead.
1211 locatorImpl.setXMLVersion(fVersion);
1212 locatorImpl.setPublicId(e.getPublicId());
1213 locatorImpl.setSystemId(e.getExpandedSystemId());
1214 locatorImpl.setLineNumber(e.getLineNumber());
1215 locatorImpl.setColumnNumber(e.getColumnNumber());
1216 throw (ex == null) ?
1217 new SAXParseException(e.getMessage(), locatorImpl) :
1218 new SAXParseException(e.getMessage(), locatorImpl, ex);
1219 }
1220 if (ex instanceof SAXException) {
1221 // why did we create an XMLParseException?
1222 throw (SAXException)ex;
1223 }
1224 if (ex instanceof IOException) {
1225 throw (IOException)ex;
1226 }
1227 throw new SAXException(ex);
1228 }
1229 catch (XNIException e) {
1230 Exception ex = e.getException();
1231 if (ex == null) {
1232 throw new SAXException(e.getMessage());
1233 }
1234 if (ex instanceof SAXException) {
1235 throw (SAXException)ex;
1236 }
1237 if (ex instanceof IOException) {
1238 throw (IOException)ex;
1239 }
1240 throw new SAXException(ex);
1241 }
1242
1243 } // parse(InputSource)
1244
1245 /**
1246 * Sets the resolver used to resolve external entities. The EntityResolver
1247 * interface supports resolution of public and system identifiers.
1248 *
1249 * @param resolver The new entity resolver. Passing a null value will
1250 * uninstall the currently installed resolver.
1251 */
1252 public void setEntityResolver(EntityResolver resolver) {
1253
1254 try {
1255 XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER);
1256 if (fUseEntityResolver2 && resolver instanceof EntityResolver2) {
1257 if (xer instanceof EntityResolver2Wrapper) {
1258 EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer;
1259 er2w.setEntityResolver((EntityResolver2) resolver);
1260 }
1261 else {
1262 fConfiguration.setProperty(ENTITY_RESOLVER,
1263 new EntityResolver2Wrapper((EntityResolver2) resolver));
1264 }
1265 }
1266 else {
1267 if (xer instanceof EntityResolverWrapper) {
1268 EntityResolverWrapper erw = (EntityResolverWrapper) xer;
1269 erw.setEntityResolver(resolver);
1270 }
1271 else {
1272 fConfiguration.setProperty(ENTITY_RESOLVER,
1273 new EntityResolverWrapper(resolver));
1274 }
1275 }
1276 }
1277 catch (XMLConfigurationException e) {
1278 // do nothing
1279 }
1280
1281 } // setEntityResolver(EntityResolver)
1282
1283 /**
1284 * Return the current entity resolver.
1285 *
1286 * @return The current entity resolver, or null if none
1287 * has been registered.
1288 * @see #setEntityResolver
1289 */
1290 public EntityResolver getEntityResolver() {
1291
1292 EntityResolver entityResolver = null;
1293 try {
1294 XMLEntityResolver xmlEntityResolver =
1295 (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER);
1296 if (xmlEntityResolver != null) {
1297 if (xmlEntityResolver instanceof EntityResolverWrapper) {
1298 entityResolver =
1299 ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver();
1300 }
1301 else if (xmlEntityResolver instanceof EntityResolver2Wrapper) {
1302 entityResolver =
1303 ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver();
1304 }
1305 }
1306 }
1307 catch (XMLConfigurationException e) {
1308 // do nothing
1309 }
1310 return entityResolver;
1311
1312 } // getEntityResolver():EntityResolver
1313
1314 /**
1315 * Allow an application to register an error event handler.
1316 *
1317 * <p>If the application does not register an error handler, all
1318 * error events reported by the SAX parser will be silently
1319 * ignored; however, normal processing may not continue. It is
1320 * highly recommended that all SAX applications implement an
1321 * error handler to avoid unexpected bugs.</p>
1322 *
1323 * <p>Applications may register a new or different handler in the
1324 * middle of a parse, and the SAX parser must begin using the new
1325 * handler immediately.</p>
1326 *
1327 * @param errorHandler The error handler.
1328 * @see #getErrorHandler
1329 */
1330 public void setErrorHandler(ErrorHandler errorHandler) {
1331
1332 try {
1333 XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER);
1334 if (xeh instanceof ErrorHandlerWrapper) {
1335 ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh;
1336 ehw.setErrorHandler(errorHandler);
1337 }
1338 else {
1339 fConfiguration.setProperty(ERROR_HANDLER,
1340 new ErrorHandlerWrapper(errorHandler));
1341 }
1342 }
1343 catch (XMLConfigurationException e) {
1344 // do nothing
1345 }
1346
1347 } // setErrorHandler(ErrorHandler)
1348
1349 /**
1350 * Return the current error handler.
1351 *
1352 * @return The current error handler, or null if none
1353 * has been registered.
1354 * @see #setErrorHandler
1355 */
1356 public ErrorHandler getErrorHandler() {
1357
1358 ErrorHandler errorHandler = null;
1359 try {
1360 XMLErrorHandler xmlErrorHandler =
1361 (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER);
1362 if (xmlErrorHandler != null &&
1363 xmlErrorHandler instanceof ErrorHandlerWrapper) {
1364 errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler();
1365 }
1366 }
1367 catch (XMLConfigurationException e) {
1368 // do nothing
1369 }
1370 return errorHandler;
1371
1372 } // getErrorHandler():ErrorHandler
1373
1374 /**
1375 * Set the locale to use for messages.
1376 *
1377 * @param locale The locale object to use for localization of messages.
1378 *
1379 * @exception SAXException An exception thrown if the parser does not
1380 * support the specified locale.
1381 *
1382 * @see org.xml.sax.Parser
1383 */
1384 public void setLocale(Locale locale) throws SAXException {
1385 //REVISIT:this methods is not part of SAX2 interfaces, we should throw exception
1386 //if any application uses SAX2 and sets locale also. -nb
1387 fConfiguration.setLocale(locale);
1388
1389 } // setLocale(Locale)
1390
1391 /**
1392 * Allow an application to register a DTD event handler.
1393 * <p>
1394 * If the application does not register a DTD handler, all DTD
1395 * events reported by the SAX parser will be silently ignored.
1396 * <p>
1397 * Applications may register a new or different handler in the
1398 * middle of a parse, and the SAX parser must begin using the new
1399 * handler immediately.
1400 *
1401 * @param dtdHandler The DTD handler.
1402 *
1403
1404 * @see #getDTDHandler
1405 */
1406 public void setDTDHandler(DTDHandler dtdHandler) {
1407 fDTDHandler = dtdHandler;
1408 } // setDTDHandler(DTDHandler)
1409
1410 //
1411 // Parser methods
1412 //
1413
1414 /**
1415 * Allow an application to register a document event handler.
1416 * <p>
1417 * If the application does not register a document handler, all
1418 * document events reported by the SAX parser will be silently
1419 * ignored (this is the default behaviour implemented by
1420 * HandlerBase).
1421 * <p>
1422 * Applications may register a new or different handler in the
1423 * middle of a parse, and the SAX parser must begin using the new
1424 * handler immediately.
1425 *
1426 * @param documentHandler The document handler.
1427 */
1428 public void setDocumentHandler(DocumentHandler documentHandler) {
1429 fDocumentHandler = documentHandler;
1430 } // setDocumentHandler(DocumentHandler)
1431
1432 //
1433 // XMLReader methods
1434 //
1435
1436 /**
1437 * Allow an application to register a content event handler.
1438 * <p>
1439 * If the application does not register a content handler, all
1440 * content events reported by the SAX parser will be silently
1441 * ignored.
1442 * <p>
1443 * Applications may register a new or different handler in the
1444 * middle of a parse, and the SAX parser must begin using the new
1445 * handler immediately.
1446 *
1447 * @param contentHandler The content handler.
1448 *
1449 * @see #getContentHandler
1450 */
1451 public void setContentHandler(ContentHandler contentHandler) {
1452 fContentHandler = contentHandler;
1453 } // setContentHandler(ContentHandler)
1454
1455 /**
1456 * Return the current content handler.
1457 *
1458 * @return The current content handler, or null if none
1459 * has been registered.
1460 *
1461 * @see #setContentHandler
1462 */
1463 public ContentHandler getContentHandler() {
1464 return fContentHandler;
1465 } // getContentHandler():ContentHandler
1466
1467 /**
1468 * Return the current DTD handler.
1469 *
1470 * @return The current DTD handler, or null if none
1471 * has been registered.
1472 * @see #setDTDHandler
1473 */
1474 public DTDHandler getDTDHandler() {
1475 return fDTDHandler;
1476 } // getDTDHandler():DTDHandler
1477
1478 /**
1479 * Set the state of any feature in a SAX2 parser. The parser
1480 * might not recognize the feature, and if it does recognize
1481 * it, it might not be able to fulfill the request.
1482 *
1483 * @param featureId The unique identifier (URI) of the feature.
1484 * @param state The requested state of the feature (true or false).
1485 *
1486 * @exception SAXNotRecognizedException If the
1487 * requested feature is not known.
1488 * @exception SAXNotSupportedException If the
1489 * requested feature is known, but the requested
1490 * state is not supported.
1491 */
1492 public void setFeature(String featureId, boolean state)
1493 throws SAXNotRecognizedException, SAXNotSupportedException {
1494
1495 try {
1496 //
1497 // SAX2 Features
1498 //
1499
1500 if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) {
1501 final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length();
1502
1503 // http://xml.org/sax/features/namespaces
1504 if (suffixLength == Constants.NAMESPACES_FEATURE.length() &&
1505 featureId.endsWith(Constants.NAMESPACES_FEATURE)) {
1506 fConfiguration.setFeature(featureId, state);
1507 fNamespaces = state;
1508 return;
1509 }
1510
1511 // http://xml.org/sax/features/namespace-prefixes
1512 // controls the reporting of raw prefixed names and Namespace
1513 // declarations (xmlns* attributes): when this feature is false
1514 // (the default), raw prefixed names may optionally be reported,
1515 // and xmlns* attributes must not be reported.
1516 //
1517 if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() &&
1518 featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) {
1519 fNamespacePrefixes = state;
1520 return;
1521 }
1522
1523 // http://xml.org/sax/features/string-interning
1524 // controls the use of java.lang.String#intern() for strings
1525 // passed to SAX handlers.
1526 //
1527 if (suffixLength == Constants.STRING_INTERNING_FEATURE.length() &&
1528 featureId.endsWith(Constants.STRING_INTERNING_FEATURE)) {
1529 if (!state) {
1530 throw new SAXNotSupportedException(
1531 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1532 "false-not-supported", new Object [] {featureId}));
1533 }
1534 return;
1535 }
1536
1537 // http://xml.org/sax/features/lexical-handler/parameter-entities
1538 // controls whether the beginning and end of parameter entities
1539 // will be reported to the LexicalHandler.
1540 //
1541 if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() &&
1542 featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) {
1543 fLexicalHandlerParameterEntities = state;
1544 return;
1545 }
1546
1547 // http://xml.org/sax/features/resolve-dtd-uris
1548 // controls whether system identifiers will be absolutized relative to
1549 // their base URIs before reporting.
1550 //
1551 if (suffixLength == Constants.RESOLVE_DTD_URIS_FEATURE.length() &&
1552 featureId.endsWith(Constants.RESOLVE_DTD_URIS_FEATURE)) {
1553 fResolveDTDURIs = state;
1554 return;
1555 }
1556
1557 // http://xml.org/sax/features/unicode-normalization-checking
1558 // controls whether Unicode normalization checking is performed
1559 // as per Appendix B of the XML 1.1 specification
1560 //
1561 if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() &&
1562 featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) {
1563 // REVISIT: Allow this feature to be set once Unicode normalization
1564 // checking is supported -- mrglavas.
1565 if (state) {
1566 throw new SAXNotSupportedException(
1567 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1568 "true-not-supported", new Object [] {featureId}));
1569 }
1570 return;
1571 }
1572
1573 // http://xml.org/sax/features/xmlns-uris
1574 // controls whether the parser reports that namespace declaration
1575 // attributes as being in the namespace: http://www.w3.org/2000/xmlns/
1576 //
1577 if (suffixLength == Constants.XMLNS_URIS_FEATURE.length() &&
1578 featureId.endsWith(Constants.XMLNS_URIS_FEATURE)) {
1579 fXMLNSURIs = state;
1580 return;
1581 }
1582
1583 // http://xml.org/sax/features/use-entity-resolver2
1584 // controls whether the methods of an object implementing
1585 // org.xml.sax.ext.EntityResolver2 will be used by the parser.
1586 //
1587 if (suffixLength == Constants.USE_ENTITY_RESOLVER2_FEATURE.length() &&
1588 featureId.endsWith(Constants.USE_ENTITY_RESOLVER2_FEATURE)) {
1589 if (state != fUseEntityResolver2) {
1590 fUseEntityResolver2 = state;
1591 // Refresh EntityResolver wrapper.
1592 setEntityResolver(getEntityResolver());
1593 }
1594 return;
1595 }
1596
1597 //
1598 // Read only features.
1599 //
1600
1601 // http://xml.org/sax/features/is-standalone
1602 // reports whether the document specified a standalone document declaration.
1603 // http://xml.org/sax/features/use-attributes2
1604 // reports whether Attributes objects passed to startElement also implement
1605 // the org.xml.sax.ext.Attributes2 interface.
1606 // http://xml.org/sax/features/use-locator2
1607 // reports whether Locator objects passed to setDocumentLocator also implement
1608 // the org.xml.sax.ext.Locator2 interface.
1609 // http://xml.org/sax/features/xml-1.1
1610 // reports whether the parser supports both XML 1.1 and XML 1.0.
1611 if ((suffixLength == Constants.IS_STANDALONE_FEATURE.length() &&
1612 featureId.endsWith(Constants.IS_STANDALONE_FEATURE)) ||
1613 (suffixLength == Constants.USE_ATTRIBUTES2_FEATURE.length() &&
1614 featureId.endsWith(Constants.USE_ATTRIBUTES2_FEATURE)) ||
1615 (suffixLength == Constants.USE_LOCATOR2_FEATURE.length() &&
1616 featureId.endsWith(Constants.USE_LOCATOR2_FEATURE)) ||
1617 (suffixLength == Constants.XML_11_FEATURE.length() &&
1618 featureId.endsWith(Constants.XML_11_FEATURE))) {
1619 throw new SAXNotSupportedException(
1620 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1621 "feature-read-only", new Object [] {featureId}));
1622 }
1623
1624
1625 //
1626 // Drop through and perform default processing
1627 //
1628 }
1629
1630 //
1631 // Xerces Features
1632 //
1633
1634 /*
1635 else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) {
1636 String feature = featureId.substring(XERCES_FEATURES_PREFIX.length());
1637 //
1638 // Drop through and perform default processing
1639 //
1640 }
1641 */
1642
1643 //
1644 // Default handling
1645 //
1646
1647 fConfiguration.setFeature(featureId, state);
1648 }
1649 catch (XMLConfigurationException e) {
1650 String identifier = e.getIdentifier();
1651 if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
1652 throw new SAXNotRecognizedException(
1653 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1654 "feature-not-recognized", new Object [] {identifier}));
1655 }
1656 else {
1657 throw new SAXNotSupportedException(
1658 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1659 "feature-not-supported", new Object [] {identifier}));
1660 }
1661 }
1662
1663 } // setFeature(String,boolean)
1664
1665 /**
1666 * Query the state of a feature.
1667 *
1668 * Query the current state of any feature in a SAX2 parser. The
1669 * parser might not recognize the feature.
1670 *
1671 * @param featureId The unique identifier (URI) of the feature
1672 * being set.
1673 * @return The current state of the feature.
1674 * @exception org.xml.sax.SAXNotRecognizedException If the
1675 * requested feature is not known.
1676 * @exception SAXNotSupportedException If the
1677 * requested feature is known but not supported.
1678 */
1679 public boolean getFeature(String featureId)
1680 throws SAXNotRecognizedException, SAXNotSupportedException {
1681
1682 try {
1683 //
1684 // SAX2 Features
1685 //
1686
1687 if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) {
1688 final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length();
1689
1690 // http://xml.org/sax/features/namespace-prefixes
1691 // controls the reporting of raw prefixed names and Namespace
1692 // declarations (xmlns* attributes): when this feature is false
1693 // (the default), raw prefixed names may optionally be reported,
1694 // and xmlns* attributes must not be reported.
1695 //
1696 if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() &&
1697 featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) {
1698 return fNamespacePrefixes;
1699 }
1700 // http://xml.org/sax/features/string-interning
1701 // controls the use of java.lang.String#intern() for strings
1702 // passed to SAX handlers.
1703 //
1704 if (suffixLength == Constants.STRING_INTERNING_FEATURE.length() &&
1705 featureId.endsWith(Constants.STRING_INTERNING_FEATURE)) {
1706 return true;
1707 }
1708
1709 // http://xml.org/sax/features/is-standalone
1710 // reports whether the document specified a standalone document declaration.
1711 //
1712 if (suffixLength == Constants.IS_STANDALONE_FEATURE.length() &&
1713 featureId.endsWith(Constants.IS_STANDALONE_FEATURE)) {
1714 return fStandalone;
1715 }
1716
1717 // http://xml.org/sax/features/xml-1.1
1718 // reports whether the parser supports both XML 1.1 and XML 1.0.
1719 //
1720 if (suffixLength == Constants.XML_11_FEATURE.length() &&
1721 featureId.endsWith(Constants.XML_11_FEATURE)) {
1722 return (fConfiguration instanceof XML11Configurable);
1723 }
1724
1725 // http://xml.org/sax/features/lexical-handler/parameter-entities
1726 // controls whether the beginning and end of parameter entities
1727 // will be reported to the LexicalHandler.
1728 //
1729 if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() &&
1730 featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) {
1731 return fLexicalHandlerParameterEntities;
1732 }
1733
1734 // http://xml.org/sax/features/resolve-dtd-uris
1735 // controls whether system identifiers will be absolutized relative to
1736 // their base URIs before reporting.
1737 if (suffixLength == Constants.RESOLVE_DTD_URIS_FEATURE.length() &&
1738 featureId.endsWith(Constants.RESOLVE_DTD_URIS_FEATURE)) {
1739 return fResolveDTDURIs;
1740 }
1741
1742 // http://xml.org/sax/features/xmlns-uris
1743 // controls whether the parser reports that namespace declaration
1744 // attributes as being in the namespace: http://www.w3.org/2000/xmlns/
1745 //
1746 if (suffixLength == Constants.XMLNS_URIS_FEATURE.length() &&
1747 featureId.endsWith(Constants.XMLNS_URIS_FEATURE)) {
1748 return fXMLNSURIs;
1749 }
1750
1751 // http://xml.org/sax/features/unicode-normalization-checking
1752 // controls whether Unicode normalization checking is performed
1753 // as per Appendix B of the XML 1.1 specification
1754 //
1755 if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() &&
1756 featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) {
1757 // REVISIT: Allow this feature to be set once Unicode normalization
1758 // checking is supported -- mrglavas.
1759 return false;
1760 }
1761
1762 // http://xml.org/sax/features/use-entity-resolver2
1763 // controls whether the methods of an object implementing
1764 // org.xml.sax.ext.EntityResolver2 will be used by the parser.
1765 //
1766 if (suffixLength == Constants.USE_ENTITY_RESOLVER2_FEATURE.length() &&
1767 featureId.endsWith(Constants.USE_ENTITY_RESOLVER2_FEATURE)) {
1768 return fUseEntityResolver2;
1769 }
1770
1771 // http://xml.org/sax/features/use-attributes2
1772 // reports whether Attributes objects passed to startElement also implement
1773 // the org.xml.sax.ext.Attributes2 interface.
1774 // http://xml.org/sax/features/use-locator2
1775 // reports whether Locator objects passed to setDocumentLocator also implement
1776 // the org.xml.sax.ext.Locator2 interface.
1777 //
1778 if ((suffixLength == Constants.USE_ATTRIBUTES2_FEATURE.length() &&
1779 featureId.endsWith(Constants.USE_ATTRIBUTES2_FEATURE)) ||
1780 (suffixLength == Constants.USE_LOCATOR2_FEATURE.length() &&
1781 featureId.endsWith(Constants.USE_LOCATOR2_FEATURE))) {
1782 return true;
1783 }
1784
1785
1786 //
1787 // Drop through and perform default processing
1788 //
1789 }
1790
1791 //
1792 // Xerces Features
1793 //
1794
1795 /*
1796 else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) {
1797 //
1798 // Drop through and perform default processing
1799 //
1800 }
1801 */
1802
1803 return fConfiguration.getFeature(featureId);
1804 }
1805 catch (XMLConfigurationException e) {
1806 String identifier = e.getIdentifier();
1807 if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
1808 throw new SAXNotRecognizedException(
1809 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1810 "feature-not-recognized", new Object [] {identifier}));
1811 }
1812 else {
1813 throw new SAXNotSupportedException(
1814 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1815 "feature-not-supported", new Object [] {identifier}));
1816 }
1817 }
1818
1819 } // getFeature(String):boolean
1820
1821 /**
1822 * Set the value of any property in a SAX2 parser. The parser
1823 * might not recognize the property, and if it does recognize
1824 * it, it might not support the requested value.
1825 *
1826 * @param propertyId The unique identifier (URI) of the property
1827 * being set.
1828 * @param value The value to which the property is being set.
1829 *
1830 * @exception SAXNotRecognizedException If the
1831 * requested property is not known.
1832 * @exception SAXNotSupportedException If the
1833 * requested property is known, but the requested
1834 * value is not supported.
1835 */
1836 public void setProperty(String propertyId, Object value)
1837 throws SAXNotRecognizedException, SAXNotSupportedException {
1838
1839 try {
1840 //
1841 // SAX2 core properties
1842 //
1843
1844 if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
1845 final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length();
1846
1847 //
1848 // http://xml.org/sax/properties/lexical-handler
1849 // Value type: org.xml.sax.ext.LexicalHandler
1850 // Access: read/write, pre-parse only
1851 // Set the lexical event handler.
1852 //
1853 if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() &&
1854 propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) {
1855 try {
1856 setLexicalHandler((LexicalHandler)value);
1857 }
1858 catch (ClassCastException e) {
1859 throw new SAXNotSupportedException(
1860 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1861 "incompatible-class", new Object [] {propertyId, "org.xml.sax.ext.LexicalHandler"}));
1862 }
1863 return;
1864 }
1865 //
1866 // http://xml.org/sax/properties/declaration-handler
1867 // Value type: org.xml.sax.ext.DeclHandler
1868 // Access: read/write, pre-parse only
1869 // Set the DTD declaration event handler.
1870 //
1871 if (suffixLength == Constants.DECLARATION_HANDLER_PROPERTY.length() &&
1872 propertyId.endsWith(Constants.DECLARATION_HANDLER_PROPERTY)) {
1873 try {
1874 setDeclHandler((DeclHandler)value);
1875 }
1876 catch (ClassCastException e) {
1877 throw new SAXNotSupportedException(
1878 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1879 "incompatible-class", new Object [] {propertyId, "org.xml.sax.ext.DeclHandler"}));
1880 }
1881 return;
1882 }
1883 //
1884 // http://xml.org/sax/properties/dom-node
1885 // Value type: DOM Node
1886 // Access: read-only
1887 // Get the DOM node currently being visited, if the SAX parser is
1888 // iterating over a DOM tree. If the parser recognises and
1889 // supports this property but is not currently visiting a DOM
1890 // node, it should return null (this is a good way to check for
1891 // availability before the parse begins).
1892 // http://xml.org/sax/properties/document-xml-version
1893 // Value type: java.lang.String
1894 // Access: read-only
1895 // The literal string describing the actual XML version of the document.
1896 //
1897 if ((suffixLength == Constants.DOM_NODE_PROPERTY.length() &&
1898 propertyId.endsWith(Constants.DOM_NODE_PROPERTY)) ||
1899 (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() &&
1900 propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY))) {
1901 throw new SAXNotSupportedException(
1902 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1903 "property-read-only", new Object [] {propertyId}));
1904 }
1905 //
1906 // Drop through and perform default processing
1907 //
1908 }
1909
1910 //
1911 // Xerces Properties
1912 //
1913
1914 /*
1915 else if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) {
1916 //
1917 // Drop through and perform default processing
1918 //
1919 }
1920 */
1921
1922 //
1923 // Perform default processing
1924 //
1925
1926 fConfiguration.setProperty(propertyId, value);
1927 }
1928 catch (XMLConfigurationException e) {
1929 String identifier = e.getIdentifier();
1930 if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
1931 throw new SAXNotRecognizedException(
1932 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1933 "property-not-recognized", new Object [] {identifier}));
1934 }
1935 else {
1936 throw new SAXNotSupportedException(
1937 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1938 "property-not-supported", new Object [] {identifier}));
1939 }
1940 }
1941
1942 } // setProperty(String,Object)
1943
1944 /**
1945 * Query the value of a property.
1946 *
1947 * Return the current value of a property in a SAX2 parser.
1948 * The parser might not recognize the property.
1949 *
1950 * @param propertyId The unique identifier (URI) of the property
1951 * being set.
1952 * @return The current value of the property.
1953 * @exception org.xml.sax.SAXNotRecognizedException If the
1954 * requested property is not known.
1955 * @exception SAXNotSupportedException If the
1956 * requested property is known but not supported.
1957 */
1958 public Object getProperty(String propertyId)
1959 throws SAXNotRecognizedException, SAXNotSupportedException {
1960
1961 try {
1962 //
1963 // SAX2 core properties
1964 //
1965
1966 if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
1967 final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length();
1968
1969 //
1970 // http://xml.org/sax/properties/document-xml-version
1971 // Value type: java.lang.String
1972 // Access: read-only
1973 // The literal string describing the actual XML version of the document.
1974 //
1975 if (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() &&
1976 propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY)) {
1977 return fVersion;
1978 }
1979
1980 //
1981 // http://xml.org/sax/properties/lexical-handler
1982 // Value type: org.xml.sax.ext.LexicalHandler
1983 // Access: read/write, pre-parse only
1984 // Set the lexical event handler.
1985 //
1986 if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() &&
1987 propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) {
1988 return getLexicalHandler();
1989 }
1990 //
1991 // http://xml.org/sax/properties/declaration-handler
1992 // Value type: org.xml.sax.ext.DeclHandler
1993 // Access: read/write, pre-parse only
1994 // Set the DTD declaration event handler.
1995 //
1996 if (suffixLength == Constants.DECLARATION_HANDLER_PROPERTY.length() &&
1997 propertyId.endsWith(Constants.DECLARATION_HANDLER_PROPERTY)) {
1998 return getDeclHandler();
1999 }
2000
2001 //
2002 // http://xml.org/sax/properties/dom-node
2003 // Value type: DOM Node
2004 // Access: read-only
2005 // Get the DOM node currently being visited, if the SAX parser is
2006 // iterating over a DOM tree. If the parser recognises and
2007 // supports this property but is not currently visiting a DOM
2008 // node, it should return null (this is a good way to check for
2009 // availability before the parse begins).
2010 //
2011 if (suffixLength == Constants.DOM_NODE_PROPERTY.length() &&
2012 propertyId.endsWith(Constants.DOM_NODE_PROPERTY)) {
2013 // we are not iterating a DOM tree
2014 throw new SAXNotSupportedException(
2015 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2016 "dom-node-read-not-supported", null));
2017 }
2018
2019 //
2020 // Drop through and perform default processing
2021 //
2022 }
2023
2024 //
2025 // Xerces properties
2026 //
2027
2028 /*
2029 else if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) {
2030 //
2031 // Drop through and perform default processing
2032 //
2033 }
2034 */
2035
2036 //
2037 // Perform default processing
2038 //
2039
2040 return fConfiguration.getProperty(propertyId);
2041 }
2042 catch (XMLConfigurationException e) {
2043 String identifier = e.getIdentifier();
2044 if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
2045 throw new SAXNotRecognizedException(
2046 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2047 "property-not-recognized", new Object [] {identifier}));
2048 }
2049 else {
2050 throw new SAXNotSupportedException(
2051 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2052 "property-not-supported", new Object [] {identifier}));
2053 }
2054 }
2055
2056 } // getProperty(String):Object
2057
2058 //
2059 // Protected methods
2060 //
2061
2062 // SAX2 core properties
2063
2064 /**
2065 * Set the DTD declaration event handler.
2066 * <p>
2067 * This method is the equivalent to the property:
2068 * <pre>
2069 * http://xml.org/sax/properties/declaration-handler
2070 * </pre>
2071 *
2072 * @param handler The new handler.
2073 *
2074 * @see #getDeclHandler
2075 * @see #setProperty
2076 */
2077 protected void setDeclHandler(DeclHandler handler)
2078 throws SAXNotRecognizedException, SAXNotSupportedException {
2079
2080 if (fParseInProgress) {
2081 throw new SAXNotSupportedException(
2082 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2083 "property-not-parsing-supported",
2084 new Object [] {"http://xml.org/sax/properties/declaration-handler"}));
2085 }
2086 fDeclHandler = handler;
2087
2088 } // setDeclHandler(DeclHandler)
2089
2090 /**
2091 * Returns the DTD declaration event handler.
2092 *
2093 * @see #setDeclHandler
2094 */
2095 protected DeclHandler getDeclHandler()
2096 throws SAXNotRecognizedException, SAXNotSupportedException {
2097 return fDeclHandler;
2098 } // getDeclHandler():DeclHandler
2099
2100 /**
2101 * Set the lexical event handler.
2102 * <p>
2103 * This method is the equivalent to the property:
2104 * <pre>
2105 * http://xml.org/sax/properties/lexical-handler
2106 * </pre>
2107 *
2108 * @param handler lexical event handler
2109 *
2110 * @see #getLexicalHandler
2111 * @see #setProperty
2112 */
2113 protected void setLexicalHandler(LexicalHandler handler)
2114 throws SAXNotRecognizedException, SAXNotSupportedException {
2115
2116 if (fParseInProgress) {
2117 throw new SAXNotSupportedException(
2118 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2119 "property-not-parsing-supported",
2120 new Object [] {"http://xml.org/sax/properties/lexical-handler"}));
2121 }
2122 fLexicalHandler = handler;
2123
2124 } // setLexicalHandler(LexicalHandler)
2125
2126 /**
2127 * Returns the lexical handler.
2128 *
2129 * @see #setLexicalHandler
2130 */
2131 protected LexicalHandler getLexicalHandler()
2132 throws SAXNotRecognizedException, SAXNotSupportedException {
2133 return fLexicalHandler;
2134 } // getLexicalHandler():LexicalHandler
2135
2136 /**
2137 * Send startPrefixMapping events
2138 */
2139 protected final void startNamespaceMapping() throws SAXException{
2140 int count = fNamespaceContext.getDeclaredPrefixCount();
2141 if (count > 0) {
2142 String prefix = null;
2143 String uri = null;
2144 for (int i = 0; i < count; i++) {
2145 prefix = fNamespaceContext.getDeclaredPrefixAt(i);
2146 uri = fNamespaceContext.getURI(prefix);
2147 fContentHandler.startPrefixMapping(prefix,
2148 (uri == null) ? "" : uri);
2149 }
2150 }
2151 }
2152
2153 /**
2154 * Send endPrefixMapping events
2155 */
2156 protected final void endNamespaceMapping() throws SAXException {
2157 int count = fNamespaceContext.getDeclaredPrefixCount();
2158 if (count > 0) {
2159 for (int i = 0; i < count; i++) {
2160 fContentHandler.endPrefixMapping(fNamespaceContext.getDeclaredPrefixAt(i));
2161 }
2162 }
2163 }
2164
2165 //
2166 // XMLDocumentParser methods
2167 //
2168
2169 /**
2170 * Reset all components before parsing.
2171 *
2172 * @throws XNIException Thrown if an error occurs during initialization.
2173 */
2174 public void reset() throws XNIException {
2175 super.reset();
2176
2177 // reset state
2178 fInDTD = false;
2179 fVersion = "1.0";
2180 fStandalone = false;
2181
2182 // features
2183 fNamespaces = fConfiguration.getFeature(NAMESPACES);
2184 fAugmentations = null;
2185 fDeclaredAttrs = null;
2186
2187 } // reset()
2188
2189 //
2190 // Classes
2191 //
2192
2193 protected static final class LocatorProxy
2194 implements Locator2 {
2195
2196 //
2197 // Data
2198 //
2199
2200 /** XML locator. */
2201 protected XMLLocator fLocator;
2202
2203 //
2204 // Constructors
2205 //
2206
2207 /** Constructs an XML locator proxy. */
2208 public LocatorProxy(XMLLocator locator) {
2209 fLocator = locator;
2210 }
2211
2212 //
2213 // Locator methods
2214 //
2215
2216 /** Public identifier. */
2217 public String getPublicId() {
2218 return fLocator.getPublicId();
2219 }
2220
2221 /** System identifier. */
2222 public String getSystemId() {
2223 return fLocator.getExpandedSystemId();
2224 }
2225 /** Line number. */
2226 public int getLineNumber() {
2227 return fLocator.getLineNumber();
2228 }
2229
2230 /** Column number. */
2231 public int getColumnNumber() {
2232 return fLocator.getColumnNumber();
2233 }
2234
2235 // Locator2 methods
2236 public String getXMLVersion() {
2237 return fLocator.getXMLVersion();
2238 }
2239
2240 public String getEncoding() {
2241 return fLocator.getEncoding();
2242 }
2243
2244 } // class LocatorProxy
2245
2246 protected static final class AttributesProxy
2247 implements AttributeList, Attributes2 {
2248
2249 //
2250 // Data
2251 //
2252
2253 /** XML attributes. */
2254 protected XMLAttributes fAttributes;
2255
2256 //
2257 // Public methods
2258 //
2259
2260 /** Sets the XML attributes. */
2261 public void setAttributes(XMLAttributes attributes) {
2262 fAttributes = attributes;
2263 } // setAttributes(XMLAttributes)
2264
2265 public int getLength() {
2266 return fAttributes.getLength();
2267 }
2268
2269 public String getName(int i) {
2270 return fAttributes.getQName(i);
2271 }
2272
2273 public String getQName(int index) {
2274 return fAttributes.getQName(index);
2275 }
2276
2277 public String getURI(int index) {
2278 // REVISIT: this hides the fact that internally we use
2279 // null instead of empty string
2280 // SAX requires URI to be a string or an empty string
2281 String uri= fAttributes.getURI(index);
2282 return uri != null ? uri : "";
2283 }
2284
2285 public String getLocalName(int index) {
2286 return fAttributes.getLocalName(index);
2287 }
2288
2289 public String getType(int i) {
2290 return fAttributes.getType(i);
2291 }
2292
2293 public String getType(String name) {
2294 return fAttributes.getType(name);
2295 }
2296
2297 public String getType(String uri, String localName) {
2298 return uri.equals("") ? fAttributes.getType(null, localName) :
2299 fAttributes.getType(uri, localName);
2300 }
2301
2302 public String getValue(int i) {
2303 return fAttributes.getValue(i);
2304 }
2305
2306 public String getValue(String name) {
2307 return fAttributes.getValue(name);
2308 }
2309
2310 public String getValue(String uri, String localName) {
2311 return uri.equals("") ? fAttributes.getValue(null, localName) :
2312 fAttributes.getValue(uri, localName);
2313 }
2314
2315 public int getIndex(String qName) {
2316 return fAttributes.getIndex(qName);
2317 }
2318
2319 public int getIndex(String uri, String localPart) {
2320 return uri.equals("") ? fAttributes.getIndex(null, localPart) :
2321 fAttributes.getIndex(uri, localPart);
2322 }
2323
2324 // Attributes2 methods
2325 // REVISIT: Localize exception messages. -- mrglavas
2326 public boolean isDeclared(int index) {
2327 if (index < 0 || index >= fAttributes.getLength()) {
2328 throw new ArrayIndexOutOfBoundsException(index);