/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999-2002 The Apache Software Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
*
* This component requires the following features and properties from the * component manager that uses it: *
* Note: Components should silently ignore features * that do not affect the operation of the component. * * @param featureId The feature identifier. * @param state The state of the feature. * * @throws SAXNotRecognizedException The component should not throw * this exception. * @throws SAXNotSupportedException The component should not throw * this exception. */ public void setFeature(String featureId, boolean state) throws XMLConfigurationException { } // setFeature(String,boolean) /** * Returns a list of property identifiers that are recognized by * this component. This method may return null if no properties * are recognized by this component. */ public String[] getRecognizedProperties() { return (String[])(RECOGNIZED_PROPERTIES.clone()); } // getRecognizedProperties():String[] /** * Sets the value of a property. This method is called by the component * manager any time after reset when a property changes value. *
* Note: Components should silently ignore properties * that do not affect the operation of the component. * * @param propertyId The property identifier. * @param value The value of the property. * * @throws SAXNotRecognizedException The component should not throw * this exception. * @throws SAXNotSupportedException The component should not throw * this exception. */ public void setProperty(String propertyId, Object value) throws XMLConfigurationException { } // setProperty(String,Object) /** * Returns the default state for a feature, or null if this * component does not want to report a default value for this * feature. * * @param featureId The feature identifier. * * @since Xerces 2.2.0 */ public Boolean getFeatureDefault(String featureId) { for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { if (RECOGNIZED_FEATURES[i].equals(featureId)) { return FEATURE_DEFAULTS[i]; } } return null; } // getFeatureDefault(String):Boolean /** * Returns the default state for a property, or null if this * component does not want to report a default value for this * property. * * @param propertyId The property identifier. * * @since Xerces 2.2.0 */ public Object getPropertyDefault(String propertyId) { for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { return PROPERTY_DEFAULTS[i]; } } return null; } // getPropertyDefault(String):Object // // XMLDTDSource methods // /** * Sets the DTD handler. * * @param dtdHandler The DTD handler. */ public void setDTDHandler(XMLDTDHandler dtdHandler) { fDTDHandler = dtdHandler; } // setDTDHandler(XMLDTDHandler) /** * Returns the DTD handler. * * @return The DTD handler. */ public XMLDTDHandler getDTDHandler() { return fDTDHandler; } // getDTDHandler(): XMLDTDHandler // // XMLDTDContentModelSource methods // /** * Sets the DTD content model handler. * * @param dtdContentModelHandler The DTD content model handler. */ public void setDTDContentModelHandler(XMLDTDContentModelHandler dtdContentModelHandler) { fDTDContentModelHandler = dtdContentModelHandler; } // setDTDContentModelHandler(XMLDTDContentModelHandler) /** * Gets the DTD content model handler. * * @return dtdContentModelHandler The DTD content model handler. */ public XMLDTDContentModelHandler getDTDContentModelHandler() { return fDTDContentModelHandler; } // getDTDContentModelHandler(): XMLDTDContentModelHandler // // XMLDTDContentModelHandler and XMLDTDHandler methods // /** * The start of the DTD external subset. * * @param augs Additional information that may include infoset * augmentations. * * @throws XNIException Thrown by handler to signal an error. */ public void startExternalSubset(XMLResourceIdentifier identifier, Augmentations augs) throws XNIException { if(fDTDGrammar != null) fDTDGrammar.startExternalSubset(identifier, augs); if(fDTDHandler != null){ fDTDHandler.startExternalSubset(identifier, augs); } } /** * The end of the DTD external subset. * * @param augs Additional information that may include infoset * augmentations. * * @throws XNIException Thrown by handler to signal an error. */ public void endExternalSubset(Augmentations augs) throws XNIException { if(fDTDGrammar != null) fDTDGrammar.endExternalSubset(augs); if(fDTDHandler != null){ fDTDHandler.endExternalSubset(augs); } } /** * Check standalone entity reference. * Made static to make common between the validator and loader. * * @param name *@param grammar grammar to which entity belongs * @param tempEntityDecl empty entity declaration to put results in * @param errorReporter error reporter to send errors to * * @throws XNIException Thrown by application to signal an error. */ protected static void checkStandaloneEntityRef(String name, DTDGrammar grammar, XMLEntityDecl tempEntityDecl, XMLErrorReporter errorReporter) throws XNIException { // check VC: Standalone Document Declartion, entities references appear in the document. int entIndex = grammar.getEntityDeclIndex(name); if (entIndex > -1) { grammar.getEntityDecl(entIndex, tempEntityDecl); if (tempEntityDecl.inExternal) { errorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); } } } /** * A comment. * * @param text The text in the comment. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by application to signal an error. */ public void comment(XMLString text, Augmentations augs) throws XNIException { // call handlers if(fDTDGrammar != null) fDTDGrammar.comment(text, augs); if (fDTDHandler != null) { fDTDHandler.comment(text, augs); } } // comment(XMLString) /** * A processing instruction. Processing instructions consist of a * target name and, optionally, text data. The data is only meaningful * to the application. *
* Typically, a processing instruction's data will contain a series * of pseudo-attributes. These pseudo-attributes follow the form of * element attributes but are not parsed or presented * to the application as anything other than text. The application is * responsible for parsing the data. * * @param target The target. * @param data The data or null if none specified. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void processingInstruction(String target, XMLString data, Augmentations augs) throws XNIException { // call handlers if(fDTDGrammar != null) fDTDGrammar.processingInstruction(target, data, augs); if (fDTDHandler != null) { fDTDHandler.processingInstruction(target, data, augs); } } // processingInstruction(String,XMLString) // // XMLDTDHandler methods // /** * The start of the DTD. * * @param locator The document locator, or null if the document * location cannot be reported during the parsing of * the document DTD. However, it is strongly * recommended that a locator be supplied that can * at least report the base system identifier of the * DTD. * @param augs Additional information that may include infoset * augmentations. * * @throws XNIException Thrown by handler to signal an error. */ public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException { // initialize state fNDataDeclNotations.clear(); fDTDElementDecls.removeAllElements(); // the grammar bucket's DTDGrammar will now be the // one we want, whether we're constructing it or not. // if we're not constructing it, then we should not have a reference // to it! if( !fGrammarBucket.getActiveGrammar().isImmutable()) { fDTDGrammar = fGrammarBucket.getActiveGrammar(); } // call handlers if(fDTDGrammar != null ) fDTDGrammar.startDTD(locator, augs); if (fDTDHandler != null) { fDTDHandler.startDTD(locator, augs); } } // startDTD(XMLLocator) /** * Characters within an IGNORE conditional section. * * @param text The ignored text. * @param augs Additional information that may include infoset * augmentations. * * @throws XNIException Thrown by handler to signal an error. */ public void ignoredCharacters(XMLString text, Augmentations augs) throws XNIException { // ignored characters in DTD if(fDTDGrammar != null ) fDTDGrammar.ignoredCharacters(text, augs); if (fDTDHandler != null) { fDTDHandler.ignoredCharacters(text, augs); } } /** * Notifies of the presence of a TextDecl line in an entity. If present, * this method will be called immediately following the startParameterEntity call. *
* Note: This method is only called for external
* parameter entities referenced in the DTD.
*
* @param version The XML version, or null if not specified.
* @param encoding The IANA encoding name of the entity.
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void textDecl(String version, String encoding, Augmentations augs) throws XNIException {
// call handlers
if(fDTDGrammar != null )
fDTDGrammar.textDecl(version, encoding, augs);
if (fDTDHandler != null) {
fDTDHandler.textDecl(version, encoding, augs);
}
}
/**
* This method notifies of the start of a parameter entity. The parameter
* entity name start with a '%' character.
*
* @param name The name of the parameter entity.
* @param identifier The resource identifier.
* @param encoding The auto-detected IANA encoding name of the entity
* stream. This value will be null in those situations
* where the entity encoding is not auto-detected (e.g.
* internal parameter entities).
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void startParameterEntity(String name,
XMLResourceIdentifier identifier,
String encoding,
Augmentations augs) throws XNIException {
if (fPerformValidation && fDTDGrammar != null &&
fGrammarBucket.getStandalone()) {
checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter);
}
// call handlers
if(fDTDGrammar != null )
fDTDGrammar.startParameterEntity(name, identifier, encoding, augs);
if (fDTDHandler != null) {
fDTDHandler.startParameterEntity(name, identifier, encoding, augs);
}
}
/**
* This method notifies the end of a parameter entity. Parameter entity
* names begin with a '%' character.
*
* @param name The name of the parameter entity.
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void endParameterEntity(String name, Augmentations augs) throws XNIException {
// call handlers
if(fDTDGrammar != null )
fDTDGrammar.endParameterEntity(name, augs);
if (fDTDHandler != null) {
fDTDHandler.endParameterEntity(name, augs);
}
}
/**
* An element declaration.
*
* @param name The name of the element.
* @param contentModel The element content model.
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void elementDecl(String name, String contentModel, Augmentations augs)
throws XNIException {
//check VC: Unique Element Declaration
if (fValidation) {
if (fDTDElementDecls.contains(name)) {
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"MSG_ELEMENT_ALREADY_DECLARED",
new Object[]{ name},
XMLErrorReporter.SEVERITY_ERROR);
}
else {
fDTDElementDecls.addElement(name);
}
}
// call handlers
if(fDTDGrammar != null )
fDTDGrammar.elementDecl(name, contentModel, augs);
if (fDTDHandler != null) {
fDTDHandler.elementDecl(name, contentModel, augs);
}
} // elementDecl(String,String)
/**
* The start of an attribute list.
*
* @param elementName The name of the element that this attribute
* list is associated with.
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void startAttlist(String elementName, Augmentations augs)
throws XNIException {
// call handlers
if(fDTDGrammar != null )
fDTDGrammar.startAttlist(elementName, augs);
if (fDTDHandler != null) {
fDTDHandler.startAttlist(elementName, augs);
}
} // startAttlist(String)
/**
* An attribute declaration.
*
* @param elementName The name of the element that this attribute
* is associated with.
* @param attributeName The name of the attribute.
* @param type The attribute type. This value will be one of
* the following: "CDATA", "ENTITY", "ENTITIES",
* "ENUMERATION", "ID", "IDREF", "IDREFS",
* "NMTOKEN", "NMTOKENS", or "NOTATION".
* @param enumeration If the type has the value "ENUMERATION" or
* "NOTATION", this array holds the allowed attribute
* values; otherwise, this array is null.
* @param defaultType The attribute default type. This value will be
* one of the following: "#FIXED", "#IMPLIED",
* "#REQUIRED", or null.
* @param defaultValue The attribute default value, or null if no
* default value is specified.
* @param nonNormalizedDefaultValue The attribute default value with no normalization
* performed, or null if no default value is specified.
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void attributeDecl(String elementName, String attributeName,
String type, String[] enumeration,
String defaultType, XMLString defaultValue,
XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {
if (type != XMLSymbols.fCDATASymbol && defaultValue != null) {
normalizeDefaultAttrValue(defaultValue);
}
if (fValidation) {
boolean duplicateAttributeDef = false ;
//Get Grammar index to grammar array
DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar:fGrammarBucket.getActiveGrammar());
int elementIndex = grammar.getElementDeclIndex( elementName);
if (grammar.getAttributeDeclIndex(elementIndex, attributeName) != -1) {
//more than one attribute definition is provided for the same attribute of a given element type.
duplicateAttributeDef = true ;
//this feature works only when validation is true.
if(fWarnDuplicateAttdef){
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"MSG_DUPLICATE_ATTRIBUTE_DEFINITION",
new Object[]{ elementName, attributeName },
XMLErrorReporter.SEVERITY_WARNING );
}
}
//
// a) VC: One ID per Element Type, If duplicate ID attribute
// b) VC: ID attribute Default. if there is a declareared attribute
// default for ID it should be of type #IMPLIED or #REQUIRED
if (type == XMLSymbols.fIDSymbol) {
if (defaultValue != null && defaultValue.length != 0) {
if (defaultType == null ||
!(defaultType == XMLSymbols.fIMPLIEDSymbol ||
defaultType == XMLSymbols.fREQUIREDSymbol)) {
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"IDDefaultTypeInvalid",
new Object[]{ attributeName},
XMLErrorReporter.SEVERITY_ERROR);
}
}
if (!fTableOfIDAttributeNames.containsKey(elementName)) {
fTableOfIDAttributeNames.put(elementName, attributeName);
}
else {
//we should not report an error, when there is duplicate attribute definition for given element type
//according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given
//element type, the first declaration is binding and later declaration are *ignored*. So processor should
//ignore the second declarations, however an application would be warned of the duplicate attribute defintion
// if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true,
// one typical case where this could be a problem, when any XML file
// provide the ID type information through internal subset so that it is available to the parser which read
//only internal subset. Now that attribute declaration(ID Type) can again be part of external parsed entity
//referenced. At that time if parser doesn't make this distinction it will throw an error for VC One ID per
//Element Type, which (second defintion) actually should be ignored. Application behavior may differ on the
//basis of error or warning thrown. - nb.
if(!duplicateAttributeDef){
String previousIDAttributeName = (String)fTableOfIDAttributeNames.get( elementName );//rule a)
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"MSG_MORE_THAN_ONE_ID_ATTRIBUTE",
new Object[]{ elementName, previousIDAttributeName, attributeName},
XMLErrorReporter.SEVERITY_ERROR);
}
}
}
//
// VC: One Notation Per Element Type, should check if there is a
// duplicate NOTATION attribute
if (type == XMLSymbols.fNOTATIONSymbol) {
// VC: Notation Attributes: all notation names in the
// (attribute) declaration must be declared.
for (int i=0; istartGroup()
.
*
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*
* @see #startGroup
*/
public void pcdata(Augmentations augs) {
fMixed = true;
if(fDTDGrammar != null)
fDTDGrammar.pcdata(augs);
if (fDTDContentModelHandler != null) {
fDTDContentModelHandler.pcdata(augs);
}
} // pcdata()
/**
* A referenced element in a mixed or children content model.
*
* @param elementName The name of the referenced element.
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void element(String elementName, Augmentations augs) throws XNIException {
// check VC: No duplicate Types, in a single mixed-content declaration
if (fMixed && fValidation) {
if (fMixedElementTypes.contains(elementName)) {
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"DuplicateTypeInMixedContent",
new Object[]{fDTDElementDeclName, elementName},
XMLErrorReporter.SEVERITY_ERROR);
}
else {
fMixedElementTypes.addElement(elementName);
}
}
// call handlers
if(fDTDGrammar != null)
fDTDGrammar.element(elementName, augs);
if (fDTDContentModelHandler != null) {
fDTDContentModelHandler.element(elementName, augs);
}
} // childrenElement(String)
/**
* The separator between choices or sequences of a mixed or children
* content model.
*
* @param separator The type of children separator.
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*
* @see #SEPARATOR_CHOICE
* @see #SEPARATOR_SEQUENCE
*/
public void separator(short separator, Augmentations augs)
throws XNIException {
// call handlers
if(fDTDGrammar != null)
fDTDGrammar.separator(separator, augs);
if (fDTDContentModelHandler != null) {
fDTDContentModelHandler.separator(separator, augs);
}
} // separator(short)
/**
* The occurrence count for a child in a children content model or
* for the mixed content model group.
*
* @param occurrence The occurrence count for the last element
* or group.
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*
* @see #OCCURS_ZERO_OR_ONE
* @see #OCCURS_ZERO_OR_MORE
* @see #OCCURS_ONE_OR_MORE
*/
public void occurrence(short occurrence, Augmentations augs)
throws XNIException {
// call handlers
if(fDTDGrammar != null)
fDTDGrammar.occurrence(occurrence, augs);
if (fDTDContentModelHandler != null) {
fDTDContentModelHandler.occurrence(occurrence, augs);
}
} // occurrence(short)
/**
* The end of a group for mixed or children content models.
*
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void endGroup(Augmentations augs) throws XNIException {
// call handlers
if(fDTDGrammar != null)
fDTDGrammar.endGroup(augs);
if (fDTDContentModelHandler != null) {
fDTDContentModelHandler.endGroup(augs);
}
} // endGroup()
/**
* The end of a content model.
*
* @param augs Additional information that may include infoset
* augmentations.
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void endContentModel(Augmentations augs) throws XNIException {
// call handlers
if(fDTDGrammar != null)
fDTDGrammar.endContentModel(augs);
if (fDTDContentModelHandler != null) {
fDTDContentModelHandler.endContentModel(augs);
}
} // endContentModel()
//
// Private methods
//
/**
* Normalize the attribute value of a non CDATA default attribute
* collapsing sequences of space characters (x20)
*
* @param value The value to normalize
* @return Whether the value was changed or not.
*/
private boolean normalizeDefaultAttrValue(XMLString value) {
int oldLength = value.length;
boolean skipSpace = true; // skip leading spaces
int current = value.offset;
int end = value.offset + value.length;
for (int i = value.offset; i < end; i++) {
if (value.ch[i] == ' ') {
if (!skipSpace) {
// take the first whitespace as a space and skip the others
value.ch[current++] = ' ';
skipSpace = true;
}
else {
// just skip it.
}
}
else {
// simply shift non space chars if needed
if (current != i) {
value.ch[current] = value.ch[i];
}
current++;
skipSpace = false;
}
}
if (current != end) {
if (skipSpace) {
// if we finished on a space trim it
current--;
}
// set the new value length
value.length = current - value.offset;
return true;
}
return false;
}
protected boolean isValidNmtoken(String nmtoken) {
return XMLChar.isValidNmtoken(nmtoken);
} // isValidNmtoken(String): boolean
protected boolean isValidName(String name) {
return XMLChar.isValidName(name);
} // isValidName(String): boolean
} // class XMLDTDProcessor