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