KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > xinclude > XIncludeHandler


1 /*
2  * Copyright 2003-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.xerces.xinclude;
17
18 import java.io.CharConversionException JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import java.util.Locale JavaDoc;
23 import java.util.Stack JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25
26 import org.apache.xerces.impl.Constants;
27 import org.apache.xerces.impl.XMLEntityManager;
28 import org.apache.xerces.impl.XMLErrorReporter;
29 import org.apache.xerces.impl.io.MalformedByteSequenceException;
30 import org.apache.xerces.impl.msg.XMLMessageFormatter;
31 import org.apache.xerces.util.AugmentationsImpl;
32 import org.apache.xerces.util.HTTPInputSource;
33 import org.apache.xerces.util.IntStack;
34 import org.apache.xerces.util.ParserConfigurationSettings;
35 import org.apache.xerces.util.SecurityManager;
36 import org.apache.xerces.util.SymbolTable;
37 import org.apache.xerces.util.URI;
38 import org.apache.xerces.util.XMLAttributesImpl;
39 import org.apache.xerces.util.XMLResourceIdentifierImpl;
40 import org.apache.xerces.util.XMLChar;
41 import org.apache.xerces.util.XMLSymbols;
42 import org.apache.xerces.util.URI.MalformedURIException;
43 import org.apache.xerces.xni.Augmentations;
44 import org.apache.xerces.xni.NamespaceContext;
45 import org.apache.xerces.xni.QName;
46 import org.apache.xerces.xni.XMLAttributes;
47 import org.apache.xerces.xni.XMLDTDHandler;
48 import org.apache.xerces.xni.XMLDocumentHandler;
49 import org.apache.xerces.xni.XMLLocator;
50 import org.apache.xerces.xni.XMLResourceIdentifier;
51 import org.apache.xerces.xni.XMLString;
52 import org.apache.xerces.xni.XNIException;
53 import org.apache.xerces.xni.parser.XMLComponent;
54 import org.apache.xerces.xni.parser.XMLComponentManager;
55 import org.apache.xerces.xni.parser.XMLConfigurationException;
56 import org.apache.xerces.xni.parser.XMLDTDFilter;
57 import org.apache.xerces.xni.parser.XMLDTDSource;
58 import org.apache.xerces.xni.parser.XMLDocumentFilter;
59 import org.apache.xerces.xni.parser.XMLDocumentSource;
60 import org.apache.xerces.xni.parser.XMLEntityResolver;
61 import org.apache.xerces.xni.parser.XMLInputSource;
62 import org.apache.xerces.xni.parser.XMLParserConfiguration;
63 import org.apache.xerces.xpointer.XPointerHandler;
64 import org.apache.xerces.xpointer.XPointerProcessor;
65
66 /**
67  * <p>
68  * This is a pipeline component which performs XInclude handling, according to the
69  * W3C specification for XML Inclusions.
70  * </p>
71  * <p>
72  * This component analyzes each event in the pipeline, looking for &lt;include&gt;
73  * elements. An &lt;include&gt; element is one which has a namespace of
74  * <code>http://www.w3.org/2001/XInclude</code> and a localname of <code>include</code>.
75  * When it finds an &lt;include&gt; element, it attempts to include the file specified
76  * in the <code>href</code> attribute of the element. If inclusion succeeds, all
77  * children of the &lt;include&gt; element are ignored (with the exception of
78  * checking for invalid children as outlined in the specification). If the inclusion
79  * fails, the &lt;fallback&gt; child of the &lt;include&gt; element is processed.
80  * </p>
81  * <p>
82  * See the <a HREF="http://www.w3.org/TR/xinclude/">XInclude specification</a> for
83  * more information on how XInclude is to be used.
84  * </p>
85  * <p>
86  * This component requires the following features and properties from the
87  * component manager that uses it:
88  * <ul>
89  * <li>http://xml.org/sax/features/allow-dtd-events-after-endDTD</li>
90  * <li>http://apache.org/xml/properties/internal/error-reporter</li>
91  * <li>http://apache.org/xml/properties/internal/entity-resolver</li>
92  * </ul>
93  * Optional property:
94  * <ul>
95  * <li>http://apache.org/xml/properties/input-buffer-size</li>
96  * </ul>
97  *
98  * Furthermore, the <code>NamespaceContext</code> used in the pipeline is required
99  * to be an instance of <code>XIncludeNamespaceSupport</code>.
100  * </p>
101  * <p>
102  * Currently, this implementation has only partial support for the XInclude specification.
103  * Specifically, it is missing support for XPointer document fragments. Thus, only whole
104  * documents can be included using this component in the pipeline.
105  * </p>
106  *
107  * @author Peter McCracken, IBM
108  * @author Michael Glavassevich, IBM
109  *
110  * @version $Id: XIncludeHandler.java,v 1.56 2005/07/25 18:04:26 mrglavas Exp $
111  *
112  * @see XIncludeNamespaceSupport
113  */

114 public class XIncludeHandler
115     implements XMLComponent, XMLDocumentFilter, XMLDTDFilter {
116
117     public final static String JavaDoc XINCLUDE_DEFAULT_CONFIGURATION =
118         "org.apache.xerces.parsers.XIncludeParserConfiguration";
119     public final static String JavaDoc HTTP_ACCEPT = "Accept";
120     public final static String JavaDoc HTTP_ACCEPT_LANGUAGE = "Accept-Language";
121     public final static String JavaDoc XPOINTER = "xpointer";
122
123     public final static String JavaDoc XINCLUDE_NS_URI =
124         "http://www.w3.org/2001/XInclude".intern();
125     public final static String JavaDoc XINCLUDE_INCLUDE = "include".intern();
126     public final static String JavaDoc XINCLUDE_FALLBACK = "fallback".intern();
127
128     public final static String JavaDoc XINCLUDE_PARSE_XML = "xml".intern();
129     public final static String JavaDoc XINCLUDE_PARSE_TEXT = "text".intern();
130
131     public final static String JavaDoc XINCLUDE_ATTR_HREF = "href".intern();
132     public final static String JavaDoc XINCLUDE_ATTR_PARSE = "parse".intern();
133     public final static String JavaDoc XINCLUDE_ATTR_ENCODING = "encoding".intern();
134     public final static String JavaDoc XINCLUDE_ATTR_ACCEPT = "accept".intern();
135     public final static String JavaDoc XINCLUDE_ATTR_ACCEPT_LANGUAGE = "accept-language".intern();
136
137     // Top Level Information Items have [included] property in infoset
138
public final static String JavaDoc XINCLUDE_INCLUDED = "[included]".intern();
139
140     /** The identifier for the Augmentation that contains the current base URI */
141     public final static String JavaDoc CURRENT_BASE_URI = "currentBaseURI";
142
143     // used for adding [base URI] attributes
144
public final static String JavaDoc XINCLUDE_BASE = "base".intern();
145     public final static QName XML_BASE_QNAME =
146         new QName(
147             XMLSymbols.PREFIX_XML,
148             XINCLUDE_BASE,
149             (XMLSymbols.PREFIX_XML + ":" + XINCLUDE_BASE).intern(),
150             NamespaceContext.XML_URI);
151     
152     // used for adding [language] attributes
153
public final static String JavaDoc XINCLUDE_LANG = "lang".intern();
154     public final static QName XML_LANG_QNAME =
155         new QName(
156             XMLSymbols.PREFIX_XML,
157             XINCLUDE_LANG,
158             (XMLSymbols.PREFIX_XML + ":" + XINCLUDE_LANG).intern(),
159             NamespaceContext.XML_URI);
160
161     public final static QName NEW_NS_ATTR_QNAME =
162         new QName(
163             XMLSymbols.PREFIX_XMLNS,
164             "",
165             XMLSymbols.PREFIX_XMLNS + ":",
166             NamespaceContext.XMLNS_URI);
167
168     // Processing States
169
private final static int STATE_NORMAL_PROCESSING = 1;
170     // we go into this state after a successful include (thus we ignore the children
171
// of the include) or after a fallback
172
private final static int STATE_IGNORE = 2;
173     // we go into this state after a failed include. If we don't encounter a fallback
174
// before we reach the end include tag, it's a fatal error
175
private final static int STATE_EXPECT_FALLBACK = 3;
176
177     // recognized features and properties
178

179     /** Feature identifier: validation. */
180     protected static final String JavaDoc VALIDATION =
181         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
182     
183     /** Feature identifier: schema validation. */
184     protected static final String JavaDoc SCHEMA_VALIDATION =
185         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
186     
187     /** Feature identifier: dynamic validation. */
188     protected static final String JavaDoc DYNAMIC_VALIDATION =
189         Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
190
191     /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */
192     protected static final String JavaDoc ALLOW_UE_AND_NOTATION_EVENTS =
193         Constants.SAX_FEATURE_PREFIX
194             + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE;
195     
196     /** Feature identifier: fixup base URIs. */
197     protected static final String JavaDoc XINCLUDE_FIXUP_BASE_URIS =
198         Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE;
199     
200     /** Feature identifier: fixup language. */
201     protected static final String JavaDoc XINCLUDE_FIXUP_LANGUAGE =
202         Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE;
203     
204     /** Property identifier: symbol table. */
205     protected static final String JavaDoc SYMBOL_TABLE =
206         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
207
208     /** Property identifier: error reporter. */
209     protected static final String JavaDoc ERROR_REPORTER =
210         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
211
212     /** Property identifier: entity resolver. */
213     protected static final String JavaDoc ENTITY_RESOLVER =
214         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
215
216     /** property identifier: security manager. */
217     protected static final String JavaDoc SECURITY_MANAGER =
218         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
219     
220     /** property identifier: buffer size. */
221     public static final String JavaDoc BUFFER_SIZE =
222         Constants.XERCES_PROPERTY_PREFIX + Constants.BUFFER_SIZE_PROPERTY;
223     
224     protected static final String JavaDoc PARSER_SETTINGS =
225         Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
226
227     /** Recognized features. */
228     private static final String JavaDoc[] RECOGNIZED_FEATURES =
229         { ALLOW_UE_AND_NOTATION_EVENTS, XINCLUDE_FIXUP_BASE_URIS, XINCLUDE_FIXUP_LANGUAGE };
230
231     /** Feature defaults. */
232     private static final Boolean JavaDoc[] FEATURE_DEFAULTS = { Boolean.TRUE, Boolean.TRUE, Boolean.TRUE };
233
234     /** Recognized properties. */
235     private static final String JavaDoc[] RECOGNIZED_PROPERTIES =
236         { ERROR_REPORTER, ENTITY_RESOLVER, SECURITY_MANAGER, BUFFER_SIZE };
237
238     /** Property defaults. */
239     private static final Object JavaDoc[] PROPERTY_DEFAULTS = { null, null, null, new Integer JavaDoc(XMLEntityManager.DEFAULT_BUFFER_SIZE) };
240
241     // instance variables
242

243     // for XMLDocumentFilter
244
protected XMLDocumentHandler fDocumentHandler;
245     protected XMLDocumentSource fDocumentSource;
246
247     // for XMLDTDFilter
248
protected XMLDTDHandler fDTDHandler;
249     protected XMLDTDSource fDTDSource;
250
251     // for XIncludeHandler
252
protected XIncludeHandler fParentXIncludeHandler;
253     
254     // for buffer size in XIncludeTextReader
255
protected int fBufferSize = XMLEntityManager.DEFAULT_BUFFER_SIZE;
256
257     // It "feels wrong" to store this value here. However,
258
// calculating it can be time consuming, so we cache it.
259
// It's never going to change in the lifetime of this XIncludeHandler
260
protected String JavaDoc fParentRelativeURI;
261
262     // we cache the child parser configuration, so we don't have to re-create
263
// the objects when the parser is re-used
264
protected XMLParserConfiguration fChildConfig;
265
266     // The cached child parser configuration, may contain a
267
// XInclude or XPointer Handler. Cache both these
268
protected XMLParserConfiguration fXIncludeChildConfig;
269     protected XMLParserConfiguration fXPointerChildConfig;
270     
271     // The XPointerProcessor
272
protected XPointerProcessor fXPtrProcessor = null;
273
274     protected XMLLocator fDocLocation;
275     protected XIncludeMessageFormatter fXIncludeMessageFormatter = new XIncludeMessageFormatter();
276     protected XIncludeNamespaceSupport fNamespaceContext;
277     protected SymbolTable fSymbolTable;
278     protected XMLErrorReporter fErrorReporter;
279     protected XMLEntityResolver fEntityResolver;
280     protected SecurityManager JavaDoc fSecurityManager;
281     
282     // these are needed for text include processing
283
protected XIncludeTextReader fXInclude10TextReader;
284     protected XIncludeTextReader fXInclude11TextReader;
285
286     // these are needed for XML Base processing
287
protected XMLResourceIdentifier fCurrentBaseURI;
288     protected IntStack fBaseURIScope;
289     protected Stack JavaDoc fBaseURI;
290     protected Stack JavaDoc fLiteralSystemID;
291     protected Stack JavaDoc fExpandedSystemID;
292     
293     // these are needed for Language Fixup
294
protected IntStack fLanguageScope;
295     protected Stack JavaDoc fLanguageStack;
296     protected String JavaDoc fCurrentLanguage;
297
298     // used for passing features on to child XIncludeHandler objects
299
protected ParserConfigurationSettings fSettings;
300
301     // The current element depth. We start at depth 0 (before we've reached any elements).
302
// The first element is at depth 1.
303
private int fDepth;
304     
305     // The current element depth of the result infoset.
306
private int fResultDepth;
307
308     // this value must be at least 1
309
private static final int INITIAL_SIZE = 8;
310
311     // Used to ensure that fallbacks are always children of include elements,
312
// and that include elements are never children of other include elements.
313
// An index contains true if the ancestor of the current element which resides
314
// at that depth was an include element.
315
private boolean[] fSawInclude = new boolean[INITIAL_SIZE];
316
317     // Ensures that only one fallback element can be at a single depth.
318
// An index contains true if we have seen any fallback elements at that depth,
319
// and it is only reset to false when the end tag of the parent is encountered.
320
private boolean[] fSawFallback = new boolean[INITIAL_SIZE];
321
322     // The state of the processor at each given depth.
323
private int[] fState = new int[INITIAL_SIZE];
324
325     // buffering the necessary DTD events
326
private ArrayList JavaDoc fNotations;
327     private ArrayList JavaDoc fUnparsedEntities;
328     
329     // flags which control whether base URI or language fixup is performed.
330
private boolean fFixupBaseURIs = true;
331     private boolean fFixupLanguage = true;
332
333     // for SAX compatibility.
334
// Has the value of the ALLOW_UE_AND_NOTATION_EVENTS feature
335
private boolean fSendUEAndNotationEvents;
336
337     // track the version of the document being parsed
338
private boolean fIsXML11;
339
340     // track whether a DTD is being parsed
341
private boolean fInDTD;
342     
343     // track whether the root element of the result infoset has been processed
344
private boolean fSeenRootElement;
345     
346     // track whether the child config needs its features refreshed
347
private boolean fNeedCopyFeatures = true;
348
349     // Constructors
350

351     public XIncludeHandler() {
352         fDepth = 0;
353
354         fSawFallback[fDepth] = false;
355         fSawInclude[fDepth] = false;
356         fState[fDepth] = STATE_NORMAL_PROCESSING;
357         fNotations = new ArrayList JavaDoc();
358         fUnparsedEntities = new ArrayList JavaDoc();
359
360         fBaseURIScope = new IntStack();
361         fBaseURI = new Stack JavaDoc();
362         fLiteralSystemID = new Stack JavaDoc();
363         fExpandedSystemID = new Stack JavaDoc();
364         fCurrentBaseURI = new XMLResourceIdentifierImpl();
365         
366         fLanguageScope = new IntStack();
367         fLanguageStack = new Stack JavaDoc();
368         fCurrentLanguage = null;
369     }
370
371     // XMLComponent methods
372

373     public void reset(XMLComponentManager componentManager)
374         throws XNIException {
375         fNamespaceContext = null;
376         fDepth = 0;
377         fResultDepth = isRootDocument() ? 0 : fParentXIncludeHandler.getResultDepth();
378         fNotations.clear();
379         fUnparsedEntities.clear();
380         fParentRelativeURI = null;
381         fIsXML11 = false;
382         fInDTD = false;
383         fSeenRootElement = false;
384
385         fBaseURIScope.clear();
386         fBaseURI.clear();
387         fLiteralSystemID.clear();
388         fExpandedSystemID.clear();
389         fLanguageScope.clear();
390         fLanguageStack.clear();
391
392         // REVISIT: Find a better method for maintaining
393
// the state of the XInclude processor. These arrays
394
// can potentially grow quite large. Cleaning them
395
// out on reset may be very time consuming. -- mrglavas
396
//
397
// clear the previous settings from the arrays
398
for (int i = 0; i < fState.length; ++i) {
399             fState[i] = STATE_NORMAL_PROCESSING;
400         }
401         for (int i = 0; i < fSawFallback.length; ++i) {
402             fSawFallback[i] = false;
403         }
404         for (int i = 0; i < fSawInclude.length; ++i) {
405             fSawInclude[i] = false;
406         }
407         
408         try {
409             if (!componentManager.getFeature(PARSER_SETTINGS)) {
410                 // if parser settings have not changed return.
411
return;
412             }
413         }
414         catch (XMLConfigurationException e) {}
415         
416         // parser settings changed. Need to refresh features on child config.
417
fNeedCopyFeatures = true;
418
419         try {
420             fSendUEAndNotationEvents =
421                 componentManager.getFeature(ALLOW_UE_AND_NOTATION_EVENTS);
422             if (fChildConfig != null) {
423                 fChildConfig.setFeature(
424                     ALLOW_UE_AND_NOTATION_EVENTS,
425                     fSendUEAndNotationEvents);
426             }
427         }
428         catch (XMLConfigurationException e) {
429         }
430         
431         try {
432             fFixupBaseURIs =
433                 componentManager.getFeature(XINCLUDE_FIXUP_BASE_URIS);
434             if (fChildConfig != null) {
435                 fChildConfig.setFeature(
436                     XINCLUDE_FIXUP_BASE_URIS,
437                     fFixupBaseURIs);
438             }
439         }
440         catch (XMLConfigurationException e) {
441             fFixupBaseURIs = true;
442         }
443         
444         try {
445             fFixupLanguage =
446                 componentManager.getFeature(XINCLUDE_FIXUP_LANGUAGE);
447             if (fChildConfig != null) {
448                 fChildConfig.setFeature(
449                     XINCLUDE_FIXUP_LANGUAGE,
450                     fFixupLanguage);
451             }
452         }
453         catch (XMLConfigurationException e) {
454             fFixupLanguage = true;
455         }
456         
457         // Get symbol table.
458
try {
459             SymbolTable value =
460                 (SymbolTable)componentManager.getProperty(SYMBOL_TABLE);
461             if (value != null) {
462                 fSymbolTable = value;
463                 if (fChildConfig != null) {
464                     fChildConfig.setProperty(SYMBOL_TABLE, value);
465                 }
466             }
467         }
468         catch (XMLConfigurationException e) {
469             fSymbolTable = null;
470         }
471
472         // Get error reporter.
473
try {
474             XMLErrorReporter value =
475                 (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER);
476             if (value != null) {
477                 setErrorReporter(value);
478                 if (fChildConfig != null) {
479                     fChildConfig.setProperty(ERROR_REPORTER, value);
480                 }
481             }
482         }
483         catch (XMLConfigurationException e) {
484             fErrorReporter = null;
485         }
486
487         // Get entity resolver.
488
try {
489             XMLEntityResolver value =
490                 (XMLEntityResolver)componentManager.getProperty(
491                     ENTITY_RESOLVER);
492
493             if (value != null) {
494                 fEntityResolver = value;
495                 if (fChildConfig != null) {
496                     fChildConfig.setProperty(ENTITY_RESOLVER, value);
497                 }
498             }
499         }
500         catch (XMLConfigurationException e) {
501             fEntityResolver = null;
502         }
503
504         // Get security manager.
505
try {
506             SecurityManager JavaDoc value =
507                 (SecurityManager JavaDoc)componentManager.getProperty(
508                     SECURITY_MANAGER);
509
510             if (value != null) {
511                 fSecurityManager = value;
512                 if (fChildConfig != null) {
513                     fChildConfig.setProperty(SECURITY_MANAGER, value);
514                 }
515             }
516         }
517         catch (XMLConfigurationException e) {
518             fSecurityManager = null;
519         }
520         
521         // Get buffer size.
522
try {
523             Integer JavaDoc value =
524                 (Integer JavaDoc)componentManager.getProperty(
525                     BUFFER_SIZE);
526
527             if (value != null && value.intValue() > 0) {
528                 fBufferSize = value.intValue();
529                 if (fChildConfig != null) {
530                     fChildConfig.setProperty(BUFFER_SIZE, value);
531                 }
532             }
533             else {
534                 fBufferSize = ((Integer JavaDoc)getPropertyDefault(BUFFER_SIZE)).intValue();
535             }
536         }
537         catch (XMLConfigurationException e) {
538             fBufferSize = ((Integer JavaDoc)getPropertyDefault(BUFFER_SIZE)).intValue();
539         }
540         
541         // Reset XML 1.0 text reader.
542
if (fXInclude10TextReader != null) {
543             fXInclude10TextReader.setBufferSize(fBufferSize);
544         }
545         // Reset XML 1.1 text reader.
546
if (fXInclude11TextReader != null) {
547             fXInclude11TextReader.setBufferSize(fBufferSize);
548         }
549
550         fSettings = new ParserConfigurationSettings();
551         copyFeatures(componentManager, fSettings);
552         
553         // We don't want a schema validator on the new pipeline,
554
// so if it was enabled, we set the feature to false. If
555
// the validation feature was also enabled we turn on
556
// dynamic validation, so that DTD validation is performed
557
// on the included documents only if they have a DOCTYPE.
558
// This is consistent with the behaviour on the main pipeline.
559
try {
560             if (componentManager.getFeature(SCHEMA_VALIDATION)) {
561                 fSettings.setFeature(SCHEMA_VALIDATION, false);
562                 if (componentManager.getFeature(VALIDATION)) {
563                     fSettings.setFeature(DYNAMIC_VALIDATION, true);
564                 }
565             }
566         }
567         catch (XMLConfigurationException e) {}
568         
569         // Don't reset fChildConfig -- we don't want it to share the same components.
570
// It will be reset when it is actually used to parse something.
571
} // reset(XMLComponentManager)
572

573     /**
574      * Returns a list of feature identifiers that are recognized by
575      * this component. This method may return null if no features
576      * are recognized by this component.
577      */

578     public String JavaDoc[] getRecognizedFeatures() {
579         return (String JavaDoc[])(RECOGNIZED_FEATURES.clone());
580     } // getRecognizedFeatures():String[]
581

582     /**
583      * Sets the state of a feature. This method is called by the component
584      * manager any time after reset when a feature changes state.
585      * <p>
586      * <strong>Note:</strong> Components should silently ignore features
587      * that do not affect the operation of the component.
588      *
589      * @param featureId The feature identifier.
590      * @param state The state of the feature.
591      *
592      * @throws SAXNotRecognizedException The component should not throw
593      * this exception.
594      * @throws SAXNotSupportedException The component should not throw
595      * this exception.
596      */

597     public void setFeature(String JavaDoc featureId, boolean state)
598         throws XMLConfigurationException {
599         if (featureId.equals(ALLOW_UE_AND_NOTATION_EVENTS)) {
600             fSendUEAndNotationEvents = state;
601         }
602         if (fSettings != null) {
603             fNeedCopyFeatures = true;
604             fSettings.setFeature(featureId, state);
605         }
606     } // setFeature(String,boolean)
607

608     /**
609      * Returns a list of property identifiers that are recognized by
610      * this component. This method may return null if no properties
611      * are recognized by this component.
612      */

613     public String JavaDoc[] getRecognizedProperties() {
614         return (String JavaDoc[])(RECOGNIZED_PROPERTIES.clone());
615     } // getRecognizedProperties():String[]
616

617     /**
618      * Sets the value of a property. This method is called by the component
619      * manager any time after reset when a property changes value.
620      * <p>
621      * <strong>Note:</strong> Components should silently ignore properties
622      * that do not affect the operation of the component.
623      *
624      * @param propertyId The property identifier.
625      * @param value The value of the property.
626      *
627      * @throws SAXNotRecognizedException The component should not throw
628      * this exception.
629      * @throws SAXNotSupportedException The component should not throw
630      * this exception.
631      */

632     public void setProperty(String JavaDoc propertyId, Object JavaDoc value)
633         throws XMLConfigurationException {
634         if (propertyId.equals(SYMBOL_TABLE)) {
635             fSymbolTable = (SymbolTable)value;
636             if (fChildConfig != null) {
637                 fChildConfig.setProperty(propertyId, value);
638             }
639             return;
640         }
641         if (propertyId.equals(ERROR_REPORTER)) {
642             setErrorReporter((XMLErrorReporter)value);
643             if (fChildConfig != null) {
644                 fChildConfig.setProperty(propertyId, value);
645             }
646             return;
647         }
648         if (propertyId.equals(ENTITY_RESOLVER)) {
649             fEntityResolver = (XMLEntityResolver)value;
650             if (fChildConfig != null) {
651                 fChildConfig.setProperty(propertyId, value);
652             }
653             return;
654         }
655         if (propertyId.equals(SECURITY_MANAGER)) {
656             fSecurityManager = (SecurityManager JavaDoc)value;
657             if (fChildConfig != null) {
658                 fChildConfig.setProperty(propertyId, value);
659             }
660             return;
661         }
662         if (propertyId.equals(BUFFER_SIZE)) {
663             Integer JavaDoc bufferSize = (Integer JavaDoc) value;
664             if (fChildConfig != null) {
665                 fChildConfig.setProperty(propertyId, value);
666             }
667             if (bufferSize != null && bufferSize.intValue() > 0) {
668                 fBufferSize = bufferSize.intValue();
669                 // Reset XML 1.0 text reader.
670
if (fXInclude10TextReader != null) {
671                     fXInclude10TextReader.setBufferSize(fBufferSize);
672                 }
673                 // Reset XML 1.1 text reader.
674
if (fXInclude11TextReader != null) {
675                     fXInclude11TextReader.setBufferSize(fBufferSize);
676                 }
677             }
678             return;
679         }
680
681     } // setProperty(String,Object)
682

683     /**
684      * Returns the default state for a feature, or null if this
685      * component does not want to report a default value for this
686      * feature.
687      *
688      * @param featureId The feature identifier.
689      *
690      * @since Xerces 2.2.0
691      */

692     public Boolean JavaDoc getFeatureDefault(String JavaDoc featureId) {
693         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
694             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
695                 return FEATURE_DEFAULTS[i];
696             }
697         }
698         return null;
699     } // getFeatureDefault(String):Boolean
700

701     /**
702      * Returns the default state for a property, or null if this
703      * component does not want to report a default value for this
704      * property.
705      *
706      * @param propertyId The property identifier.
707      *
708      * @since Xerces 2.2.0
709      */

710     public Object JavaDoc getPropertyDefault(String JavaDoc propertyId) {
711         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
712             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
713                 return PROPERTY_DEFAULTS[i];
714             }
715         }
716         return null;
717     } // getPropertyDefault(String):Object
718

719     public void setDocumentHandler(XMLDocumentHandler handler) {
720         fDocumentHandler = handler;
721     }
722
723     public XMLDocumentHandler getDocumentHandler() {
724         return fDocumentHandler;
725     }
726
727     // XMLDocumentHandler methods
728

729     /**
730      * Event sent at the start of the document.
731      *
732      * A fatal error will occur here, if it is detected that this document has been processed
733      * before.
734      *
735      * This event is only passed on to the document handler if this is the root document.
736      */

737     public void startDocument(
738         XMLLocator locator,
739         String JavaDoc encoding,
740         NamespaceContext namespaceContext,
741         Augmentations augs)
742         throws XNIException {
743
744         // we do this to ensure that the proper location is reported in errors
745
// otherwise, the locator from the root document would always be used
746
fErrorReporter.setDocumentLocator(locator);
747
748         if (!isRootDocument()
749             && fParentXIncludeHandler.searchForRecursiveIncludes(locator)) {
750             reportFatalError(
751                 "RecursiveInclude",
752                 new Object JavaDoc[] { locator.getExpandedSystemId()});
753         }
754
755         if (!(namespaceContext instanceof XIncludeNamespaceSupport)) {
756             reportFatalError("IncompatibleNamespaceContext");
757         }
758         fNamespaceContext = (XIncludeNamespaceSupport)namespaceContext;
759         fDocLocation = locator;
760
761         // initialize the current base URI
762
fCurrentBaseURI.setBaseSystemId(locator.getBaseSystemId());
763         fCurrentBaseURI.setExpandedSystemId(locator.getExpandedSystemId());
764         fCurrentBaseURI.setLiteralSystemId(locator.getLiteralSystemId());
765         saveBaseURI();
766         if (augs == null) {
767             augs = new AugmentationsImpl();
768         }
769         augs.putItem(CURRENT_BASE_URI, fCurrentBaseURI);
770         
771         // initialize the current language
772
fCurrentLanguage = XMLSymbols.EMPTY_STRING;
773         saveLanguage(fCurrentLanguage);
774
775         if (isRootDocument() && fDocumentHandler != null) {
776             fDocumentHandler.startDocument(
777                 locator,
778                 encoding,
779                 namespaceContext,
780                 augs);
781         }
782     }
783
784     public void xmlDecl(
785         String JavaDoc version,
786         String JavaDoc encoding,
787         String JavaDoc standalone,
788         Augmentations augs)
789         throws XNIException {
790         fIsXML11 = "1.1".equals(version);
791         if (isRootDocument() && fDocumentHandler != null) {
792             fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
793         }
794     }
795
796     public void doctypeDecl(
797         String JavaDoc rootElement,
798         String JavaDoc publicId,
799         String JavaDoc systemId,
800         Augmentations augs)
801         throws XNIException {
802         if (isRootDocument() && fDocumentHandler != null) {
803             fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs);
804         }
805     }
806
807     public void comment(XMLString text, Augmentations augs)
808         throws XNIException {
809         if (!fInDTD) {
810             if (fDocumentHandler != null
811                 && getState() == STATE_NORMAL_PROCESSING) {
812                 fDepth++;
813                 augs = modifyAugmentations(augs);
814                 fDocumentHandler.comment(text, augs);
815                 fDepth--;
816             }
817         }
818         else if (fDTDHandler != null) {
819             fDTDHandler.comment(text, augs);
820         }
821     }
822
823     public void processingInstruction(
824         String JavaDoc target,
825         XMLString data,
826         Augmentations augs)
827         throws XNIException {
828         if (!fInDTD) {
829             if (fDocumentHandler != null
830                 && getState() == STATE_NORMAL_PROCESSING) {
831                 // we need to change the depth like this so that modifyAugmentations() works
832
fDepth++;
833                 augs = modifyAugmentations(augs);
834                 fDocumentHandler.processingInstruction(target, data, augs);
835                 fDepth--;
836             }
837         }
838         else if (fDTDHandler != null) {
839             fDTDHandler.processingInstruction(target, data, augs);
840         }
841     }
842
843     public void startElement(
844         QName element,
845         XMLAttributes attributes,
846         Augmentations augs)
847         throws XNIException {
848         fDepth++;
849         int lastState = getState(fDepth - 1);
850         // If the last two states were fallback then this must be a descendant of an include
851
// child which isn't a fallback. The specification says we should ignore such elements
852
// and their children.
853
if (lastState == STATE_EXPECT_FALLBACK && getState(fDepth - 2) == STATE_EXPECT_FALLBACK) {
854             setState(STATE_IGNORE);
855         }
856         else {
857             setState(lastState);
858         }
859
860         // we process the xml:base and xml:lang attributes regardless
861
// of what type of element it is.
862
processXMLBaseAttributes(attributes);
863         if (fFixupLanguage) {
864             processXMLLangAttributes(attributes);
865         }
866
867         if (isIncludeElement(element)) {
868             boolean success = this.handleIncludeElement(attributes);
869             if (success) {
870                 setState(STATE_IGNORE);
871             }
872             else {
873                 setState(STATE_EXPECT_FALLBACK);
874             }
875         }
876         else if (isFallbackElement(element)) {
877             this.handleFallbackElement();
878         }
879         else if (hasXIncludeNamespace(element)) {
880             if (getSawInclude(fDepth - 1)) {
881                 reportFatalError(
882                     "IncludeChild",
883                     new Object JavaDoc[] { element.rawname });
884             }
885             if (getSawFallback(fDepth - 1)) {
886                 reportFatalError(
887                     "FallbackChild",
888                     new Object JavaDoc[] { element.rawname });
889             }
890             if (getState() == STATE_NORMAL_PROCESSING) {
891                 if (fResultDepth++ == 0) {
892                     checkMultipleRootElements();
893                 }
894                 if (fDocumentHandler != null) {
895                     augs = modifyAugmentations(augs);
896                     attributes = processAttributes(attributes);
897                     fDocumentHandler.startElement(element, attributes, augs);
898                 }
899             }
900         }
901         else if (getState() == STATE_NORMAL_PROCESSING) {
902             if (fResultDepth++ == 0) {
903                 checkMultipleRootElements();
904             }
905             if (fDocumentHandler != null) {
906                 augs = modifyAugmentations(augs);
907                 attributes = processAttributes(attributes);
908                 fDocumentHandler.startElement(element, attributes, augs);
909             }
910         }
911     }
912
913     public void emptyElement(
914         QName element,
915         XMLAttributes attributes,
916         Augmentations augs)
917         throws XNIException {
918         fDepth++;
919         int lastState = getState(fDepth - 1);
920         // If the last two states were fallback then this must be a descendant of an include
921
// child which isn't a fallback. The specification says we should ignore such elements
922
// and their children.
923
if (lastState == STATE_EXPECT_FALLBACK && getState(fDepth - 2) == STATE_EXPECT_FALLBACK) {
924             setState(STATE_IGNORE);
925         }
926         else {
927             setState(lastState);
928         }
929
930         // we process the xml:base and xml:lang attributes regardless
931
// of what type of element it is.
932
processXMLBaseAttributes(attributes);
933         if (fFixupLanguage) {
934             processXMLLangAttributes(attributes);
935         }
936
937         if (isIncludeElement(element)) {
938             boolean success = this.handleIncludeElement(attributes);
939             if (success) {
940                 setState(STATE_IGNORE);
941             }
942             else {
943                 reportFatalError("NoFallback");
944             }
945         }
946         else if (isFallbackElement(element)) {
947             this.handleFallbackElement();
948         }
949         else if (hasXIncludeNamespace(element)) {
950             if (getSawInclude(fDepth - 1)) {
951                 reportFatalError(
952                     "IncludeChild",
953                     new Object JavaDoc[] { element.rawname });
954             }
955             if (getSawFallback(fDepth - 1)) {
956                 reportFatalError(
957                     "FallbackChild",
958                     new Object JavaDoc[] { element.rawname });
959             }
960             if (getState() == STATE_NORMAL_PROCESSING) {
961                 if (fResultDepth == 0) {
962                     checkMultipleRootElements();
963                 }
964                 if (fDocumentHandler != null) {
965                     augs = modifyAugmentations(augs);
966                     attributes = processAttributes(attributes);
967                     fDocumentHandler.emptyElement(element, attributes, augs);
968                 }
969             }
970         }
971         else if (getState() == STATE_NORMAL_PROCESSING) {
972             if (fResultDepth == 0) {
973                 checkMultipleRootElements();
974             }
975             if (fDocumentHandler != null) {
976                 augs = modifyAugmentations(augs);
977                 attributes = processAttributes(attributes);
978                 fDocumentHandler.emptyElement(element, attributes, augs);
979             }
980         }
981         // reset the out of scope stack elements
982
setSawFallback(fDepth + 1, false);
983         setSawInclude(fDepth, false);
984
985         // check if an xml:base has gone out of scope
986
if (fBaseURIScope.size() > 0 && fDepth == fBaseURIScope.peek()) {
987             // pop the values from the stack
988
restoreBaseURI();
989         }
990         fDepth--;
991     }
992
993     public void endElement(QName element, Augmentations augs)
994         throws XNIException {
995
996         if (isIncludeElement(element)) {
997             // if we're ending an include element, and we were expecting a fallback
998
// we check to see if the children of this include element contained a fallback
999
if (getState() == STATE_EXPECT_FALLBACK
1000                && !getSawFallback(fDepth + 1)) {
1001                reportFatalError("NoFallback");
1002            }
1003        }
1004        if (isFallbackElement(element)) {
1005            // the state would have been set to normal processing if we were expecting the fallback element
1006
// now that we're done processing it, we should ignore all the other children of the include element
1007
if (getState() == STATE_NORMAL_PROCESSING) {
1008                setState(STATE_IGNORE);
1009            }
1010        }
1011        else if (getState() == STATE_NORMAL_PROCESSING) {
1012            --fResultDepth;
1013            if (fDocumentHandler != null) {
1014                fDocumentHandler.endElement(element, augs);
1015            }
1016        }
1017
1018        // reset the out of scope stack elements
1019
setSawFallback(fDepth + 1, false);
1020        setSawInclude(fDepth, false);
1021
1022        // check if an xml:base has gone out of scope
1023
if (fBaseURIScope.size() > 0 && fDepth == fBaseURIScope.peek()) {
1024            // pop the values from the stack
1025
restoreBaseURI();
1026        }
1027        
1028        // check if an xml:lang has gone out of scope
1029
if (fLanguageScope.size() > 0 && fDepth == fLanguageScope.peek()) {
1030            // pop the language from the stack
1031
fCurrentLanguage = restoreLanguage();
1032        }
1033        
1034        fDepth--;
1035    }
1036
1037    public void startGeneralEntity(
1038        String JavaDoc name,
1039        XMLResourceIdentifier resId,
1040        String JavaDoc encoding,
1041        Augmentations augs)
1042        throws XNIException {
1043        if (getState() == STATE_NORMAL_PROCESSING) {
1044            if (fResultDepth == 0) {
1045                if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
1046                    reportFatalError("UnexpandedEntityReferenceIllegal");
1047                }
1048            }
1049            else if (fDocumentHandler != null) {
1050                fDocumentHandler.startGeneralEntity(name, resId, encoding, augs);
1051            }
1052        }
1053    }
1054
1055    public void textDecl(String JavaDoc version, String JavaDoc encoding, Augmentations augs)
1056        throws XNIException {
1057        if (fDocumentHandler != null
1058            && getState() == STATE_NORMAL_PROCESSING) {
1059            fDocumentHandler.textDecl(version, encoding, augs);
1060        }
1061    }
1062
1063    public void endGeneralEntity(String JavaDoc name, Augmentations augs)
1064        throws XNIException {
1065        if (fDocumentHandler != null
1066            && getState() == STATE_NORMAL_PROCESSING
1067            && fResultDepth != 0) {
1068            fDocumentHandler.endGeneralEntity(name, augs);
1069        }
1070    }
1071
1072    public void characters(XMLString text, Augmentations augs)
1073        throws XNIException {
1074        if (getState() == STATE_NORMAL_PROCESSING) {
1075            if (fResultDepth == 0) {
1076                checkWhitespace(text);
1077            }
1078            else if (fDocumentHandler != null) {
1079                // we need to change the depth like this so that modifyAugmentations() works
1080
fDepth++;
1081                augs = modifyAugmentations(augs);
1082                fDocumentHandler.characters(text, augs);
1083                fDepth--;
1084            }
1085        }
1086    }
1087
1088    public void ignorableWhitespace(XMLString text, Augmentations augs)
1089        throws XNIException {
1090        if (fDocumentHandler != null
1091            && getState() == STATE_NORMAL_PROCESSING
1092            && fResultDepth != 0) {
1093            fDocumentHandler.ignorableWhitespace(text, augs);
1094        }
1095    }
1096
1097    public void startCDATA(Augmentations augs) throws XNIException {
1098        if (fDocumentHandler != null
1099            && getState() == STATE_NORMAL_PROCESSING
1100            && fResultDepth != 0) {
1101            fDocumentHandler.startCDATA(augs);
1102        }
1103    }
1104
1105    public void endCDATA(Augmentations augs) throws XNIException {
1106        if (fDocumentHandler != null
1107            && getState() == STATE_NORMAL_PROCESSING
1108            && fResultDepth != 0) {
1109            fDocumentHandler.endCDATA(augs);
1110        }
1111    }
1112
1113    public void endDocument(Augmentations augs) throws XNIException {
1114        if (isRootDocument()) {
1115            if (!fSeenRootElement) {
1116                reportFatalError("RootElementRequired");
1117            }
1118            if (fDocumentHandler != null) {
1119                fDocumentHandler.endDocument(augs);
1120            }
1121        }
1122    }
1123
1124    public void setDocumentSource(XMLDocumentSource source) {
1125        fDocumentSource = source;
1126    }
1127
1128    public XMLDocumentSource getDocumentSource() {
1129        return fDocumentSource;
1130    }
1131
1132    // DTDHandler methods
1133
// We are only interested in the notation and unparsed entity declarations,
1134
// the rest we just pass on
1135

1136    /* (non-Javadoc)
1137     * @see org.apache.xerces.xni.XMLDTDHandler#attributeDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, org.apache.xerces.xni.XMLString, org.apache.xerces.xni.XMLString, org.apache.xerces.xni.Augmentations)
1138     */

1139    public void attributeDecl(
1140        String JavaDoc elementName,
1141        String JavaDoc attributeName,
1142        String JavaDoc type,
1143        String JavaDoc[] enumeration,
1144        String JavaDoc defaultType,
1145        XMLString defaultValue,
1146        XMLString nonNormalizedDefaultValue,
1147        Augmentations augmentations)
1148        throws XNIException {
1149        if (fDTDHandler != null) {
1150            fDTDHandler.attributeDecl(
1151                elementName,
1152                attributeName,
1153                type,
1154                enumeration,
1155                defaultType,
1156                defaultValue,
1157                nonNormalizedDefaultValue,
1158                augmentations);
1159        }
1160    }
1161
1162    /* (non-Javadoc)
1163     * @see org.apache.xerces.xni.XMLDTDHandler#elementDecl(java.lang.String, java.lang.String, org.apache.xerces.xni.Augmentations)
1164     */

1165    public void elementDecl(
1166        String JavaDoc name,
1167        String JavaDoc contentModel,
1168        Augmentations augmentations)
1169        throws XNIException {
1170        if (fDTDHandler != null) {
1171            fDTDHandler.elementDecl(name, contentModel, augmentations);
1172        }
1173    }
1174
1175    /* (non-Javadoc)
1176     * @see org.apache.xerces.xni.XMLDTDHandler#endAttlist(org.apache.xerces.xni.Augmentations)
1177     */

1178    public void endAttlist(Augmentations augmentations) throws XNIException {
1179        if (fDTDHandler != null) {
1180            fDTDHandler.endAttlist(augmentations);
1181        }
1182    }
1183
1184    /* (non-Javadoc)
1185     * @see org.apache.xerces.xni.XMLDTDHandler#endConditional(org.apache.xerces.xni.Augmentations)
1186     */

1187    public void endConditional(Augmentations augmentations)
1188        throws XNIException {
1189        if (fDTDHandler != null) {
1190            fDTDHandler.endConditional(augmentations);
1191        }
1192    }
1193
1194    /* (non-Javadoc)
1195     * @see org.apache.xerces.xni.XMLDTDHandler#endDTD(org.apache.xerces.xni.Augmentations)
1196     */

1197    public void endDTD(Augmentations augmentations) throws XNIException {
1198        if (fDTDHandler != null) {
1199            fDTDHandler.endDTD(augmentations);
1200        }
1201        fInDTD = false;
1202    }
1203
1204    /* (non-Javadoc)
1205     * @see org.apache.xerces.xni.XMLDTDHandler#endExternalSubset(org.apache.xerces.xni.Augmentations)
1206     */

1207    public void endExternalSubset(Augmentations augmentations)
1208        throws XNIException {
1209        if (fDTDHandler != null) {
1210            fDTDHandler.endExternalSubset(augmentations);
1211        }
1212    }
1213
1214    /* (non-Javadoc)
1215     * @see org.apache.xerces.xni.XMLDTDHandler#endParameterEntity(java.lang.String, org.apache.xerces.xni.Augmentations)
1216     */

1217    public void endParameterEntity(String JavaDoc name, Augmentations augmentations)
1218        throws XNIException {
1219        if (fDTDHandler != null) {
1220            fDTDHandler.endParameterEntity(name, augmentations);
1221        }
1222    }
1223
1224    /* (non-Javadoc)
1225     * @see org.apache.xerces.xni.XMLDTDHandler#externalEntityDecl(java.lang.String, org.apache.xerces.xni.XMLResourceIdentifier, org.apache.xerces.xni.Augmentations)
1226     */

1227    public void externalEntityDecl(
1228        String JavaDoc name,
1229        XMLResourceIdentifier identifier,
1230        Augmentations augmentations)
1231        throws XNIException {
1232        if (fDTDHandler != null) {
1233            fDTDHandler.externalEntityDecl(name, identifier, augmentations);
1234        }
1235    }
1236
1237    /* (non-Javadoc)
1238     * @see org.apache.xerces.xni.XMLDTDHandler#getDTDSource()
1239     */

1240    public XMLDTDSource getDTDSource() {
1241        return fDTDSource;
1242    }
1243
1244    /* (non-Javadoc)
1245     * @see org.apache.xerces.xni.XMLDTDHandler#ignoredCharacters(org.apache.xerces.xni.XMLString, org.apache.xerces.xni.Augmentations)
1246     */

1247    public void ignoredCharacters(XMLString text, Augmentations augmentations)
1248        throws XNIException {
1249        if (fDTDHandler != null) {
1250            fDTDHandler.ignoredCharacters(text, augmentations);
1251        }
1252    }
1253
1254    /* (non-Javadoc)
1255     * @see org.apache.xerces.xni.XMLDTDHandler#internalEntityDecl(java.lang.String, org.apache.xerces.xni.XMLString, org.apache.xerces.xni.XMLString, org.apache.xerces.xni.Augmentations)
1256     */

1257    public void internalEntityDecl(
1258        String JavaDoc name,
1259        XMLString text,
1260        XMLString nonNormalizedText,
1261        Augmentations augmentations)
1262        throws XNIException {
1263        if (fDTDHandler != null) {
1264            fDTDHandler.internalEntityDecl(
1265                name,
1266                text,
1267                nonNormalizedText,
1268                augmentations);
1269        }
1270    }
1271
1272    /* (non-Javadoc)
1273     * @see org.apache.xerces.xni.XMLDTDHandler#notationDecl(java.lang.String, org.apache.xerces.xni.XMLResourceIdentifier, org.apache.xerces.xni.Augmentations)
1274     */

1275    public void notationDecl(
1276        String JavaDoc name,
1277        XMLResourceIdentifier identifier,
1278        Augmentations augmentations)
1279        throws XNIException {
1280        this.addNotation(name, identifier, augmentations);
1281        if (fDTDHandler != null) {
1282            fDTDHandler.notationDecl(name, identifier, augmentations);
1283        }
1284    }
1285
1286    /* (non-Javadoc)
1287     * @see org.apache.xerces.xni.XMLDTDHandler#setDTDSource(org.apache.xerces.xni.parser.XMLDTDSource)
1288     */

1289    public void setDTDSource(XMLDTDSource source) {
1290        fDTDSource = source;
1291    }
1292
1293    /* (non-Javadoc)
1294     * @see org.apache.xerces.xni.XMLDTDHandler#startAttlist(java.lang.String, org.apache.xerces.xni.Augmentations)
1295     */

1296    public void startAttlist(String JavaDoc elementName, Augmentations augmentations)
1297        throws XNIException {
1298        if (fDTDHandler != null) {
1299            fDTDHandler.startAttlist(elementName, augmentations);
1300        }
1301    }
1302
1303    /* (non-Javadoc)
1304     * @see org.apache.xerces.xni.XMLDTDHandler#startConditional(short, org.apache.xerces.xni.Augmentations)
1305     */

1306    public void startConditional(short type, Augmentations augmentations)
1307        throws XNIException {
1308        if (fDTDHandler != null) {
1309            fDTDHandler.startConditional(type, augmentations);
1310        }
1311    }
1312
1313    /* (non-Javadoc)
1314     * @see org.apache.xerces.xni.XMLDTDHandler#startDTD(org.apache.xerces.xni.XMLLocator, org.apache.xerces.xni.Augmentations)
1315     */

1316    public void startDTD(XMLLocator locator, Augmentations augmentations)
1317        throws XNIException {
1318        fInDTD = true;
1319        if (fDTDHandler != null) {
1320            fDTDHandler.startDTD(locator, augmentations);
1321        }
1322    }
1323
1324    /* (non-Javadoc)
1325     * @see org.apache.xerces.xni.XMLDTDHandler#startExternalSubset(org.apache.xerces.xni.XMLResourceIdentifier, org.apache.xerces.xni.Augmentations)
1326     */

1327    public void startExternalSubset(
1328        XMLResourceIdentifier identifier,
1329        Augmentations augmentations)
1330        throws XNIException {
1331        if (fDTDHandler != null) {
1332            fDTDHandler.startExternalSubset(identifier, augmentations);
1333        }
1334    }
1335
1336    /* (non-Javadoc)
1337     * @see org.apache.xerces.xni.XMLDTDHandler#startParameterEntity(java.lang.String, org.apache.xerces.xni.XMLResourceIdentifier, java.lang.String, org.apache.xerces.xni.Augmentations)
1338     */

1339    public void startParameterEntity(
1340        String JavaDoc name,
1341        XMLResourceIdentifier identifier,
1342        String JavaDoc encoding,
1343        Augmentations augmentations)
1344        throws XNIException {
1345        if (fDTDHandler != null) {
1346            fDTDHandler.startParameterEntity(
1347                name,
1348                identifier,
1349                encoding,
1350                augmentations);
1351        }
1352    }
1353
1354    /* (non-Javadoc)
1355     * @see org.apache.xerces.xni.XMLDTDHandler#unparsedEntityDecl(java.lang.String, org.apache.xerces.xni.XMLResourceIdentifier, java.lang.String, org.apache.xerces.xni.Augmentations)
1356     */

1357    public void unparsedEntityDecl(
1358        String JavaDoc name,
1359        XMLResourceIdentifier identifier,
1360        String JavaDoc notation,
1361        Augmentations augmentations)
1362        throws XNIException {
1363        this.addUnparsedEntity(name, identifier, notation, augmentations);
1364        if (fDTDHandler != null) {
1365            fDTDHandler.unparsedEntityDecl(
1366                name,
1367                identifier,
1368                notation,
1369                augmentations);
1370        }
1371    }
1372
1373    /* (non-Javadoc)
1374     * @see org.apache.xerces.xni.parser.XMLDTDSource#getDTDHandler()
1375     */

1376    public XMLDTDHandler getDTDHandler() {
1377        return fDTDHandler;
1378    }
1379
1380    /* (non-Javadoc)
1381     * @see org.apache.xerces.xni.parser.XMLDTDSource#setDTDHandler(org.apache.xerces.xni.XMLDTDHandler)
1382     */

1383    public void setDTDHandler(XMLDTDHandler handler) {
1384        fDTDHandler = handler;
1385    }
1386
1387    // XIncludeHandler methods
1388

1389    private void setErrorReporter(XMLErrorReporter reporter) {
1390        fErrorReporter = reporter;
1391        if (fErrorReporter != null) {
1392            fErrorReporter.putMessageFormatter(
1393                XIncludeMessageFormatter.XINCLUDE_DOMAIN, fXIncludeMessageFormatter);
1394            // this ensures the proper location is displayed in error messages
1395
if (fDocLocation != null) {
1396                fErrorReporter.setDocumentLocator(fDocLocation);
1397            }
1398        }
1399    }
1400
1401    protected void handleFallbackElement() {
1402        if (!getSawInclude(fDepth - 1)) {
1403            if (getState() == STATE_IGNORE) {
1404                return;
1405            }
1406            reportFatalError("FallbackParent");
1407        }
1408        
1409        setSawInclude(fDepth, false);
1410        fNamespaceContext.setContextInvalid();
1411
1412        if (getSawFallback(fDepth)) {
1413            reportFatalError("MultipleFallbacks");
1414        }
1415        else {
1416            setSawFallback(fDepth, true);
1417        }
1418
1419        // Either the state is STATE_EXPECT_FALLBACK or it's STATE_IGNORE.
1420
// If we're ignoring, we want to stay ignoring. But if we're expecting this fallback element,
1421
// we want to signal that we should process the children.
1422
if (getState() == STATE_EXPECT_FALLBACK) {
1423            setState(STATE_NORMAL_PROCESSING);
1424        }
1425    }
1426
1427    protected boolean handleIncludeElement(XMLAttributes attributes)
1428        throws XNIException {
1429        if (getSawInclude(fDepth - 1)) {
1430            reportFatalError("IncludeChild", new Object JavaDoc[] { XINCLUDE_INCLUDE });
1431        }
1432        if (getState() == STATE_IGNORE) {
1433            return true;
1434        }
1435        setSawInclude(fDepth, true);
1436        fNamespaceContext.setContextInvalid();
1437
1438        // TODO: does Java use IURIs by default?
1439
// [Definition: An internationalized URI reference, or IURI, is a URI reference that directly uses [Unicode] characters.]
1440
// TODO: figure out what section 4.1.1 of the XInclude spec is talking about
1441
// has to do with disallowed ASCII character escaping
1442
// this ties in with the above IURI section, but I suspect Java already does it
1443

1444        String JavaDoc href = attributes.getValue(XINCLUDE_ATTR_HREF);
1445        String JavaDoc parse = attributes.getValue(XINCLUDE_ATTR_PARSE);
1446        String JavaDoc xpointer = attributes.getValue(XPOINTER);
1447        String JavaDoc accept = attributes.getValue(XINCLUDE_ATTR_ACCEPT);
1448        String JavaDoc acceptLanguage = attributes.getValue(XINCLUDE_ATTR_ACCEPT_LANGUAGE);
1449        
1450        if (parse == null) {
1451            parse = XINCLUDE_PARSE_XML;
1452        }
1453        if (href == null) {
1454            href = XMLSymbols.EMPTY_STRING;
1455        }
1456        if (href.length() == 0 && XINCLUDE_PARSE_XML.equals(parse)) {
1457            if (xpointer == null) {
1458                reportFatalError("XpointerMissing");
1459            }
1460            else {
1461                // When parse="xml" and an xpointer is specified treat
1462
// all absences of the href attribute as a resource error.
1463
Locale JavaDoc locale = (fErrorReporter != null) ? fErrorReporter.getLocale() : null;
1464                String JavaDoc reason = fXIncludeMessageFormatter.formatMessage(locale, "XPointerStreamability", null);
1465                reportResourceError("XMLResourceError", new Object JavaDoc[] { href, reason });
1466                return false;
1467            }
1468        }
1469
1470        URI hrefURI = null;
1471        
1472        // Check whether href is correct and perform escaping as per section 4.1.1 of the XInclude spec.
1473
// Report fatal error if the href value contains a fragment identifier or if the value after
1474
// escaping is a syntactically invalid URI or IRI.
1475
try {
1476            hrefURI = new URI(href, true);
1477            if (hrefURI.getFragment() != null) {
1478                reportFatalError("HrefFragmentIdentifierIllegal", new Object JavaDoc[] {href});
1479            }
1480        }
1481        catch (URI.MalformedURIException exc) {
1482            String JavaDoc newHref = escapeHref(href);
1483            if (href != newHref) {
1484                href = newHref;
1485                try {
1486                    hrefURI = new URI(href, true);
1487                    if (hrefURI.getFragment() != null) {
1488                        reportFatalError("HrefFragmentIdentifierIllegal", new Object JavaDoc[] {href});
1489                    }
1490                }
1491                catch (URI.MalformedURIException exc2) {
1492                    reportFatalError("HrefSyntacticallyInvalid", new Object JavaDoc[] {href});
1493                }
1494            }
1495            else {
1496                reportFatalError("HrefSyntacticallyInvalid", new Object JavaDoc[] {href});
1497            }
1498        }
1499        
1500        // Verify that if an accept and/or an accept-language attribute exist
1501
// that the value(s) don't contain disallowed characters.
1502
if (accept != null && !isValidInHTTPHeader(accept)) {
1503            reportFatalError("AcceptMalformed", null);
1504            accept = null;
1505        }
1506        if (acceptLanguage != null && !isValidInHTTPHeader(acceptLanguage)) {
1507            reportFatalError("AcceptLanguageMalformed", null);
1508            acceptLanguage = null;
1509        }
1510
1511        XMLInputSource includedSource = null;
1512        if (fEntityResolver != null) {
1513            try {
1514                XMLResourceIdentifier resourceIdentifier =
1515                    new XMLResourceIdentifierImpl(
1516                        null,
1517                        href,
1518                        fCurrentBaseURI.getExpandedSystemId(),
1519                        XMLEntityManager.expandSystemId(
1520                            href,
1521                            fCurrentBaseURI.getExpandedSystemId(),
1522                            false));
1523
1524                includedSource =
1525                    fEntityResolver.resolveEntity(resourceIdentifier);
1526                
1527                if (includedSource != null &&
1528                    !(includedSource instanceof HTTPInputSource) &&
1529                    (accept != null || acceptLanguage != null) &&
1530                    includedSource.getCharacterStream() == null &&
1531                    includedSource.getByteStream() == null) {
1532                    
1533                    includedSource = createInputSource(includedSource.getPublicId(), includedSource.getSystemId(),
1534                        includedSource.getBaseSystemId(), accept, acceptLanguage);
1535                }
1536            }
1537            catch (IOException JavaDoc e) {
1538                reportResourceError(
1539                    "XMLResourceError",
1540                    new Object JavaDoc[] { href, e.getMessage()});
1541                return false;
1542            }
1543        }
1544
1545        if (includedSource == null) {
1546            // setup an HTTPInputSource if either of the content negotation attributes were specified.
1547
if (accept != null || acceptLanguage != null) {
1548                includedSource = createInputSource(null, href, fCurrentBaseURI.getExpandedSystemId(), accept, acceptLanguage);
1549            }
1550            else {
1551                includedSource = new XMLInputSource(null, href, fCurrentBaseURI.getExpandedSystemId());
1552            }
1553        }
1554        
1555        if (parse.equals(XINCLUDE_PARSE_XML)) {
1556            // Instead of always creating a new configuration, the first one can be reused
1557
if ((xpointer != null && fXPointerChildConfig == null)
1558                    || (xpointer == null && fXIncludeChildConfig == null) ) {
1559                
1560                String JavaDoc parserName = XINCLUDE_DEFAULT_CONFIGURATION;
1561                if (xpointer != null)
1562                    parserName = "org.apache.xerces.parsers.XPointerParserConfiguration";
1563                
1564                fChildConfig =
1565                    (XMLParserConfiguration)ObjectFactory.newInstance(
1566                        parserName,
1567                        ObjectFactory.findClassLoader(),
1568                        true);
1569
1570                // use the same symbol table, error reporter, entity resolver, security manager and buffer size.
1571
if (fSymbolTable != null) fChildConfig.setProperty(SYMBOL_TABLE, fSymbolTable);
1572                if (fErrorReporter != null) fChildConfig.setProperty(ERROR_REPORTER, fErrorReporter);
1573                if (fEntityResolver != null) fChildConfig.setProperty(ENTITY_RESOLVER, fEntityResolver);
1574                fChildConfig.setProperty(SECURITY_MANAGER, fSecurityManager);
1575                fChildConfig.setProperty(BUFFER_SIZE, new Integer JavaDoc(fBufferSize));
1576                
1577                // features must be copied to child configuration
1578
fNeedCopyFeatures = true;
1579
1580                // use the same namespace context
1581
fChildConfig.setProperty(
1582                    Constants.XERCES_PROPERTY_PREFIX
1583                        + Constants.NAMESPACE_CONTEXT_PROPERTY,
1584                    fNamespaceContext);
1585
1586                fChildConfig.setFeature(
1587                            XINCLUDE_FIXUP_BASE_URIS,
1588                            fFixupBaseURIs);
1589
1590                fChildConfig.setFeature(
1591                            XINCLUDE_FIXUP_LANGUAGE,
1592                            fFixupLanguage);
1593                
1594               
1595                // If the xpointer attribute is present
1596
if (xpointer != null ) {
1597                    
1598                    XPointerHandler newHandler =
1599                        (XPointerHandler)fChildConfig.getProperty(
1600                            Constants.XERCES_PROPERTY_PREFIX
1601                                + Constants.XPOINTER_HANDLER_PROPERTY);
1602
1603                    fXPtrProcessor = newHandler;
1604
1605                    // ???
1606
((XPointerHandler)fXPtrProcessor).setProperty(
1607                            Constants.XERCES_PROPERTY_PREFIX
1608                            + Constants.NAMESPACE_CONTEXT_PROPERTY,
1609                        fNamespaceContext);
1610
1611                    ((XPointerHandler)fXPtrProcessor).setProperty(XINCLUDE_FIXUP_BASE_URIS,
1612                            new Boolean JavaDoc(fFixupBaseURIs));
1613
1614                    ((XPointerHandler)fXPtrProcessor).setProperty(
1615                            XINCLUDE_FIXUP_LANGUAGE,
1616                            new Boolean JavaDoc (fFixupLanguage));
1617                    
1618                    if (fErrorReporter != null)
1619                        ((XPointerHandler)fXPtrProcessor).setProperty(ERROR_REPORTER, fErrorReporter);
1620                    // ???
1621

1622                    newHandler.setParent(this);
1623                    newHandler.setDocumentHandler(this.getDocumentHandler());
1624                    fXPointerChildConfig = fChildConfig;
1625                } else {
1626                    XIncludeHandler newHandler =
1627                        (XIncludeHandler)fChildConfig.getProperty(
1628                            Constants.XERCES_PROPERTY_PREFIX
1629                                + Constants.XINCLUDE_HANDLER_PROPERTY);
1630
1631                    newHandler.setParent(this);
1632                    newHandler.setDocumentHandler(this.getDocumentHandler());
1633                    fXIncludeChildConfig = fChildConfig;
1634                }
1635            }
1636
1637            // If an xpointer attribute is present
1638
if (xpointer != null ) {
1639                fChildConfig = fXPointerChildConfig ;
1640                
1641                // Parse the XPointer expression
1642
try {
1643                    ((XPointerProcessor)fXPtrProcessor).parseXPointer(xpointer);
1644                    
1645                } catch (XNIException ex) {
1646                    // report the XPointer error as a resource error
1647
reportResourceError(
1648                            "XMLResourceError",
1649                            new Object JavaDoc[] { href, ex.getMessage()});
1650                        return false;
1651                }
1652            } else {
1653                fChildConfig = fXIncludeChildConfig;
1654            }
1655
1656            // set all features on parserConfig to match this parser configuration
1657
if (fNeedCopyFeatures) {
1658                copyFeatures(fSettings, fChildConfig);
1659            }
1660            fNeedCopyFeatures = false;
1661
1662            try {
1663                fNamespaceContext.pushScope();
1664
1665                fChildConfig.parse(includedSource);
1666                // necessary to make sure proper location is reported in errors
1667
if (fErrorReporter != null) {
1668                    fErrorReporter.setDocumentLocator(fDocLocation);
1669                }
1670
1671                // If the xpointer attribute is present
1672
if (xpointer != null ) {
1673                    // and it was not resolved
1674
if (!((XPointerProcessor)fXPtrProcessor).isXPointerResolved()) {
1675                        Locale JavaDoc locale = (fErrorReporter != null) ? fErrorReporter.getLocale() : null;
1676                        String JavaDoc reason = fXIncludeMessageFormatter.formatMessage(locale, "XPointerResolutionUnsuccessful", null);
1677                        reportResourceError("XMLResourceError", new Object JavaDoc[] {href, reason});
1678                        // use the fallback
1679
return false;
1680                    }
1681                }
1682            }
1683            catch (XNIException e) {
1684                // necessary to make sure proper location is reported in errors
1685
if (fErrorReporter != null) {
1686                    fErrorReporter.setDocumentLocator(fDocLocation);
1687                }
1688                reportFatalError("XMLParseError", new Object JavaDoc[] { href });
1689            }
1690            catch (IOException JavaDoc e) {
1691                // necessary to make sure proper location is reported in errors
1692
if (fErrorReporter != null) {
1693                    fErrorReporter.setDocumentLocator(fDocLocation);
1694                }
1695                // An IOException indicates that we had trouble reading the file, not
1696
// that it was an invalid XML file. So we send a resource error, not a
1697
// fatal error.
1698
reportResourceError(
1699                    "XMLResourceError",
1700                    new Object JavaDoc[] { href, e.getMessage()});
1701                return false;
1702            }
1703            finally {
1704                fNamespaceContext.popScope();
1705            }
1706        }
1707        else if (parse.equals(XINCLUDE_PARSE_TEXT)) {
1708            // we only care about encoding for parse="text"
1709
String JavaDoc encoding = attributes.getValue(XINCLUDE_ATTR_ENCODING);
1710            includedSource.setEncoding(encoding);
1711            XIncludeTextReader textReader = null;
1712            
1713            try {
1714                // Setup the appropriate text reader.
1715
if (!fIsXML11) {
1716                    if (fXInclude10TextReader == null) {
1717                        fXInclude10TextReader = new XIncludeTextReader(includedSource, this, fBufferSize);
1718                    }
1719                    else {
1720                        fXInclude10TextReader.setInputSource(includedSource);
1721                    }
1722                    textReader = fXInclude10TextReader;
1723                }
1724                else {
1725                    if (fXInclude11TextReader == null) {
1726                        fXInclude11TextReader = new XInclude11TextReader(includedSource, this, fBufferSize);
1727                    }
1728                    else {
1729                        fXInclude11TextReader.setInputSource(includedSource);
1730                    }
1731                    textReader = fXInclude11TextReader;
1732                }
1733                textReader.setErrorReporter(fErrorReporter);
1734                textReader.parse();
1735            }
1736            // encoding errors
1737
catch (MalformedByteSequenceException ex) {
1738                fErrorReporter.reportError(ex.getDomain(), ex.getKey(),
1739                    ex.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR);
1740            }
1741            catch (CharConversionException JavaDoc e) {
1742                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1743                    "CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR);
1744            }
1745            catch (IOException JavaDoc e) {
1746                reportResourceError(
1747                    "TextResourceError",
1748                    new Object JavaDoc[] { href, e.getMessage()});
1749                return false;
1750            }
1751            finally {
1752                if (textReader != null) {
1753                    try {
1754                        textReader.close();
1755                    }
1756                    catch (IOException JavaDoc e) {
1757                        reportResourceError(
1758                            "TextResourceError",
1759                            new Object JavaDoc[] { href, e.getMessage()});
1760                        return false;
1761                    }
1762                }
1763            }
1764        }
1765        else {
1766            reportFatalError("InvalidParseValue", new Object JavaDoc[] { parse });
1767        }
1768        return true;
1769    }
1770
1771    /**
1772     * Returns true if the element has the namespace "http://www.w3.org/2001/XInclude"
1773     * @param element the element to check
1774     * @return true if the element has the namespace "http://www.w3.org/2001/XInclude"
1775     */

1776    protected boolean hasXIncludeNamespace(QName element) {
1777        // REVISIT: The namespace of this element should be bound
1778
// already. Why are we looking it up from the namespace
1779
// context? -- mrglavas
1780
return element.uri == XINCLUDE_NS_URI
1781            || fNamespaceContext.getURI(element.prefix) == XINCLUDE_NS_URI;
1782    }
1783
1784    /**
1785     * Checks if the element is an &lt;include&gt; element. The element must have
1786     * the XInclude namespace, and a local name of "include".
1787     *
1788     * @param element the element to check
1789     * @return true if the element is an &lt;include&gt; element
1790     * @see #hasXIncludeNamespace(QName)
1791     */

1792    protected boolean isIncludeElement(QName element) {
1793        return element.localpart.equals(XINCLUDE_INCLUDE) &&
1794            hasXIncludeNamespace(element);
1795    }
1796
1797    /**
1798     * Checks if the element is an &lt;fallback&gt; element. The element must have
1799     * the XInclude namespace, and a local name of "fallback".
1800     *
1801     * @param element the element to check
1802     * @return true if the element is an &lt;fallback; element
1803     * @see #hasXIncludeNamespace(QName)
1804     */

1805    protected boolean isFallbackElement(QName element) {
1806        return element.localpart.equals(XINCLUDE_FALLBACK) &&
1807            hasXIncludeNamespace(element);
1808    }
1809
1810    /**
1811     * Returns true if the current [base URI] is the same as the [base URI] that
1812     * was in effect on the include parent. This method should <em>only</em> be called
1813     * when the current element is a top level included element, i.e. the direct child
1814     * of a fallback element, or the root elements in an included document.
1815     * The "include parent" is the element which, in the result infoset, will be the
1816     * direct parent of the current element.
1817     * @return true if the [base URIs] are the same string
1818     */

1819    protected boolean sameBaseURIAsIncludeParent() {
1820        String JavaDoc parentBaseURI = getIncludeParentBaseURI();
1821        String JavaDoc baseURI = fCurrentBaseURI.getExpandedSystemId();
1822        // REVISIT: should we use File#sameFile() ?
1823
// I think the benefit of using it is that it resolves host names
1824
// instead of just doing a string comparison.
1825
// TODO: [base URI] is still an open issue with the working group.
1826
// They're deciding if xml:base should be added if the [base URI] is different in terms
1827
// of resolving relative references, or if it should be added if they are different at all.
1828
// Revisit this after a final decision has been made.
1829
// The decision also affects whether we output the file name of the URI, or just the path.
1830
return parentBaseURI != null && parentBaseURI.equals(baseURI);
1831    }
1832    
1833    /**
1834     * Returns true if the current [language] is equivalent to the [language] that
1835     * was in effect on the include parent, taking case-insensitivity into account
1836     * as per [RFC 3066]. This method should <em>only</em> be called when the
1837     * current element is a top level included element, i.e. the direct child
1838     * of a fallback element, or the root elements in an included document.
1839     * The "include parent" is the element which, in the result infoset, will be the
1840     * direct parent of the current element.
1841     *
1842     * @return true if the [language] properties have the same value
1843     * taking case-insensitivity into account as per [RFC 3066].
1844     */

1845    protected boolean sameLanguageAsIncludeParent() {
1846        String JavaDoc parentLanguage = getIncludeParentLanguage();
1847        return parentLanguage != null && parentLanguage.equalsIgnoreCase(fCurrentLanguage);
1848    }
1849
1850    /**
1851     * Checks if the file indicated by the given XMLLocator has already been included
1852     * in the current stack.
1853     * @param includedSource the source to check for inclusion
1854     * @return true if the source has already been included
1855     */

1856    protected boolean searchForRecursiveIncludes(XMLLocator includedSource) {
1857        String JavaDoc includedSystemId = includedSource.getExpandedSystemId();
1858
1859        if (includedSystemId == null) {
1860            try {
1861                includedSystemId =
1862                    XMLEntityManager.expandSystemId(
1863                        includedSource.getLiteralSystemId(),
1864                        includedSource.getBaseSystemId(),
1865                        false);
1866            }
1867            catch (MalformedURIException e) {
1868                reportFatalError("ExpandedSystemId");
1869            }
1870        }
1871
1872        if (includedSystemId.equals(fCurrentBaseURI.getExpandedSystemId())) {
1873            return true;
1874        }
1875
1876        if (fParentXIncludeHandler == null) {
1877            return false;
1878        }
1879        return fParentXIncludeHandler.searchForRecursiveIncludes(
1880            includedSource);
1881    }
1882
1883    /**
1884     * Returns true if the current element is a top level included item. This means
1885     * it's either the child of a fallback element, or the top level item in an
1886     * included document
1887     * @return true if the current element is a top level included item
1888     */

1889    protected boolean isTopLevelIncludedItem() {
1890        return isTopLevelIncludedItemViaInclude()
1891            || isTopLevelIncludedItemViaFallback();
1892    }
1893
1894    protected boolean isTopLevelIncludedItemViaInclude() {
1895        return fDepth == 1 && !isRootDocument();
1896    }
1897
1898    protected boolean isTopLevelIncludedItemViaFallback() {
1899        // Technically, this doesn't check if the parent was a fallback, it also
1900
// would return true if any of the parent's sibling elements were fallbacks.
1901
// However, this doesn't matter, since we will always be ignoring elements
1902
// whose parent's siblings were fallbacks.
1903
return getSawFallback(fDepth - 1);
1904    }
1905
1906    /**
1907     * Processes the XMLAttributes object of startElement() calls. Performs the following tasks:
1908     * <ul>
1909     * <li> If the element is a top level included item whose [base URI] is different from the
1910     * [base URI] of the include parent, then an xml:base attribute is added to specify the
1911     * true [base URI]
1912     * <li> For all namespace prefixes which are in-scope in an included item, but not in scope
1913     * in the include parent, a xmlns:prefix attribute is added
1914     * <li> For all attributes with a type of ENTITY, ENTITIES or NOTATIONS, the notations and
1915     * unparsed entities are processed as described in the spec, sections 4.5.1 and 4.5.2
1916     * </ul>
1917     * @param attributes
1918     * @return
1919     */

1920    protected XMLAttributes processAttributes(XMLAttributes attributes) {
1921        if (isTopLevelIncludedItem()) {
1922            // Modify attributes to fix the base URI (spec 4.5.5).
1923
// We only do it to top level included elements, which have a different
1924
// base URI than their include parent.
1925
if (fFixupBaseURIs && !sameBaseURIAsIncludeParent()) {
1926                if (attributes == null) {
1927                    attributes = new XMLAttributesImpl();
1928                }
1929
1930                // This causes errors with schema validation, if the schema doesn't
1931
// specify that these elements can have an xml:base attribute
1932
String JavaDoc uri = null;
1933                try {
1934                    uri = this.getRelativeBaseURI();
1935                }
1936                catch (MalformedURIException e) {
1937                    // this shouldn't ever happen, since by definition, we had to traverse
1938
// the same URIs to even get to this place
1939
uri = fCurrentBaseURI.getExpandedSystemId();
1940                }
1941                int index =
1942                    attributes.addAttribute(
1943                        XML_BASE_QNAME,
1944                        XMLSymbols.fCDATASymbol,
1945                        uri);
1946                attributes.setSpecified(index, true);
1947            }
1948            
1949            // Modify attributes to perform language-fixup (spec 4.5.6).
1950
// We only do it to top level included elements, which have a different
1951
// [language] than their include parent.
1952
if (fFixupLanguage && !sameLanguageAsIncludeParent()) {
1953                if (attributes == null) {
1954                    attributes = new XMLAttributesImpl();
1955                }
1956                int index =
1957                    attributes.addAttribute(
1958                        XML_LANG_QNAME,
1959                        XMLSymbols.fCDATASymbol,
1960                        fCurrentLanguage);
1961                attributes.setSpecified(index, true);
1962            }
1963
1964            // Modify attributes of included items to do namespace-fixup. (spec 4.5.4)
1965
Enumeration JavaDoc inscopeNS = fNamespaceContext.getAllPrefixes();
1966            while (inscopeNS.hasMoreElements()) {
1967                String JavaDoc prefix = (String JavaDoc)inscopeNS.nextElement();
1968                String JavaDoc parentURI =
1969                    fNamespaceContext.getURIFromIncludeParent(prefix);
1970                String JavaDoc uri = fNamespaceContext.getURI(prefix);
1971                if (parentURI != uri && attributes != null) {
1972                    if (prefix == XMLSymbols.EMPTY_STRING) {
1973                        if (attributes
1974                            .getValue(
1975                                NamespaceContext.XMLNS_URI,
1976                                XMLSymbols.PREFIX_XMLNS)
1977                            == null) {
1978                            if (attributes == null) {
1979                                attributes = new XMLAttributesImpl();
1980                            }
1981
1982                            QName ns = (QName)NEW_NS_ATTR_QNAME.clone();
1983                            ns.prefix = null;
1984                            ns.localpart = XMLSymbols.PREFIX_XMLNS;
1985                            ns.rawname = XMLSymbols.PREFIX_XMLNS;
1986                            int index =
1987                                attributes.addAttribute(
1988                                    ns,
1989                                    XMLSymbols.fCDATASymbol,
1990                                    uri != null ? uri : XMLSymbols.EMPTY_STRING);
1991                            attributes.setSpecified(index, true);
1992                            // Need to re-declare this prefix in the current context
1993
// in order for the SAX parser to report the appropriate
1994
// start and end prefix mapping events. -- mrglavas
1995
fNamespaceContext.declarePrefix(prefix, uri);
1996                        }
1997                    }
1998                    else if (
1999                        attributes.getValue(NamespaceContext.XMLNS_URI, prefix)
2000                            == null) {
2001                        if (attributes == null) {
2002                            attributes = new XMLAttributesImpl();
2003                        }
2004
2005                        QName ns = (QName)NEW_NS_ATTR_QNAME.clone();
2006                        ns.localpart = prefix;
2007                        ns.rawname += prefix;
2008                        ns.rawname = (fSymbolTable != null) ?
2009                            fSymbolTable.addSymbol(ns.rawname) :
2010                            ns.rawname.intern();
2011                        int index =
2012                            attributes.addAttribute(
2013                                ns,
2014                                XMLSymbols.fCDATASymbol,
2015                                uri != null ? uri : XMLSymbols.EMPTY_STRING);
2016                        attributes.setSpecified(index, true);
2017                        // Need to re-declare this prefix in the current context
2018
// in order for the SAX parser to report the appropriate
2019
// start and end prefix mapping events. -- mrglavas
2020
fNamespaceContext.declarePrefix(prefix, uri);
2021                    }
2022                }
2023            }
2024        }
2025
2026        if (attributes != null) {
2027            int length = attributes.getLength();
2028            for (int i = 0; i < length; i++) {
2029                String JavaDoc type = attributes.getType(i);
2030                String JavaDoc value = attributes.getValue(i);
2031                if (type == XMLSymbols.fENTITYSymbol) {
2032                    this.checkUnparsedEntity(value);
2033                }
2034                if (type == XMLSymbols.fENTITIESSymbol) {
2035                    // 4.5.1 - Unparsed Entities
2036
StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(value);
2037                    while (st.hasMoreTokens()) {
2038                        String JavaDoc entName = st.nextToken();
2039                        this.checkUnparsedEntity(entName);
2040                    }
2041                }
2042                else if (type == XMLSymbols.fNOTATIONSymbol) {
2043                    // 4.5.2 - Notations
2044
this.checkNotation(value);
2045                }
2046                /* We actually don't need to do anything for 4.5.3, because at this stage the
2047                 * value of the attribute is just a string. It will be taken care of later
2048                 * in the pipeline, when the IDREFs are actually resolved against IDs.
2049                 *
2050                 * if (type == XMLSymbols.fIDREFSymbol || type == XMLSymbols.fIDREFSSymbol) { }
2051                 */

2052            }
2053        }
2054
2055        return attributes;
2056    }
2057
2058    /**
2059     * Returns a URI, relative to the include parent's base URI, of the current
2060     * [base URI]. For instance, if the current [base URI] was "dir1/dir2/file.xml"
2061     * and the include parent's [base URI] was "dir/", this would return "dir2/file.xml".
2062     * @return the relative URI
2063     */

2064    protected String JavaDoc getRelativeBaseURI() throws MalformedURIException {
2065        int includeParentDepth = getIncludeParentDepth();
2066        String JavaDoc relativeURI = this.getRelativeURI(includeParentDepth);
2067        if (isRootDocument()) {
2068            return relativeURI;
2069        }
2070        else {
2071            if (relativeURI.equals("")) {
2072                relativeURI = fCurrentBaseURI.getLiteralSystemId();
2073            }
2074
2075            if (includeParentDepth == 0) {
2076                if (fParentRelativeURI == null) {
2077                    fParentRelativeURI =
2078                        fParentXIncludeHandler.getRelativeBaseURI();
2079                }
2080                if (fParentRelativeURI.equals("")) {
2081                    return relativeURI;
2082                }
2083
2084                URI base = new URI(fParentRelativeURI, true);
2085                URI uri = new URI(base, relativeURI);
2086                
2087                /** Check whether the scheme components are equal. */
2088                final String JavaDoc baseScheme = base.getScheme();
2089                final String JavaDoc literalScheme = uri.getScheme();
2090                if (!isEqual(baseScheme, literalScheme)) {
2091                    return relativeURI;
2092                }
2093                
2094                /** Check whether the authority components are equal. */
2095                final String JavaDoc baseAuthority = base.getAuthority();
2096                final String JavaDoc literalAuthority = uri.getAuthority();
2097                if (!isEqual(baseAuthority, literalAuthority)) {
2098                    return uri.getSchemeSpecificPart();
2099                }
2100                
2101                /**
2102                 * The scheme and authority components are equal,
2103                 * return the path and the possible query and/or
2104                 * fragment which follow.
2105                 */

2106                final String JavaDoc literalPath = uri.getPath();
2107                final String JavaDoc literalQuery = uri.getQueryString();
2108                final String JavaDoc literalFragment = uri.getFragment();
2109                if (literalQuery != null || literalFragment != null) {
2110                    StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
2111                    if (literalPath != null) {
2112                        buffer.append(literalPath);
2113                    }
2114                    if (literalQuery != null) {
2115                        buffer.append('?');
2116                        buffer.append(literalQuery);
2117                    }
2118                    if (literalFragment != null) {
2119                        buffer.append('#');
2120                        buffer.append(literalFragment);
2121                    }
2122                    return buffer.toString();
2123                }
2124                return literalPath;
2125            }
2126            else {
2127                return relativeURI;
2128            }
2129        }
2130    }
2131
2132    /**
2133     * Returns the [base URI] of the include parent.
2134     * @return the base URI of the include parent.
2135     */

2136    private String JavaDoc getIncludeParentBaseURI() {
2137        int depth = getIncludeParentDepth();
2138        if (!isRootDocument() && depth == 0) {
2139            return fParentXIncludeHandler.getIncludeParentBaseURI();
2140        }
2141        else {
2142            return this.getBaseURI(depth);
2143        }
2144    }
2145    
2146    /**
2147     * Returns the [language] of the include parent.
2148     *
2149     * @return the language property of the include parent.
2150     */

2151    private String JavaDoc getIncludeParentLanguage() {
2152        int depth = getIncludeParentDepth();
2153        if (!isRootDocument() && depth == 0) {
2154            return fParentXIncludeHandler.getIncludeParentLanguage();
2155        }
2156        else {
2157            return getLanguage(depth);
2158        }
2159    }
2160
2161    /**
2162     * Returns the depth of the include parent. Here, the include parent is
2163     * calculated as the last non-include or non-fallback element. It is assumed
2164     * this method is called when the current element is a top level included item.
2165     * Returning 0 indicates that the top level element in this document
2166     * was an include element.
2167     * @return the depth of the top level include element
2168     */

2169    private int getIncludeParentDepth() {
2170        // We don't start at fDepth, since it is either the top level included item,
2171
// or an include element, when this method is called.
2172
for (int i = fDepth - 1; i >= 0; i--) {
2173            // This technically might not always return the first non-include/fallback
2174
// element that it comes to, since sawFallback() returns true if a fallback
2175
// was ever encountered at that depth. However, if a fallback was encountered
2176
// at that depth, and it wasn't the direct descendant of the current element
2177
// then we can't be in a situation where we're calling this method (because
2178
// we'll always be in STATE_IGNORE)
2179
if (!getSawInclude(i) && !getSawFallback(i)) {
2180                return i;
2181            }
2182        }
2183        // shouldn't get here, since depth 0 should never have an include element or
2184
// a fallback element
2185
return 0;
2186    }
2187    
2188    /**
2189     * Returns the current element depth of the result infoset.
2190     */

2191    private int getResultDepth() {
2192        return fResultDepth;
2193    }
2194
2195    /**
2196     * Modify the augmentations. Add an [included] infoset item, if the current
2197     * element is a top level included item.
2198     * @param augs the Augmentations to modify.
2199     * @return the modified Augmentations
2200     */

2201    protected Augmentations modifyAugmentations(Augmentations augs) {
2202        return modifyAugmentations(augs, false);
2203    }
2204
2205    /**
2206     * Modify the augmentations. Add an [included] infoset item, if <code>force</code>
2207     * is true, or if the current element is a top level included item.
2208     * @param augs the Augmentations to modify.
2209     * @param force whether to force modification
2210     * @return the modified Augmentations
2211     */

2212    protected Augmentations modifyAugmentations(
2213        Augmentations augs,
2214        boolean force) {
2215        if (force || isTopLevelIncludedItem()) {
2216            if (augs == null) {
2217                augs = new AugmentationsImpl();
2218            }
2219            augs.putItem(XINCLUDE_INCLUDED, Boolean.TRUE);
2220        }
2221        return augs;
2222    }
2223
2224    protected int getState(int depth) {
2225        return fState[depth];
2226    }
2227
2228    protected int getState() {
2229        return fState[fDepth];
2230    }
2231
2232    protected void setState(int state) {
2233        if (fDepth >= fState.length) {
2234            int[] newarray = new int[fDepth * 2];
2235            System.arraycopy(fState, 0, newarray, 0, fState.length);
2236            fState = newarray;
2237        }
2238        fState[fDepth] = state;
2239    }
2240
2241    /**
2242     * Records that an &lt;fallback&gt; was encountered at the specified depth,
2243     * as an ancestor of the current element, or as a sibling of an ancestor of the
2244     * current element.
2245     *
2246     * @param depth
2247     * @param val
2248     */

2249    protected void setSawFallback(int depth, boolean val) {
2250        if (depth >= fSawFallback.length) {
2251            boolean[] newarray = new boolean[depth * 2];
2252            System.arraycopy(fSawFallback, 0, newarray, 0, fSawFallback.length);
2253            fSawFallback = newarray;
2254        }
2255        fSawFallback[depth] = val;
2256    }
2257
2258    /**
2259     * Returns whether an &lt;fallback&gt; was encountered at the specified depth,
2260     * as an ancestor of the current element, or as a sibling of an ancestor of the
2261     * current element.
2262     *
2263     * @param depth
2264     */

2265    protected boolean getSawFallback(int depth) {
2266        if (depth >= fSawFallback.length) {
2267            return false;
2268        }
2269        return fSawFallback[depth];
2270    }
2271
2272    /**
2273     * Records that an &lt;include&gt; was encountered at the specified depth,
2274     * as an ancestor of the current item.
2275     *
2276     * @param depth
2277     * @param val
2278     */

2279    protected void setSawInclude(int depth, boolean val) {
2280        if (depth >= fSawInclude.length) {
2281            boolean[] newarray = new boolean[depth * 2];
2282            System.arraycopy(fSawInclude, 0, newarray, 0, fSawInclude.length);
2283            fSawInclude = newarray;
2284        }
2285        fSawInclude[depth] = val;
2286    }
2287
2288    /**
2289     * Return whether an &lt;include&gt; was encountered at the specified depth,
2290     * as an ancestor of the current item.
2291     *
2292     * @param depth
2293     * @return
2294     */

2295    protected boolean getSawInclude(int depth) {
2296        if (depth >= fSawInclude.length) {
2297            return false;
2298        }
2299        return fSawInclude[depth];
2300    }
2301
2302    protected void reportResourceError(String JavaDoc key) {
2303        this.reportFatalError(key, null);
2304    }
2305
2306    protected void reportResourceError(String JavaDoc key, Object JavaDoc[] args) {
2307        this.reportError(key, args, XMLErrorReporter.SEVERITY_WARNING);
2308    }
2309
2310    protected void reportFatalError(String JavaDoc key) {
2311        this.reportFatalError(key, null);
2312    }
2313
2314    protected void reportFatalError(String JavaDoc key, Object JavaDoc[] args) {
2315        this.reportError(key, args, XMLErrorReporter.SEVERITY_FATAL_ERROR);
2316    }
2317
2318    private void reportError(String JavaDoc key, Object JavaDoc[] args, short severity) {
2319        if (fErrorReporter != null) {
2320            fErrorReporter.reportError(
2321                XIncludeMessageFormatter.XINCLUDE_DOMAIN,
2322                key,
2323                args,
2324                severity);
2325        }
2326        // we won't worry about when error reporter is null, since there should always be
2327
// at least the default error reporter
2328
}
2329
2330    /**
2331     * Set the parent of this XIncludeHandler in the tree
2332     * @param parent
2333     */

2334    protected void setParent(XIncludeHandler parent) {
2335        fParentXIncludeHandler = parent;
2336    }
2337
2338    // used to know whether to pass declarations to the document handler
2339
protected boolean isRootDocument() {
2340        return fParentXIncludeHandler == null;
2341    }
2342
2343    /**
2344     * Caches an unparsed entity.
2345     * @param name the name of the unparsed entity
2346     * @param identifier the location of the unparsed entity
2347     * @param augmentations any Augmentations that were on the original unparsed entity declaration
2348     */

2349    protected void addUnparsedEntity(
2350        String JavaDoc name,
2351        XMLResourceIdentifier identifier,
2352        String JavaDoc notation,
2353        Augmentations augmentations) {
2354        UnparsedEntity ent = new UnparsedEntity();
2355        ent.name = name;
2356        ent.systemId = identifier.getLiteralSystemId();
2357        ent.publicId = identifier.getPublicId();
2358        ent.baseURI = identifier.getBaseSystemId();
2359        ent.expandedSystemId = identifier.getExpandedSystemId();
2360        ent.notation = notation;
2361        ent.augmentations = augmentations;
2362        fUnparsedEntities.add(ent);
2363    }
2364
2365    /**
2366     * Caches a notation.
2367     * @param name the name of the notation
2368     * @param identifier the location of the notation
2369     * @param augmentations any Augmentations that were on the original notation declaration
2370     */

2371    protected void addNotation(
2372        String JavaDoc name,
2373        XMLResourceIdentifier identifier,
2374        Augmentations augmentations) {
2375        Notation not = new Notation();
2376        not.name = name;
2377        not.systemId = identifier.getLiteralSystemId();
2378        not.publicId = identifier.getPublicId();
2379        not.baseURI = identifier.getBaseSystemId();
2380        not.expandedSystemId = identifier.getExpandedSystemId();
2381        not.augmentations = augmentations;
2382        fNotations.add(not);
2383    }
2384
2385    /**
2386     * Checks if an UnparsedEntity with the given name was declared in the DTD of the document
2387     * for the current pipeline. If so, then the notation for the UnparsedEntity is checked.
2388     * If that turns out okay, then the UnparsedEntity is passed to the root pipeline to
2389     * be checked for conflicts, and sent to the root DTDHandler.
2390     *
2391     * @param entName the name of the UnparsedEntity to check
2392     */

2393    protected void checkUnparsedEntity(String JavaDoc entName) {
2394        UnparsedEntity ent = new UnparsedEntity();
2395        ent.name = entName;
2396        int index = fUnparsedEntities.indexOf(ent);
2397        if (index != -1) {
2398            ent = (UnparsedEntity)fUnparsedEntities.get(index);
2399            // first check the notation of the unparsed entity
2400
checkNotation(ent.notation);
2401            checkAndSendUnparsedEntity(ent);
2402        }
2403    }
2404
2405    /**
2406     * Checks if a Notation with the given name was declared in the DTD of the document
2407     * for the current pipeline. If so, that Notation is passed to the root pipeline to
2408     * be checked for conflicts, and sent to the root DTDHandler
2409     *
2410     * @param notName the name of the Notation to check
2411     */

2412    protected void checkNotation(String JavaDoc notName) {
2413        Notation not = new Notation();
2414        not.name = notName;
2415        int index = fNotations.indexOf(not);
2416        if (index != -1) {
2417            not = (Notation)fNotations.get(index);
2418            checkAndSendNotation(not);
2419        }
2420    }
2421
2422    /**
2423     * The purpose of this method is to check if an UnparsedEntity conflicts with a previously
2424     * declared entity in the current pipeline stack. If there is no conflict, the
2425     * UnparsedEntity is sent by the root pipeline.
2426     *
2427     * @param ent the UnparsedEntity to check for conflicts
2428     */

2429    protected void checkAndSendUnparsedEntity(UnparsedEntity ent) {
2430        if (isRootDocument()) {
2431            int index = fUnparsedEntities.indexOf(ent);
2432            if (index == -1) {
2433                // There is no unparsed entity with the same name that we have sent.
2434
// Calling unparsedEntityDecl() will add the entity to our local store,
2435
// and also send the unparsed entity to the DTDHandler
2436
XMLResourceIdentifier id =
2437                    new XMLResourceIdentifierImpl(
2438                        ent.publicId,
2439                        ent.systemId,
2440                        ent.baseURI,
2441                        ent.expandedSystemId);
2442                addUnparsedEntity(
2443                    ent.name,
2444                    id,
2445                    ent.notation,
2446                    ent.augmentations);
2447                if (fSendUEAndNotationEvents && fDTDHandler != null) {
2448                    fDTDHandler.unparsedEntityDecl(
2449                        ent.name,
2450                        id,
2451                        ent.notation,
2452                        ent.augmentations);
2453                }
2454            }
2455            else {
2456                UnparsedEntity localEntity =
2457                    (UnparsedEntity)fUnparsedEntities.get(index);
2458                if (!ent.isDuplicate(localEntity)) {
2459                    reportFatalError(
2460                        "NonDuplicateUnparsedEntity",
2461                        new Object JavaDoc[] { ent.name });
2462                }
2463            }
2464        }
2465        else {
2466            fParentXIncludeHandler.checkAndSendUnparsedEntity(ent);
2467        }
2468    }
2469
2470    /**
2471     * The purpose of this method is to check if a Notation conflicts with a previously
2472     * declared notation in the current pipeline stack. If there is no conflict, the
2473     * Notation is sent by the root pipeline.
2474     *
2475     * @param not the Notation to check for conflicts
2476     */

2477    protected void checkAndSendNotation(Notation not) {
2478        if (isRootDocument()) {
2479            int index = fNotations.indexOf(not);
2480            if (index == -1) {
2481                // There is no notation with the same name that we have sent.
2482
XMLResourceIdentifier id =
2483                    new XMLResourceIdentifierImpl(
2484                        not.publicId,
2485                        not.systemId,
2486                        not.baseURI,
2487                        not.expandedSystemId);
2488                addNotation(not.name, id, not.augmentations);
2489                if (fSendUEAndNotationEvents && fDTDHandler != null) {
2490                    fDTDHandler.notationDecl(not.name, id, not.augmentations);
2491                }
2492            }
2493            else {
2494                Notation localNotation = (Notation)fNotations.get(index);
2495                if (!not.isDuplicate(localNotation)) {
2496                    reportFatalError(
2497                        "NonDuplicateNotation",
2498                        new Object JavaDoc[] { not.name });
2499                }
2500            }
2501        }
2502        else {
2503            fParentXIncludeHandler.checkAndSendNotation(not);
2504        }
2505    }
2506    
2507    /**
2508     * Checks whether the string only contains white space characters.
2509     *
2510     * @param value the text to check
2511     */

2512    private void checkWhitespace(XMLString value) {
2513        int end = value.offset + value.length;
2514        for (int i = value.offset; i < end; ++i) {
2515            if (!XMLChar.isSpace(value.ch[i])) {
2516                reportFatalError("ContentIllegalAtTopLevel");
2517                return;
2518            }
2519        }
2520    }
2521    
2522    /**
2523     * Checks whether the root element has already been processed.
2524     */

2525    private void checkMultipleRootElements() {
2526        if (getRootElementProcessed()) {
2527            reportFatalError("MultipleRootElements");
2528        }
2529        setRootElementProcessed(true);
2530    }
2531    
2532    /**
2533     * Sets whether the root element has been processed.
2534     */

2535    private void setRootElementProcessed(boolean seenRoot) {
2536        if (isRootDocument()) {
2537            fSeenRootElement = seenRoot;
2538            return;
2539        }
2540        fParentXIncludeHandler.setRootElementProcessed(seenRoot);
2541    }
2542    
2543    /**
2544     * Returns whether the root element has been processed.
2545     */

2546    private boolean getRootElementProcessed() {
2547        return isRootDocument() ? fSeenRootElement : fParentXIncludeHandler.getRootElementProcessed();
2548    }
2549
2550    // It would be nice if we didn't have to repeat code like this, but there's no interface that has
2551
// setFeature() and addRecognizedFeatures() that the objects have in common.
2552
protected void copyFeatures(
2553        XMLComponentManager from,
2554        ParserConfigurationSettings to) {
2555        Enumeration JavaDoc features = Constants.getXercesFeatures();
2556        copyFeatures1(features, Constants.XERCES_FEATURE_PREFIX, from, to);
2557        features = Constants.getSAXFeatures();
2558        copyFeatures1(features, Constants.SAX_FEATURE_PREFIX, from, to);
2559    }
2560
2561    protected void copyFeatures(
2562        XMLComponentManager from,
2563        XMLParserConfiguration to) {
2564        Enumeration JavaDoc features = Constants.getXercesFeatures();
2565        copyFeatures1(features, Constants.XERCES_FEATURE_PREFIX, from, to);
2566        features = Constants.getSAXFeatures();
2567        copyFeatures1(features, Constants.SAX_FEATURE_PREFIX, from, to);
2568    }
2569
2570    private void copyFeatures1(
2571        Enumeration JavaDoc features,
2572        String JavaDoc featurePrefix,
2573        XMLComponentManager from,
2574        ParserConfigurationSettings to) {
2575        while (features.hasMoreElements()) {
2576            String JavaDoc featureId = featurePrefix + (String JavaDoc)features.nextElement();
2577
2578            to.addRecognizedFeatures(new String JavaDoc[] { featureId });
2579
2580            try {
2581                to.setFeature(featureId, from.getFeature(featureId));
2582            }
2583            catch (XMLConfigurationException e) {
2584                // componentManager doesn't support this feature,
2585
// so we won't worry about it
2586
}
2587        }
2588    }
2589
2590    private void copyFeatures1(
2591        Enumeration JavaDoc features,
2592        String JavaDoc featurePrefix,
2593        XMLComponentManager from,
2594        XMLParserConfiguration to) {
2595        while (features.hasMoreElements()) {
2596            String JavaDoc featureId = featurePrefix + (String JavaDoc)features.nextElement();
2597            boolean value = from.getFeature(featureId);
2598
2599            try {
2600                to.setFeature(featureId, value);
2601            }
2602            catch (XMLConfigurationException e) {
2603                // componentManager doesn't support this feature,
2604
// so we won't worry about it
2605
}
2606        }
2607    }
2608
2609    // This is a storage class to hold information about the notations.
2610
// We're not using XMLNotationDecl because we don't want to lose the augmentations.
2611
protected static class Notation {
2612        public String JavaDoc name;
2613        public String JavaDoc systemId;
2614        public String JavaDoc baseURI;
2615        public String JavaDoc publicId;
2616        public String JavaDoc expandedSystemId;
2617        public Augmentations augmentations;
2618
2619        // equals() returns true if two Notations have the same name.
2620
// Useful for searching Vectors for notations with the same name
2621
public boolean equals(Object JavaDoc obj) {
2622            if (obj == null) {
2623                return false;
2624            }
2625            if (obj instanceof Notation) {
2626                Notation other = (Notation)obj;
2627                return name.equals(other.name);
2628            }
2629            return false;
2630        }
2631
2632        // from 4.5.2
2633
// Notation items with the same [name], [system identifier],
2634
// [public identifier], and [declaration base URI] are considered
2635
// to be duplicate. An application may also be able to detect that
2636
// notations are duplicate through other means. For instance, the URI
2637
// resulting from combining the system identifier and the declaration
2638
// base URI is the same.
2639
public boolean isDuplicate(Object JavaDoc obj) {
2640            if (obj != null && obj instanceof Notation) {
2641                Notation other = (Notation)obj;
2642                return name.equals(other.name)
2643                && isEqual(publicId, other.publicId)
2644                && isEqual(expandedSystemId, other.expandedSystemId);
2645            }
2646            return false;
2647        }
2648        
2649        private boolean isEqual(String JavaDoc one, String JavaDoc two) {
2650            return (one == two || (one != null && one.equals(two)));
2651        }
2652    }
2653
2654    // This is a storage class to hold information about the unparsed entities.
2655
// We're not using XMLEntityDecl because we don't want to lose the augmentations.
2656
protected static class UnparsedEntity {
2657        public String JavaDoc name;
2658        public String JavaDoc systemId;
2659        public String JavaDoc baseURI;
2660        public String JavaDoc publicId;
2661        public String JavaDoc expandedSystemId;
2662        public String JavaDoc notation;
2663        public Augmentations augmentations;
2664
2665        // equals() returns true if two UnparsedEntities have the same name.
2666
// Useful for searching Vectors for entities with the same name
2667
public boolean equals(Object JavaDoc obj) {
2668            if (obj == null) {
2669                return false;
2670            }
2671            if (obj instanceof UnparsedEntity) {
2672                UnparsedEntity other = (UnparsedEntity)obj;
2673                return name.equals(other.name);
2674            }
2675            return false;
2676        }
2677
2678        // from 4.5.1:
2679
// Unparsed entity items with the same [name], [system identifier],
2680
// [public identifier], [declaration base URI], [notation name], and
2681
// [notation] are considered to be duplicate. An application may also
2682
// be able to detect that unparsed entities are duplicate through other
2683
// means. For instance, the URI resulting from combining the system
2684
// identifier and the declaration base URI is the same.
2685
public boolean isDuplicate(Object JavaDoc obj) {
2686            if (obj != null && obj instanceof UnparsedEntity) {
2687                UnparsedEntity other = (UnparsedEntity)obj;
2688                return name.equals(other.name)
2689                && isEqual(publicId, other.publicId)
2690                && isEqual(expandedSystemId, other.expandedSystemId)
2691                && isEqual(notation, other.notation);
2692            }
2693            return false;
2694        }
2695        
2696        private boolean isEqual(String JavaDoc one, String JavaDoc two) {
2697            return (one == two || (one != null && one.equals(two)));
2698        }
2699    }
2700
2701    // The following methods are used for XML Base processing
2702

2703    /**
2704     * Saves the current base URI to the top of the stack.
2705     */

2706    protected void saveBaseURI() {
2707        fBaseURIScope.push(fDepth);
2708        fBaseURI.push(fCurrentBaseURI.getBaseSystemId());
2709        fLiteralSystemID.push(fCurrentBaseURI.getLiteralSystemId());
2710        fExpandedSystemID.push(fCurrentBaseURI.getExpandedSystemId());
2711    }
2712
2713    /**
2714     * Discards the URIs at the top of the stack, and restores the ones beneath it.
2715     */

2716    protected void restoreBaseURI() {
2717        fBaseURI.pop();
2718        fLiteralSystemID.pop();
2719        fExpandedSystemID.pop();
2720        fBaseURIScope.pop();
2721        fCurrentBaseURI.setBaseSystemId((String JavaDoc)fBaseURI.peek());
2722        fCurrentBaseURI.setLiteralSystemId((String JavaDoc)fLiteralSystemID.peek());
2723        fCurrentBaseURI.setExpandedSystemId((String JavaDoc)fExpandedSystemID.peek());
2724    }
2725    
2726    // The following methods are used for language processing
2727

2728    /**
2729     * Saves the given language on the top of the stack.
2730     *
2731     * @param lanaguage the language to push onto the stack.
2732     */

2733    protected void saveLanguage(String JavaDoc language) {
2734        fLanguageScope.push(fDepth);
2735        fLanguageStack.push(language);
2736    }
2737    
2738    /**
2739     * Discards the language at the top of the stack, and returns the one beneath it.
2740     */

2741    public String JavaDoc restoreLanguage() {
2742        fLanguageStack.pop();
2743        fLanguageScope.pop();
2744        return (String JavaDoc) fLanguageStack.peek();
2745    }
2746
2747    /**
2748     * Gets the base URI that was in use at that depth
2749     * @param depth
2750     * @return the base URI
2751     */

2752    public String JavaDoc getBaseURI(int depth) {
2753        int scope = scopeOfBaseURI(depth);
2754        return (String JavaDoc)fExpandedSystemID.elementAt(scope);
2755    }
2756    
2757    /**
2758     * Gets the language that was in use at that depth.
2759     * @param depth
2760     * @return the language
2761     */

2762    public String JavaDoc getLanguage(int depth) {
2763        int scope = scopeOfLanguage(depth);
2764        return (String JavaDoc)fLanguageStack.elementAt(scope);
2765    }
2766
2767    /**
2768     * Returns a relative URI, which when resolved against the base URI at the
2769     * specified depth, will create the current base URI.
2770     * This is accomplished by merged the literal system IDs.
2771     * @param depth the depth at which to start creating the relative URI
2772     * @return a relative URI to convert the base URI at the given depth to the current
2773     * base URI
2774     */

2775    public String JavaDoc getRelativeURI(int depth) throws MalformedURIException {
2776        // The literal system id at the location given by "start" is *in focus* at
2777
// the given depth. So we need to adjust it to the next scope, so that we
2778
// only process out of focus literal system ids
2779
int start = scopeOfBaseURI(depth) + 1;
2780        if (start == fBaseURIScope.size()) {
2781            // If that is the last system id, then we don't need a relative URI
2782
return "";
2783        }
2784        URI uri = new URI("file", (String JavaDoc)fLiteralSystemID.elementAt(start));
2785        for (int i = start + 1; i < fBaseURIScope.size(); i++) {
2786            uri = new URI(uri, (String JavaDoc)fLiteralSystemID.elementAt(i));
2787        }
2788        return uri.getPath();
2789    }
2790
2791    // We need to find two consecutive elements in the scope stack,
2792
// such that the first is lower than 'depth' (or equal), and the
2793
// second is higher.
2794
private int scopeOfBaseURI(int depth) {
2795        for (int i = fBaseURIScope.size() - 1; i >= 0; i--) {
2796            if (fBaseURIScope.elementAt(i) <= depth)
2797                return i;
2798        }
2799        // we should never get here, because 0 was put on the stack in startDocument()
2800
return -1;
2801    }
2802    
2803    private int scopeOfLanguage(int depth) {
2804        for (int i = fLanguageScope.size() - 1; i >= 0; i--) {
2805            if (fLanguageScope.elementAt(i) <= depth)
2806                return i;
2807        }
2808        // we should never get here, because 0 was put on the stack in startDocument()
2809
return -1;
2810    }
2811
2812    /**
2813     * Search for a xml:base attribute, and if one is found, put the new base URI into
2814     * effect.
2815     */

2816    protected void processXMLBaseAttributes(XMLAttributes attributes) {
2817        String JavaDoc baseURIValue =
2818            attributes.getValue(NamespaceContext.XML_URI, "base");
2819        if (baseURIValue != null) {
2820            try {
2821                String JavaDoc expandedValue =
2822                    XMLEntityManager.expandSystemId(
2823                        baseURIValue,
2824                        fCurrentBaseURI.getExpandedSystemId(),
2825                        false);
2826                fCurrentBaseURI.setLiteralSystemId(baseURIValue);
2827                fCurrentBaseURI.setBaseSystemId(
2828                    fCurrentBaseURI.getExpandedSystemId());
2829                fCurrentBaseURI.setExpandedSystemId(expandedValue);
2830
2831                // push the new values on the stack
2832
saveBaseURI();
2833            }
2834            catch (MalformedURIException e) {
2835                // REVISIT: throw error here
2836
}
2837        }
2838    }
2839    
2840    /**
2841     * Search for a xml:lang attribute, and if one is found, put the new
2842     * [language] into effect.
2843     */

2844    protected void processXMLLangAttributes(XMLAttributes attributes) {
2845        String JavaDoc language = attributes.getValue(NamespaceContext.XML_URI, "lang");
2846        if (language != null) {
2847            fCurrentLanguage = language;
2848            saveLanguage(fCurrentLanguage);
2849        }
2850    }
2851    
2852    /**
2853     * Returns <code>true</code> if the given string
2854     * would be valid in an HTTP header.
2855     *
2856     * @param value string to check
2857     * @return <code>true</code> if the given string
2858     * would be valid in an HTTP header
2859     */

2860    private boolean isValidInHTTPHeader (String JavaDoc value) {
2861        char ch;
2862        for (int i = value.length() - 1; i >= 0; --i) {
2863            ch = value.charAt(i);
2864            if (ch < 0x20 || ch > 0x7E) {
2865                return false;
2866            }
2867        }
2868        return true;
2869    }
2870    
2871    /**
2872     * Returns a new <code>XMLInputSource</code> from the given parameters.
2873     */

2874    private XMLInputSource createInputSource(String JavaDoc publicId,
2875            String JavaDoc systemId, String JavaDoc baseSystemId,
2876            String JavaDoc accept, String JavaDoc acceptLanguage) {
2877
2878        HTTPInputSource httpSource = new HTTPInputSource(publicId, systemId, baseSystemId);
2879        if (accept != null && accept.length() > 0) {
2880            httpSource.setHTTPRequestProperty(XIncludeHandler.HTTP_ACCEPT, accept);
2881        }
2882        if (acceptLanguage != null && acceptLanguage.length() > 0) {
2883            httpSource.setHTTPRequestProperty(XIncludeHandler.HTTP_ACCEPT_LANGUAGE, acceptLanguage);
2884        }
2885        return httpSource;
2886    }
2887    
2888    private boolean isEqual(String JavaDoc one, String JavaDoc two) {
2889        return (one == two || (one != null && one.equals(two)));
2890    }
2891    
2892    // which ASCII characters need to be escaped
2893
private static boolean gNeedEscaping[] = new boolean[128];
2894    // the first hex character if a character needs to be escaped
2895
private static char gAfterEscaping1[] = new char[128];
2896    // the second hex character if a character needs to be escaped
2897
private static char gAfterEscaping2[] = new char[128];
2898    private static char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7',
2899                                     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
2900    // initialize the above 3 arrays
2901
static {
2902        char[] escChs = {' ', '<', '>', '"', '{', '}', '|', '\\', '^', '`'};
2903        int len = escChs.length;
2904        char ch;
2905        for (int i = 0; i < len; i++) {
2906            ch = escChs[i];
2907            gNeedEscaping[ch] = true;
2908            gAfterEscaping1[ch] = gHexChs[ch >> 4];
2909            gAfterEscaping2[ch] = gHexChs[ch & 0xf];
2910        }
2911    }
2912    
2913    //
2914
// Escape an href value according to (4.1.1):
2915
//
2916
// To convert the value of the href attribute to an IRI reference, the following characters must be escaped:
2917
// space #x20
2918
// the delimiters < #x3C, > #x3E and " #x22
2919
// the unwise characters { #x7B, } #x7D, | #x7C, \ #x5C, ^ #x5E and ` #x60
2920
//
2921
// To convert an IRI reference to a URI reference, the following characters must also be escaped:
2922
// the Unicode plane 0 characters #xA0 - #xD7FF, #xF900-#xFDCF, #xFDF0-#xFFEF
2923
// the Unicode plane 1-14 characters #x10000-#x1FFFD ... #xE0000-#xEFFFD
2924
//
2925
private String JavaDoc escapeHref(String JavaDoc href) {
2926        int len = href.length();
2927        int ch;
2928        StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(len*3);
2929
2930        // for each character in the href
2931
int i = 0;
2932        for (; i < len; i++) {
2933            ch = href.charAt(i);
2934            // if it's not an ASCII character (excluding 0x7F), break here, and use UTF-8 encoding
2935
if (ch > 0x7E) {
2936                break;
2937            }
2938            // abort: href does not allow this character
2939
if (ch < 0x20) {
2940                return href;
2941            }
2942            if (gNeedEscaping[ch]) {
2943                buffer.append('%');
2944                buffer.append(gAfterEscaping1[ch]);
2945                buffer.append(gAfterEscaping2[ch]);
2946            }
2947            else {
2948                buffer.append((char)ch);
2949            }
2950        }
2951
2952        // we saw some non-ascii character
2953
if (i < len) {
2954            // check if remainder of href contains any illegal characters before proceeding
2955
for (int j = i; j < len; ++j) {
2956                ch = href.charAt(j);
2957                if ((ch >= 0x20 && ch <= 0x7E) ||
2958                    (ch >= 0xA0 && ch <= 0xD7FF) ||
2959                    (ch >= 0xF900 && ch <= 0xFDCF) ||
2960                    (ch >= 0xFDF0 && ch <= 0xFFEF)) {
2961                    continue;
2962                }
2963                if (XMLChar.isHighSurrogate(ch) && ++j < len) {
2964                    int ch2 = href.charAt(j);
2965                    if (XMLChar.isLowSurrogate(ch2)) {
2966                        ch2 = XMLChar.supplemental((char)ch, (char)ch2);
2967                        if (ch2 < 0xF0000 && (ch2 & 0xFFFF) <= 0xFFFD) {
2968                            continue;
2969                        }
2970                    }
2971                }
2972                // abort: href does not allow this character
2973
return href;
2974            }
2975            
2976            // get UTF-8 bytes for the remaining sub-string
2977
byte[] bytes = null;
2978            byte b;
2979            try {
2980                bytes = href.substring(i).getBytes("UTF-8");
2981            } catch (java.io.UnsupportedEncodingException JavaDoc e) {
2982                // should never happen
2983
return href;
2984            }
2985            len = bytes.length;
2986
2987            // for each byte
2988
for (i = 0; i < len; i++) {
2989                b = bytes[i];
2990                // for non-ascii character: make it positive, then escape
2991
if (b < 0) {
2992                    ch = b + 256;
2993                    buffer.append('%');
2994                    buffer.append(gHexChs[ch >> 4]);
2995                    buffer.append(gHexChs[ch & 0xf]);
2996                }
2997                else if (gNeedEscaping[b]) {
2998                    buffer.append('%');
2999                    buffer.append(gAfterEscaping1[b]);
3000                    buffer.append(gAfterEscaping2[b]);
3001                }
3002                else {
3003                    buffer.append((char)b);
3004                }
3005            }
3006        }
3007
3008        // If escaping happened, create a new string;
3009
// otherwise, return the orginal one.
3010
if (buffer.length() != len) {
3011            return buffer.toString();
3012        }
3013        else {
3014            return href;
3015        }
3016    }
3017}
3018
Popular Tags