/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xerces.parsers;
import java.io.CharConversionException;
import java.io.IOException;
import org.apache.xerces.dom.DOMMessageFormatter;
import org.apache.xerces.impl.Constants;
import org.apache.xerces.util.EntityResolver2Wrapper;
import org.apache.xerces.util.EntityResolverWrapper;
import org.apache.xerces.util.ErrorHandlerWrapper;
import org.apache.xerces.util.SAXMessageFormatter;
import org.apache.xerces.util.SymbolTable;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.grammars.XMLGrammarPool;
import org.apache.xerces.xni.parser.XMLConfigurationException;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import org.apache.xerces.xni.parser.XMLErrorHandler;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.apache.xerces.xni.parser.XMLParseException;
import org.apache.xerces.xni.parser.XMLParserConfiguration;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.EntityResolver2;
import org.xml.sax.helpers.LocatorImpl;
/**
* This is the main Xerces DOM parser class. It uses the abstract DOM
* parser with a document scanner, a dtd scanner, and a validator, as
* well as a grammar pool.
*
* @author Arnaud Le Hors, IBM
* @author Andy Clark, IBM
*
* @version $Id: DOMParser.java 699892 2008-09-28 21:08:27Z mrglavas $
*/
public class DOMParser
extends AbstractDOMParser {
//
// Constants
//
// features
/** Feature identifier: EntityResolver2. */
protected static final String USE_ENTITY_RESOLVER2 =
Constants.SAX_FEATURE_PREFIX + Constants.USE_ENTITY_RESOLVER2_FEATURE;
// properties
/** Property identifier: symbol table. */
protected static final String SYMBOL_TABLE =
Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
/** Property identifier: XML grammar pool. */
protected static final String XMLGRAMMAR_POOL =
Constants.XERCES_PROPERTY_PREFIX+Constants.XMLGRAMMAR_POOL_PROPERTY;
/** Recognized properties. */
private static final String[] RECOGNIZED_PROPERTIES = {
SYMBOL_TABLE,
XMLGRAMMAR_POOL,
};
//
// Data
//
// features
/** Use EntityResolver2. */
protected boolean fUseEntityResolver2 = true;
//
// Constructors
//
/**
* Constructs a DOM parser using the specified parser configuration.
*/
public DOMParser(XMLParserConfiguration config) {
super(config);
} // <init>(XMLParserConfiguration)
/**
* Constructs a DOM parser using the dtd/xml schema parser configuration.
*/
public DOMParser() {
this(null, null);
} // <init>()
/**
* Constructs a DOM parser using the specified symbol table.
*/
public DOMParser(SymbolTable symbolTable) {
this(symbolTable, null);
} // <init>(SymbolTable)
/**
* Constructs a DOM parser using the specified symbol table and
* grammar pool.
*/
public DOMParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) {
super((XMLParserConfiguration)ObjectFactory.createObject(
"org.apache.xerces.xni.parser.XMLParserConfiguration",
"org.apache.xerces.parsers.XIncludeAwareParserConfiguration"
));
// set properties
fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);
if (symbolTable != null) {
fConfiguration.setProperty(SYMBOL_TABLE, symbolTable);
}
if (grammarPool != null) {
fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool);
}
} // <init>(SymbolTable,XMLGrammarPool)
//
// XMLReader methods
//
/**
* Parses the input source specified by the given system identifier.
* <p>
* This method is equivalent to the following:
* <pre>
* parse(new InputSource(systemId));
* </pre>
*
* @param systemId The system identifier (URI).
*
* @exception org.xml.sax.SAXException Throws exception on SAX error.
* @exception java.io.IOException Throws exception on i/o error.
*/
public void parse(String systemId) throws SAXException, IOException {
// parse document
XMLInputSource source = new XMLInputSource(null, systemId, null);
try {
parse(source);
}
// wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) {
Exception ex = e.getException();
if (ex == null || ex instanceof CharConversionException) {
// must be a parser exception; mine it for locator info and throw
// a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl();
locatorImpl.setPublicId(e.getPublicId());
locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber());
throw (ex == null) ?
new SAXParseException(e.getMessage(), locatorImpl) :
new SAXParseException(e.getMessage(), locatorImpl, ex);
}
if (ex instanceof SAXException) {
// why did we create an XMLParseException?
throw (SAXException)ex;
}
if (ex instanceof IOException) {
throw (IOException)ex;
}
throw new SAXException(ex);
}
catch (XNIException e) {
e.printStackTrace();
Exception ex = e.getException();
if (ex == null) {
throw new SAXException(e.getMessage());
}
if (ex instanceof SAXException) {
throw (SAXException)ex;
}
if (ex instanceof IOException) {
throw (IOException)ex;
}
throw new SAXException(ex);
}
} // parse(String)
/**
* parse
*
* @param inputSource
*
* @exception org.xml.sax.SAXException
* @exception java.io.IOException
*/
public void parse(InputSource inputSource)
throws SAXException, IOException {
// parse document
try {
XMLInputSource xmlInputSource =
new XMLInputSource(inputSource.getPublicId(),
inputSource.getSystemId(),
null);
xmlInputSource.setByteStream(inputSource.getByteStream());
xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
xmlInputSource.setEncoding(inputSource.getEncoding());
parse(xmlInputSource);
}
// wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) {
Exception ex = e.getException();
if (ex == null || ex instanceof CharConversionException) {
// must be a parser exception; mine it for locator info and throw
// a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl();
locatorImpl.setPublicId(e.getPublicId());
locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber());
throw (ex == null) ?
new SAXParseException(e.getMessage(), locatorImpl) :
new SAXParseException(e.getMessage(), locatorImpl, ex);
}
if (ex instanceof SAXException) {
// why did we create an XMLParseException?
throw (SAXException)ex;
}
if (ex instanceof IOException) {
throw (IOException)ex;
}
throw new SAXException(ex);
}
catch (XNIException e) {
Exception ex = e.getException();
if (ex == null) {
throw new SAXException(e.getMessage());
}
if (ex instanceof SAXException) {
throw (SAXException)ex;
}
if (ex instanceof IOException) {
throw (IOException)ex;
}
throw new SAXException(ex);
}
} // parse(InputSource)
/**
* Sets the resolver used to resolve external entities. The EntityResolver
* interface supports resolution of public and system identifiers.
*
* @param resolver The new entity resolver. Passing a null value will
* uninstall the currently installed resolver.
*/
public void setEntityResolver(EntityResolver resolver) {
try {
XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER);
if (fUseEntityResolver2 && resolver instanceof EntityResolver2) {
if (xer instanceof EntityResolver2Wrapper) {
EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer;
er2w.setEntityResolver((EntityResolver2) resolver);
}
else {
fConfiguration.setProperty(ENTITY_RESOLVER,
new EntityResolver2Wrapper((EntityResolver2) resolver));
}
}
else {
if (xer instanceof EntityResolverWrapper) {
EntityResolverWrapper erw = (EntityResolverWrapper) xer;
erw.setEntityResolver(resolver);
}
else {
fConfiguration.setProperty(ENTITY_RESOLVER,
new EntityResolverWrapper(resolver));
}
}
}
catch (XMLConfigurationException e) {
// do nothing
}
} // setEntityResolver(EntityResolver)
/**
* Return the current entity resolver.
*
* @return The current entity resolver, or null if none
* has been registered.
* @see #setEntityResolver
*/
public EntityResolver getEntityResolver() {
EntityResolver entityResolver = null;
try {
XMLEntityResolver xmlEntityResolver =
(XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER);
if (xmlEntityResolver != null) {
if (xmlEntityResolver instanceof EntityResolverWrapper) {
entityResolver =
((EntityResolverWrapper) xmlEntityResolver).getEntityResolver();
}
else if (xmlEntityResolver instanceof EntityResolver2Wrapper) {
entityResolver =
((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver();
}
}
}
catch (XMLConfigurationException e) {
// do nothing
}
return entityResolver;
} // getEntityResolver():EntityResolver
/**
* Allow an application to register an error event handler.
*
* <p>If the application does not register an error handler, all
* error events reported by the SAX parser will be silently
* ignored; however, normal processing may not continue. It is
* highly recommended that all SAX applications implement an
* error handler to avoid unexpected bugs.</p>
*
* <p>Applications may register a new or different handler in the
* middle of a parse, and the SAX parser must begin using the new
* handler immediately.</p>
*
* @param errorHandler The error handler.
* @exception java.lang.NullPointerException If the handler
* argument is null.
* @see #getErrorHandler
*/
public void setErrorHandler(ErrorHandler errorHandler) {
try {
XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER);
if (xeh instanceof ErrorHandlerWrapper) {
ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh;
ehw.setErrorHandler(errorHandler);
}
else {
fConfiguration.setProperty(ERROR_HANDLER,
new ErrorHandlerWrapper(errorHandler));
}
}
catch (XMLConfigurationException e) {
// do nothing
}
} // setErrorHandler(ErrorHandler)
/**
* Return the current error handler.
*
* @return The current error handler, or null if none
* has been registered.
* @see #setErrorHandler
*/
public ErrorHandler getErrorHandler() {
ErrorHandler errorHandler = null;
try {
XMLErrorHandler xmlErrorHandler =
(XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER);
if (xmlErrorHandler != null &&
xmlErrorHandler instanceof ErrorHandlerWrapper) {
errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler();
}
}
catch (XMLConfigurationException e) {
// do nothing
}
return errorHandler;
} // getErrorHandler():ErrorHandler
/**
* Set the state of any feature in a SAX2 parser. The parser
* might not recognize the feature, and if it does recognize
* it, it might not be able to fulfill the request.
*
* @param featureId The unique identifier (URI) of the feature.
* @param state The requested state of the feature (true or false).
*
* @exception SAXNotRecognizedException If the
* requested feature is not known.
* @exception SAXNotSupportedException If the
* requested feature is known, but the requested
* state is not supported.
*/
public void setFeature(String featureId, boolean state)
throws SAXNotRecognizedException, SAXNotSupportedException {
try {
// http://xml.org/sax/features/use-entity-resolver2
// controls whether the methods of an object implementing
// org.xml.sax.ext.EntityResolver2 will be used by the parser.
//
if (featureId.equals(USE_ENTITY_RESOLVER2)) {
if (state != fUseEntityResolver2) {
fUseEntityResolver2 = state;
// Refresh EntityResolver wrapper.
setEntityResolver(getEntityResolver());
}
return;
}
//
// Default handling
//
fConfiguration.setFeature(featureId, state);
}
catch (XMLConfigurationException e) {
String identifier = e.getIdentifier();
if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
throw new SAXNotRecognizedException(
SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
"feature-not-recognized", new Object [] {identifier}));
}
else {
throw new SAXNotSupportedException(
SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
"feature-not-supported", new Object [] {identifier}));
}
}
} // setFeature(String,boolean)
/**
* Query the state of a feature.
*
* Query the current state of any feature in a SAX2 parser. The
* parser might not recognize the feature.
*
* @param featureId The unique identifier (URI) of the feature
* being set.
* @return The current state of the feature.
* @exception org.xml.sax.SAXNotRecognizedException If the
* requested feature is not known.
* @exception SAXNotSupportedException If the
* requested feature is known but not supported.
*/
public boolean getFeature(String featureId)
throws SAXNotRecognizedException, SAXNotSupportedException {
try {
// http://xml.org/sax/features/use-entity-resolver2
// controls whether the methods of an object implementing
// org.xml.sax.ext.EntityResolver2 will be used by the parser.
//
if (featureId.equals(USE_ENTITY_RESOLVER2)) {
return fUseEntityResolver2;
}
//
// Default handling
//
return fConfiguration.getFeature(featureId);
}
catch (XMLConfigurationException e) {
String identifier = e.getIdentifier();
if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
throw new SAXNotRecognizedException(
SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
"feature-not-recognized", new Object [] {identifier}));
}
else {
throw new SAXNotSupportedException(
SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
"feature-not-supported", new Object [] {identifier}));
}
}
} // getFeature(String):boolean
/**
* Set the value of any property in a SAX2 parser. The parser
* might not recognize the property, and if it does recognize
* it, it might not support the requested value.
*
* @param propertyId The unique identifier (URI) of the property
* being set.
* @param value The value to which the property is being set.
*
* @exception SAXNotRecognizedException If the
* requested property is not known.
* @exception SAXNotSupportedException If the
* requested property is known, but the requested
* value is not supported.
*/
public void setProperty(String propertyId, Object value)
throws SAXNotRecognizedException, SAXNotSupportedException {
try {
fConfiguration.setProperty(propertyId, value);
}
catch (XMLConfigurationException e) {
String identifier = e.getIdentifier();
if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
throw new SAXNotRecognizedException(
SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
"property-not-recognized", new Object [] {identifier}));
}
else {
throw new SAXNotSupportedException(
SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
"property-not-supported", new Object [] {identifier}));
}
}
} // setProperty(String,Object)
/**
* Query the value of a property.
*
* Return the current value of a property in a SAX2 parser.
* The parser might not recognize the property.
*
* @param propertyId The unique identifier (URI) of the property
* being set.
* @return The current value of the property.
* @exception org.xml.sax.SAXNotRecognizedException If the
* requested property is not known.
* @exception SAXNotSupportedException If the
* requested property is known but not supported.
*/
public Object getProperty(String propertyId)
throws SAXNotRecognizedException, SAXNotSupportedException {
if (propertyId.equals(CURRENT_ELEMENT_NODE)) {
boolean deferred = false;
try {
deferred = getFeature(DEFER_NODE_EXPANSION);
}
catch (XMLConfigurationException e){
// ignore
}
if (deferred) {
throw new SAXNotSupportedException(
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"CannotQueryDeferredNode", null));
}
return (fCurrentNode!=null &&
fCurrentNode.getNodeType() == Node.ELEMENT_NODE)? fCurrentNode:null;
}
try {
return fConfiguration.getProperty(propertyId);
}
catch (XMLConfigurationException e) {
String identifier = e.getIdentifier();
if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) {
throw new SAXNotRecognizedException(
SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
"property-not-recognized", new Object [] {identifier}));
}
else {
throw new SAXNotSupportedException(
SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
"property-not-supported", new Object [] {identifier}));
}
}
} // getProperty(String):Object
/**
* Returns this parser's XMLParserConfiguration.
*/
public XMLParserConfiguration getXMLParserConfiguration() {
return fConfiguration;
} // getXMLParserConfiguration():XMLParserConfiguration
} // class DOMParser