2
* The Apache Software License, Version 1.1
5
* Copyright (c) 1999-2003 The Apache Software Foundation.
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in
17
* the documentation and/or other materials provided with the
20
* 3. The end-user documentation included with the redistribution,
21
* if any, must include the following acknowledgment:
22
* "This product includes software developed by the
23
* Apache Software Foundation (http://www.apache.org/)."
24
* Alternately, this acknowledgment may appear in the software itself,
25
* if and wherever such third-party acknowledgments normally appear.
27
* 4. The names "Xerces" and "Apache Software Foundation" must
28
* not be used to endorse or promote products derived from this
29
* software without prior written permission. For written
30
* permission, please contact apache@apache.org.
32
* 5. Products derived from this software may not be called "Apache",
33
* nor may "Apache" appear in their name, without prior written
34
* permission of the Apache Software Foundation.
36
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48
* ====================================================================
50
* This software consists of voluntary contributions made by many
51
* individuals on behalf of the Apache Software Foundation and was
52
* originally based on software copyright (c) 1999, International
53
* Business Machines, Inc., http://www.apache.org. For more
54
* information on the Apache Software Foundation, please see
55
* <http://www.apache.org/>.
58
package org.apache.xerces.impl.dtd;
60
import org.apache.xerces.impl.Constants;
61
import org.apache.xerces.impl.XMLDTDScannerImpl;
62
import org.apache.xerces.impl.XMLErrorReporter;
63
import org.apache.xerces.impl.XMLEntityManager;
64
import org.apache.xerces.impl.msg.XMLMessageFormatter;
66
import org.apache.xerces.util.SymbolTable;
67
import org.apache.xerces.util.DefaultErrorHandler;
69
import org.apache.xerces.xni.XNIException;
70
import org.apache.xerces.xni.grammars.XMLGrammarPool;
71
import org.apache.xerces.xni.grammars.XMLGrammarLoader;
72
import org.apache.xerces.xni.grammars.Grammar;
73
import org.apache.xerces.xni.parser.XMLConfigurationException;
74
import org.apache.xerces.xni.parser.XMLErrorHandler;
75
import org.apache.xerces.xni.parser.XMLEntityResolver;
76
import org.apache.xerces.xni.parser.XMLInputSource;
78
import java.util.Locale;
79
import java.io.IOException;
80
import java.io.EOFException;
83
* The DTD loader. The loader knows how to build grammars from XMLInputSources.
84
* It extends the DTD processor in order to do this; it's
85
* a separate class because DTD processors don't need to know how
86
* to talk to the outside world in their role as instance-document
89
* This component requires the following features and properties. It
90
* know ho to set them if no one else does:from the
92
* <li>http://xml.org/sax/features/namespaces</li>
93
* <li>http://apache.org/xml/properties/internal/symbol-table</li>
94
* <li>http://apache.org/xml/properties/internal/error-reporter</li>
95
* <li>http://apache.org/xml/properties/internal/grammar-pool</li>
96
* <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
99
* @author Neil Graham, IBM
101
* @version $Id: XMLDTDLoader.java,v 1.9 2003/10/14 14:34:26 mrglavas Exp $
103
public class XMLDTDLoader
104
extends XMLDTDProcessor
105
implements XMLGrammarLoader {
111
// feature identifiers
113
/** Feature identifier: standard uri conformant feature. */
114
protected static final String STANDARD_URI_CONFORMANT_FEATURE =
115
Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
117
// recognized features:
118
private static final String[] RECOGNIZED_FEATURES = {
120
WARN_ON_DUPLICATE_ATTDEF,
122
STANDARD_URI_CONFORMANT_FEATURE
125
// property identifiers
127
/** Property identifier: error handler. */
128
protected static final String ERROR_HANDLER =
129
Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
131
/** Property identifier: entity resolver. */
132
public static final String ENTITY_RESOLVER =
133
Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
135
/** Recognized properties. */
136
private static final String[] LOADER_RECOGNIZED_PROPERTIES = {
145
// enforcing strict uri?
146
private boolean fStrictURI = false;
148
/** Entity resolver . */
149
protected XMLEntityResolver fEntityResolver;
151
// the scanner we use to actually read the DTD
152
protected XMLDTDScannerImpl fDTDScanner;
154
// the entity manager the scanner needs.
155
protected XMLEntityManager fEntityManager;
157
// what's our Locale?
158
protected Locale fLocale;
164
/** Deny default construction; we need a SymtolTable! */
165
public XMLDTDLoader() {
166
this(new SymbolTable());
169
public XMLDTDLoader(SymbolTable symbolTable) {
170
this(symbolTable, null);
171
} // init(SymbolTable)
173
public XMLDTDLoader(SymbolTable symbolTable,
174
XMLGrammarPool grammarPool) {
175
this(symbolTable, grammarPool, null, new XMLEntityManager());
176
} // init(SymbolTable, XMLGrammarPool)
178
XMLDTDLoader(SymbolTable symbolTable,
179
XMLGrammarPool grammarPool, XMLErrorReporter errorReporter,
180
XMLEntityResolver entityResolver) {
181
fSymbolTable = symbolTable;
182
fGrammarPool = grammarPool;
183
if(errorReporter == null) {
184
errorReporter = new XMLErrorReporter();
185
errorReporter.setProperty(ERROR_HANDLER, new DefaultErrorHandler());
187
fErrorReporter = errorReporter;
188
// Add XML message formatter if there isn't one.
189
if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) {
190
XMLMessageFormatter xmft = new XMLMessageFormatter();
191
fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft);
192
fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft);
194
fEntityResolver = entityResolver;
195
if(fEntityResolver instanceof XMLEntityManager) {
196
fEntityManager = (XMLEntityManager)fEntityResolver;
198
fEntityManager = new XMLEntityManager();
200
fEntityManager.setProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY, errorReporter);
201
fDTDScanner = new XMLDTDScannerImpl(fSymbolTable, fErrorReporter, fEntityManager);
202
fDTDScanner.setDTDHandler(this);
203
fDTDScanner.setDTDContentModelHandler(this);
205
} // init(SymbolTable, XMLGrammarPool, XMLErrorReporter, XMLEntityResolver)
207
// XMLGrammarLoader methods
210
* Sets the state of a feature. This method is called by the component
211
* manager any time after reset when a feature changes state.
213
* <strong>Note:</strong> Components should silently ignore features
214
* that do not affect the operation of the component.
216
* @param featureId The feature identifier.
217
* @param state The state of the feature.
219
* @throws SAXNotRecognizedException The component should not throw
221
* @throws SAXNotSupportedException The component should not throw
224
public void setFeature(String featureId, boolean state)
225
throws XMLConfigurationException {
226
if(featureId.equals(VALIDATION)) {
228
} else if(featureId.equals(WARN_ON_DUPLICATE_ATTDEF)) {
229
fWarnDuplicateAttdef = state;
230
} else if(featureId.equals(NOTIFY_CHAR_REFS)) {
231
fDTDScanner.setFeature(featureId, state);
232
} else if(featureId.equals(STANDARD_URI_CONFORMANT_FEATURE)) {
235
throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId);
237
} // setFeature(String,boolean)
240
* Returns a list of property identifiers that are recognized by
241
* this component. This method may return null if no properties
242
* are recognized by this component.
244
public String[] getRecognizedProperties() {
245
return (String[])(LOADER_RECOGNIZED_PROPERTIES.clone());
246
} // getRecognizedProperties():String[]
249
* Returns the state of a property.
251
* @param propertyId The property identifier.
253
* @throws XMLConfigurationException Thrown on configuration error.
255
public Object getProperty(String propertyId)
256
throws XMLConfigurationException {
257
if(propertyId.equals( SYMBOL_TABLE)) {
259
} else if(propertyId.equals( ERROR_REPORTER)) {
260
return fErrorReporter;
261
} else if(propertyId.equals( ERROR_HANDLER)) {
262
return fErrorReporter.getErrorHandler();
263
} else if(propertyId.equals( ENTITY_RESOLVER)) {
264
return fEntityResolver;
265
} else if(propertyId.equals( GRAMMAR_POOL)) {
267
} else if(propertyId.equals( DTD_VALIDATOR)) {
270
throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, propertyId);
271
} // getProperty(String): Object
274
* Sets the value of a property. This method is called by the component
275
* manager any time after reset when a property changes value.
277
* <strong>Note:</strong> Components should silently ignore properties
278
* that do not affect the operation of the component.
280
* @param propertyId The property identifier.
281
* @param value The value of the property.
283
* @throws SAXNotRecognizedException The component should not throw
285
* @throws SAXNotSupportedException The component should not throw
288
public void setProperty(String propertyId, Object value)
289
throws XMLConfigurationException {
290
if(propertyId.equals( SYMBOL_TABLE)) {
291
fSymbolTable = (SymbolTable)value;
292
fDTDScanner.setProperty(propertyId, value);
293
fEntityManager.setProperty(propertyId, value);
294
} else if(propertyId.equals( ERROR_REPORTER)) {
295
fErrorReporter = (XMLErrorReporter)value;
296
// Add XML message formatter if there isn't one.
297
if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) {
298
XMLMessageFormatter xmft = new XMLMessageFormatter();
299
fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft);
300
fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft);
302
fDTDScanner.setProperty(propertyId, value);
303
fEntityManager.setProperty(propertyId, value);
304
} else if(propertyId.equals( ERROR_HANDLER)) {
305
fErrorReporter.setProperty(propertyId, value);
306
} else if(propertyId.equals( ENTITY_RESOLVER)) {
307
fEntityResolver = (XMLEntityResolver)value;
308
} else if(propertyId.equals( GRAMMAR_POOL)) {
309
fGrammarPool = (XMLGrammarPool)value;
311
throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, propertyId);
313
} // setProperty(String,Object)
316
* Returns the state of a feature.
318
* @param featureId The feature identifier.
320
* @throws XMLConfigurationException Thrown on configuration error.
322
public boolean getFeature(String featureId)
323
throws XMLConfigurationException {
324
if(featureId.equals( VALIDATION)) {
326
} else if(featureId.equals( WARN_ON_DUPLICATE_ATTDEF)) {
327
return fWarnDuplicateAttdef;
328
} else if(featureId.equals( NOTIFY_CHAR_REFS)) {
329
return fDTDScanner.getFeature(featureId);
331
throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId);
332
} //getFeature(String): boolean
335
* Set the locale to use for messages.
337
* @param locale The locale object to use for localization of messages.
339
* @exception XNIException Thrown if the parser does not support the
342
public void setLocale(Locale locale) {
344
} // setLocale(Locale)
346
/** Return the Locale the XMLGrammarLoader is using. */
347
public Locale getLocale() {
349
} // getLocale(): Locale
353
* Sets the error handler.
355
* @param errorHandler The error handler.
357
public void setErrorHandler(XMLErrorHandler errorHandler) {
358
fErrorReporter.setProperty(ERROR_HANDLER, errorHandler);
359
} // setErrorHandler(XMLErrorHandler)
361
/** Returns the registered error handler. */
362
public XMLErrorHandler getErrorHandler() {
363
return fErrorReporter.getErrorHandler();
364
} // getErrorHandler(): XMLErrorHandler
367
* Sets the entity resolver.
369
* @param entityResolver The new entity resolver.
371
public void setEntityResolver(XMLEntityResolver entityResolver) {
372
fEntityResolver = entityResolver;
373
} // setEntityResolver(XMLEntityResolver)
375
/** Returns the registered entity resolver. */
376
public XMLEntityResolver getEntityResolver() {
377
return fEntityResolver;
378
} // getEntityResolver(): XMLEntityResolver
381
* Returns a Grammar object by parsing the contents of the
382
* entity pointed to by source.
384
* @param source the location of the entity which forms
385
* the starting point of the grammar to be constructed.
386
* @throws IOException When a problem is encountered reading the entity
387
* XNIException When a condition arises (such as a FatalError) that requires parsing
388
* of the entity be terminated.
390
public Grammar loadGrammar(XMLInputSource source)
391
throws IOException, XNIException {
393
// First chance checking strict URI
394
String eid = XMLEntityManager.expandSystemId(source.getSystemId(), source.getBaseSystemId(), fStrictURI);
395
fDTDGrammar = new DTDGrammar(fSymbolTable, new XMLDTDDescription(source.getPublicId(), source.getSystemId(), source.getBaseSystemId(), eid, null));
396
fGrammarBucket = new DTDGrammarBucket();
397
fGrammarBucket.setStandalone(false);
398
fGrammarBucket.setActiveGrammar(fDTDGrammar);
399
// no reason to use grammar bucket's "put" method--we
400
// know which grammar it is, and we don't know the root name anyway...
402
// actually start the parsing!
404
fDTDScanner.setInputSource(source);
405
fDTDScanner.scanDTDExternalSubset(true);
406
} catch (EOFException e) {
407
// expected behaviour...
410
// Close all streams opened by the parser.
411
fEntityManager.closeReaders();
413
if(fDTDGrammar != null && fGrammarPool != null) {
414
fGrammarPool.cacheGrammars(XMLDTDDescription.XML_DTD, new Grammar[] {fDTDGrammar});
417
} // loadGrammar(XMLInputSource): Grammar
419
// reset all the components that we rely upon
420
protected void reset() {
423
fEntityManager.reset();
424
fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner());
427
} // class XMLDTDLoader