1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.xerces.parsers;
19
20 import java.io.CharConversionException;
21 import java.io.IOException;
22
23 import org.apache.xerces.dom.DOMMessageFormatter;
24 import org.apache.xerces.impl.Constants;
25 import org.apache.xerces.util.EntityResolverWrapper;
26 import org.apache.xerces.util.EntityResolver2Wrapper;
27 import org.apache.xerces.util.ErrorHandlerWrapper;
28 import org.apache.xerces.util.SAXMessageFormatter;
29 import org.apache.xerces.util.SymbolTable;
30 import org.apache.xerces.xni.XNIException;
31 import org.apache.xerces.xni.grammars.XMLGrammarPool;
32 import org.apache.xerces.xni.parser.XMLConfigurationException;
33 import org.apache.xerces.xni.parser.XMLEntityResolver;
34 import org.apache.xerces.xni.parser.XMLErrorHandler;
35 import org.apache.xerces.xni.parser.XMLInputSource;
36 import org.apache.xerces.xni.parser.XMLParseException;
37 import org.apache.xerces.xni.parser.XMLParserConfiguration;
38 import org.w3c.dom.Node;
39 import org.xml.sax.EntityResolver;
40 import org.xml.sax.ErrorHandler;
41 import org.xml.sax.InputSource;
42 import org.xml.sax.SAXException;
43 import org.xml.sax.SAXNotRecognizedException;
44 import org.xml.sax.SAXNotSupportedException;
45 import org.xml.sax.SAXParseException;
46 import org.xml.sax.ext.EntityResolver2;
47 import org.xml.sax.helpers.LocatorImpl;
48
49 /**
50 * This is the main Xerces DOM parser class. It uses the abstract DOM
51 * parser with a document scanner, a dtd scanner, and a validator, as
52 * well as a grammar pool.
53 *
54 * @author Arnaud Le Hors, IBM
55 * @author Andy Clark, IBM
56 *
57 * @version $Id: DOMParser.java 542046 2007-05-27 22:48:02Z mrglavas $
58 */
59 public class DOMParser
60 extends AbstractDOMParser {
61
62 //
63 // Constants
64 //
65
66 // features
67
68 /** Feature identifier: EntityResolver2. */
69 protected static final String USE_ENTITY_RESOLVER2 =
70 Constants.SAX_FEATURE_PREFIX + Constants.USE_ENTITY_RESOLVER2_FEATURE;
71
72 // properties
73
74 /** Property identifier: symbol table. */
75 protected static final String SYMBOL_TABLE =
76 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
77
78 /** Property identifier: XML grammar pool. */
79 protected static final String XMLGRAMMAR_POOL =
80 Constants.XERCES_PROPERTY_PREFIX+Constants.XMLGRAMMAR_POOL_PROPERTY;
81
82 /** Recognized properties. */
83 private static final String[] RECOGNIZED_PROPERTIES = {
84 SYMBOL_TABLE,
85 XMLGRAMMAR_POOL,
86 };
87
88 //
89 // Data
90 //
91
92 // features
93
94 /** Use EntityResolver2. */
95 protected boolean fUseEntityResolver2 = true;
96
97 //
98 // Constructors
99 //
100
101 /**
102 * Constructs a DOM parser using the specified parser configuration.
103 */
104 public DOMParser(XMLParserConfiguration config) {
105 super(config);
106 } // <init>(XMLParserConfiguration)
107
108 /**
109 * Constructs a DOM parser using the dtd/xml schema parser configuration.
110 */
111 public DOMParser() {
112 this(null, null);
113 } // <init>()
114
115 /**
116 * Constructs a DOM parser using the specified symbol table.
117 */
118 public DOMParser(SymbolTable symbolTable) {
119 this(symbolTable, null);
120 } // <init>(SymbolTable)
121
122
123 /**
124 * Constructs a DOM parser using the specified symbol table and
125 * grammar pool.
126 */
127 public DOMParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) {
128 super((XMLParserConfiguration)ObjectFactory.createObject(
129 "org.apache.xerces.xni.parser.XMLParserConfiguration",
130 "org.apache.xerces.parsers.XIncludeAwareParserConfiguration"
131 ));
132
133 // set properties
134 fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);
135 if (symbolTable != null) {
136 fConfiguration.setProperty(SYMBOL_TABLE, symbolTable);
137 }
138 if (grammarPool != null) {
139 fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool);
140 }
141
142 } // <init>(SymbolTable,XMLGrammarPool)
143
144 //
145 // XMLReader methods
146 //
147
148 /**
149 * Parses the input source specified by the given system identifier.
150 * <p>
151 * This method is equivalent to the following:
152 * <pre>
153 * parse(new InputSource(systemId));
154 * </pre>
155 *
156 * @param systemId The system identifier (URI).
157 *
158 * @exception org.xml.sax.SAXException Throws exception on SAX error.
159 * @exception java.io.IOException Throws exception on i/o error.
160 */
161 public void parse(String systemId) throws SAXException, IOException {
162
163 // parse document
164 XMLInputSource source = new XMLInputSource(null, systemId, null);
165 try {
166 parse(source);
167 }
168
169 // wrap XNI exceptions as SAX exceptions
170 catch (XMLParseException e) {
171 Exception ex = e.getException();
172 if (ex == null || ex instanceof CharConversionException) {
173 // must be a parser exception; mine it for locator info and throw
174 // a SAXParseException
175 LocatorImpl locatorImpl = new LocatorImpl();
176 locatorImpl.setPublicId(e.getPublicId());
177 locatorImpl.setSystemId(e.getExpandedSystemId());
178 locatorImpl.setLineNumber(e.getLineNumber());
179 locatorImpl.setColumnNumber(e.getColumnNumber());
180 throw (ex == null) ?
181 new SAXParseException(e.getMessage(), locatorImpl) :
182 new SAXParseException(e.getMessage(), locatorImpl, ex);
183 }
184 if (ex instanceof SAXException) {
185 // why did we create an XMLParseException?
186 throw (SAXException)ex;
187 }
188 if (ex instanceof IOException) {
189 throw (IOException)ex;
190 }
191 throw new SAXException(ex);
192 }
193 catch (XNIException e) {
194 e.printStackTrace();
195 Exception ex = e.getException();
196 if (ex == null) {
197 throw new SAXException(e.getMessage());
198 }
199 if (ex instanceof SAXException) {
200 throw (SAXException)ex;
201 }
202 if (ex instanceof IOException) {
203 throw (IOException)ex;
204 }
205 throw new SAXException(ex);
206 }
207
208 } // parse(String)
209
210 /**
211 * parse
212 *
213 * @param inputSource
214 *
215 * @exception org.xml.sax.SAXException
216 * @exception java.io.IOException
217 */
218 public void parse(InputSource inputSource)
219 throws SAXException, IOException {
220
221 // parse document
222 try {
223 XMLInputSource xmlInputSource =
224 new XMLInputSource(inputSource.getPublicId(),
225 inputSource.getSystemId(),
226 null);
227 xmlInputSource.setByteStream(inputSource.getByteStream());
228 xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
229 xmlInputSource.setEncoding(inputSource.getEncoding());
230 parse(xmlInputSource);
231 }
232
233 // wrap XNI exceptions as SAX exceptions
234 catch (XMLParseException e) {
235 Exception ex = e.getException();
236 if (ex == null || ex instanceof CharConversionException) {
237 // must be a parser exception; mine it for locator info and throw
238 // a SAXParseException
239 LocatorImpl locatorImpl = new LocatorImpl();
240 locatorImpl.setPublicId(e.getPublicId());
241 locatorImpl.setSystemId(e.getExpandedSystemId());
242 locatorImpl.setLineNumber(e.getLineNumber());
243 locatorImpl.setColumnNumber(e.getColumnNumber());
244 throw (ex == null) ?
245 new SAXParseException(e.getMessage(), locatorImpl) :
246 new SAXParseException(e.getMessage(), locatorImpl, ex);
247 }
248 if (ex instanceof SAXException) {
249 // why did we create an XMLParseException?
250 throw (SAXException)ex;
251 }
252 if (ex instanceof IOException) {
253 throw (IOException)ex;
254 }
255 throw new SAXException(ex);
256 }
257 catch (XNIException e) {
258 Exception ex = e.getException();
259 if (ex == null) {
260 throw new SAXException(e.getMessage());
261 }
262 if (ex instanceof SAXException) {
263 throw (SAXException)ex;
264 }
265 if (ex instanceof IOException) {
266 throw (IOException)ex;
267 }
268 throw new SAXException(ex);
269 }
270
271 } // parse(InputSource)
272
273 /**
274 * Sets the resolver used to resolve external entities. The EntityResolver
275 * interface supports resolution of public and system identifiers.
276 *
277 * @param resolver The new entity resolver. Passing a null value will
278 * uninstall the currently installed resolver.
279 */
280 public void setEntityResolver(EntityResolver resolver) {
281
282 try {
283 XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER);
284 if (fUseEntityResolver2 && resolver instanceof EntityResolver2) {
285 if (xer instanceof EntityResolver2Wrapper) {
286 EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer;
287 er2w.setEntityResolver((EntityResolver2) resolver);
288 }
289 else {
290 fConfiguration.setProperty(ENTITY_RESOLVER,
291 new EntityResolver2Wrapper((EntityResolver2) resolver));
292 }
293 }
294 else {
295 if (xer instanceof EntityResolverWrapper) {
296 EntityResolverWrapper erw = (EntityResolverWrapper) xer;
297 erw.setEntityResolver(resolver);
298 }
299 else {
300 fConfiguration.setProperty(ENTITY_RESOLVER,
301 new EntityResolverWrapper(resolver));
302 }
303 }
304 }
305 catch (XMLConfigurationException e) {
306 // do nothing
307 }
308
309 } // setEntityResolver(EntityResolver)
310
311 /**
312 * Return the current entity resolver.
313 *
314 * @return The current entity resolver, or null if none
315 * has been registered.
316 * @see #setEntityResolver
317 */
318 public EntityResolver getEntityResolver() {
319
320 EntityResolver entityResolver = null;
321 try {
322 XMLEntityResolver xmlEntityResolver =
323 (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER);
324 if (xmlEntityResolver != null) {
325 if (xmlEntityResolver instanceof EntityResolverWrapper) {
326 entityResolver =
327 ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver();
328 }
329 else if (xmlEntityResolver instanceof EntityResolver2Wrapper) {
330 entityResolver =
331 ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver();
332 }
333 }
334 }
335 catch (XMLConfigurationException e) {
336 // do nothing
337 }
338 return entityResolver;
339
340 } // getEntityResolver():EntityResolver
341
342 /**
343 * Allow an application to register an error event handler.
344 *
345 * <p>If the application does not register an error handler, all
346 * error events reported by the SAX parser will be silently
347 * ignored; however, normal processing may not continue. It is
348 * highly recommended that all SAX applications implement an
349 * error handler to avoid unexpected bugs.</p>
350 *
351 * <p>Applications may register a new or different handler in the
352 * middle of a parse, and the SAX parser must begin using the new
353 * handler immediately.</p>
354 *
355 * @param errorHandler The error handler.
356 * @exception java.lang.NullPointerException If the handler
357 * argument is null.
358 * @see #getErrorHandler
359 */
360 public void setErrorHandler(ErrorHandler errorHandler) {
361
362 try {
363 XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER);
364 if (xeh instanceof ErrorHandlerWrapper) {
365 ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh;
366 ehw.setErrorHandler(errorHandler);
367 }
368 else {
369 fConfiguration.setProperty(ERROR_HANDLER,
370 new ErrorHandlerWrapper(errorHandler));
371 }
372 }
373 catch (XMLConfigurationException e) {
374 // do nothing
375 }
376
377 } // setErrorHandler(ErrorHandler)
378
379 /**
380 * Return the current error handler.
381 *
382 * @return The current error handler, or null if none
383 * has been registered.
384 * @see #setErrorHandler
385 */
386 public ErrorHandler getErrorHandler() {
387
388 ErrorHandler errorHandler = null;
389 try {
390 XMLErrorHandler xmlErrorHandler =
391 (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER);
392 if (xmlErrorHandler != null &&
393 xmlErrorHandler instanceof ErrorHandlerWrapper) {
394 errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler();
395 }
396 }
397 catch (XMLConfigurationException e) {
398 // do nothing
399 }
400 return errorHandler;
401
402 } // getErrorHandler():ErrorHandler
403
404 /**
405 * Set the state of any feature in a SAX2 parser. The parser
406 * might not recognize the feature, and if it does recognize
407 * it, it might not be able to fulfill the request.
408 *
409 * @param featureId The unique identifier (URI) of the feature.
410 * @param state The requested state of the feature (true or false).
411 *
412 * @exception SAXNotRecognizedException If the
413 * requested feature is not known.
414 * @exception SAXNotSupportedException If the
415 * requested feature is known, but the requested
416 * state is not supported.
417 */
418 public void setFeature(String featureId, boolean state)
419 throws SAXNotRecognizedException, SAXNotSupportedException {
420
421 try {
422
423 // http://xml.org/sax/features/use-entity-resolver2
424 // controls whether the methods of an object implementing
425 // org.xml.sax.ext.EntityResolver2 will be used by the parser.
426 //
427 if (featureId.equals(USE_ENTITY_RESOLVER2)) {
428 if (state != fUseEntityResolver2) {
429 fUseEntityResolver2 = state;
430 // Refresh EntityResolver wrapper.
431 setEntityResolver(getEntityResolver());
432 }
433 return;
434 }
435
436 //
437 // Default handling
438 //
439
440 fConfiguration.setFeature(featureId, state);
441 }
442 catch (XMLConfigurationException e) {
443 String identifier = e.getIdentifier();
444 if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
445 throw new SAXNotRecognizedException(
446 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
447 "feature-not-recognized", new Object [] {identifier}));
448 }
449 else {
450 throw new SAXNotSupportedException(
451 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
452 "feature-not-supported", new Object [] {identifier}));
453 }
454 }
455
456 } // setFeature(String,boolean)
457
458 /**
459 * Query the state of a feature.
460 *
461 * Query the current state of any feature in a SAX2 parser. The
462 * parser might not recognize the feature.
463 *
464 * @param featureId The unique identifier (URI) of the feature
465 * being set.
466 * @return The current state of the feature.
467 * @exception org.xml.sax.SAXNotRecognizedException If the
468 * requested feature is not known.
469 * @exception SAXNotSupportedException If the
470 * requested feature is known but not supported.
471 */
472 public boolean getFeature(String featureId)
473 throws SAXNotRecognizedException, SAXNotSupportedException {
474
475 try {
476
477 // http://xml.org/sax/features/use-entity-resolver2
478 // controls whether the methods of an object implementing
479 // org.xml.sax.ext.EntityResolver2 will be used by the parser.
480 //
481 if (featureId.equals(USE_ENTITY_RESOLVER2)) {
482 return fUseEntityResolver2;
483 }
484
485 //
486 // Default handling
487 //
488
489 return fConfiguration.getFeature(featureId);
490 }
491 catch (XMLConfigurationException e) {
492 String identifier = e.getIdentifier();
493 if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
494 throw new SAXNotRecognizedException(
495 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
496 "feature-not-recognized", new Object [] {identifier}));
497 }
498 else {
499 throw new SAXNotSupportedException(
500 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
501 "feature-not-supported", new Object [] {identifier}));
502 }
503 }
504
505 } // getFeature(String):boolean
506
507 /**
508 * Set the value of any property in a SAX2 parser. The parser
509 * might not recognize the property, and if it does recognize
510 * it, it might not support the requested value.
511 *
512 * @param propertyId The unique identifier (URI) of the property
513 * being set.
514 * @param value The value to which the property is being set.
515 *
516 * @exception SAXNotRecognizedException If the
517 * requested property is not known.
518 * @exception SAXNotSupportedException If the
519 * requested property is known, but the requested
520 * value is not supported.
521 */
522 public void setProperty(String propertyId, Object value)
523 throws SAXNotRecognizedException, SAXNotSupportedException {
524
525 try {
526 fConfiguration.setProperty(propertyId, value);
527 }
528 catch (XMLConfigurationException e) {
529 String identifier = e.getIdentifier();
530 if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
531 throw new SAXNotRecognizedException(
532 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
533 "property-not-recognized", new Object [] {identifier}));
534 }
535 else {
536 throw new SAXNotSupportedException(
537 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
538 "property-not-supported", new Object [] {identifier}));
539 }
540 }
541
542 } // setProperty(String,Object)
543
544 /**
545 * Query the value of a property.
546 *
547 * Return the current value of a property in a SAX2 parser.
548 * The parser might not recognize the property.
549 *
550 * @param propertyId The unique identifier (URI) of the property
551 * being set.
552 * @return The current value of the property.
553 * @exception org.xml.sax.SAXNotRecognizedException If the
554 * requested property is not known.
555 * @exception SAXNotSupportedException If the
556 * requested property is known but not supported.
557 */
558 public Object getProperty(String propertyId)
559 throws SAXNotRecognizedException, SAXNotSupportedException {
560
561 if (propertyId.equals(CURRENT_ELEMENT_NODE)) {
562 boolean deferred = false;
563 try {
564 deferred = getFeature(DEFER_NODE_EXPANSION);
565 }
566 catch (XMLConfigurationException e){
567 // ignore
568 }
569 if (deferred) {
570 throw new SAXNotSupportedException(
571 DOMMessageFormatter.formatMessage(
572 DOMMessageFormatter.DOM_DOMAIN,
573 "CannotQueryDeferredNode", null));
574 }
575 return (fCurrentNode!=null &&
576 fCurrentNode.getNodeType() == Node.ELEMENT_NODE)? fCurrentNode:null;
577 }
578
579 try {
580 return fConfiguration.getProperty(propertyId);
581 }
582 catch (XMLConfigurationException e) {
583 String identifier = e.getIdentifier();
584 if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
585 throw new SAXNotRecognizedException(
586 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
587 "property-not-recognized", new Object [] {identifier}));
588 }
589 else {
590 throw new SAXNotSupportedException(
591 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
592 "property-not-supported", new Object [] {identifier}));
593 }
594 }
595
596 } // getProperty(String):Object
597
598 /**
599 * Returns this parser's XMLParserConfiguration.
600 */
601 public XMLParserConfiguration getXMLParserConfiguration() {
602 return fConfiguration;
603 } // getXMLParserConfiguration():XMLParserConfiguration
604
605 } // class DOMParser