| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2001 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) 2001, International |
| * Business Machines, Inc., http://www.ibm.com . For more information |
| * on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| /* |
| * $Log$ |
| * Revision 1.5 2002/02/26 14:26:10 tng |
| * [Bug 6672] SAXValidator results in an access violation when validating against schema with empty element that has default value. |
| * |
| * Revision 1.4 2002/02/25 21:24:31 tng |
| * Schema Fix: Ensure no invalid uri index for UPA checking. |
| * |
| * Revision 1.3 2002/02/25 21:18:18 tng |
| * Schema Fix: Ensure no invalid uri index for UPA checking. |
| * |
| * Revision 1.2 2002/02/07 16:41:29 knoaman |
| * Fix for xsi:type. |
| * |
| * Revision 1.1.1.1 2002/02/01 22:22:47 peiyongz |
| * sane_include |
| * |
| * Revision 1.26 2001/11/21 18:05:09 tng |
| * Schema Fix: Check both XMLAttDef::Fixed and XMLAttDef::Required_And_Fixed for default values. |
| * |
| * Revision 1.25 2001/11/21 14:30:13 knoaman |
| * Fix for UPA checking. |
| * |
| * Revision 1.24 2001/11/20 20:32:52 knoaman |
| * Bypass validating element's simple content if it's empty and element is nillable. |
| * |
| * Revision 1.23 2001/11/13 13:25:08 tng |
| * Deprecate function XMLValidator::checkRootElement. |
| * |
| * Revision 1.22 2001/11/09 18:10:58 tng |
| * Schema Fix: should concatenate all characters for validation. |
| * |
| * Revision 1.21 2001/10/23 13:35:36 tng |
| * Schema fix: Resolve notation prefix to an URI. |
| * |
| * Revision 1.20 2001/10/12 20:44:01 tng |
| * Schema Fix: Notation Uri Binding. |
| * |
| * Revision 1.19 2001/10/04 15:08:56 knoaman |
| * Add support for circular import. |
| * |
| * Revision 1.18 2001/09/10 14:06:22 tng |
| * Schema: AnyAttribute support in Scanner and Validator. |
| * |
| * Revision 1.17 2001/09/05 20:49:11 knoaman |
| * Fix for complexTypes with mixed content model. |
| * |
| * Revision 1.16 2001/08/30 15:47:46 tng |
| * Schema: xsi:type fixes |
| * |
| * Revision 1.15 2001/08/29 20:52:35 tng |
| * Schema: xsi:type support |
| * |
| * Revision 1.14 2001/08/28 19:20:54 tng |
| * Schema: xsi:type support |
| * |
| * Revision 1.13 2001/08/21 16:06:11 tng |
| * Schema: Unique Particle Attribution Constraint Checking. |
| * |
| * Revision 1.12 2001/08/09 15:23:16 knoaman |
| * add support for <anyAttribute> declaration. |
| * |
| * Revision 1.11 2001/07/26 17:04:11 tng |
| * Schema: Process should stop after fatal error, and user throws need to be rethrown. |
| * |
| * Revision 1.10 2001/07/24 21:23:40 tng |
| * Schema: Use DatatypeValidator for ID/IDREF/ENTITY/ENTITIES/NOTATION. |
| * |
| * Revision 1.9 2001/07/11 21:39:58 peiyongz |
| * fix to normalizeWhiteSpace: synchronize fDatatypeBuffer with toFill. |
| * |
| * Revision 1.8 2001/05/17 18:14:32 tng |
| * Schema Fix: if nillable, it's an error to have default value |
| * |
| * Revision 1.7 2001/05/11 15:17:46 tng |
| * Schema: Nillable fixes. |
| * |
| * Revision 1.6 2001/05/11 13:27:37 tng |
| * Copyright update. |
| * |
| * Revision 1.5 2001/05/10 17:49:42 tng |
| * Schema: SchemaValidator fixes |
| * |
| * Revision 1.4 2001/05/03 20:34:44 tng |
| * Schema: SchemaValidator update |
| * |
| * Revision 1.3 2001/04/19 18:17:39 tng |
| * Schema: SchemaValidator update, and use QName in Content Model |
| * |
| * Revision 1.2 2001/03/30 16:35:19 tng |
| * Schema: Whitespace normalization. |
| * |
| * Revision 1.1 2001/03/21 21:56:33 tng |
| * Schema: Add Schema Grammar, Schema Validator, and split the DTDValidator into DTDValidator, DTDScanner, and DTDGrammar. |
| * |
| */ |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #include <xercesc/util/Janitor.hpp> |
| #include <xercesc/util/KVStringPair.hpp> |
| #include <xercesc/framework/XMLDocumentHandler.hpp> |
| #include <xercesc/internal/XMLReader.hpp> |
| #include <xercesc/internal/XMLScanner.hpp> |
| #include <xercesc/validators/datatype/DatatypeValidatorFactory.hpp> |
| #include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp> |
| #include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp> |
| #include <xercesc/validators/datatype/ListDatatypeValidator.hpp> |
| #include <xercesc/validators/datatype/UnionDatatypeValidator.hpp> |
| #include <xercesc/validators/datatype/ENTITYDatatypeValidator.hpp> |
| #include <xercesc/validators/datatype/IDDatatypeValidator.hpp> |
| #include <xercesc/validators/datatype/IDREFDatatypeValidator.hpp> |
| #include <xercesc/validators/schema/SchemaSymbols.hpp> |
| #include <xercesc/validators/schema/SchemaValidator.hpp> |
| #include <xercesc/validators/schema/SubstitutionGroupComparator.hpp> |
| |
| // --------------------------------------------------------------------------- |
| // SchemaValidator: Constructors and Destructor |
| // --------------------------------------------------------------------------- |
| SchemaValidator::SchemaValidator(XMLErrorReporter* const errReporter) : |
| |
| XMLValidator(errReporter) |
| , fGrammarResolver(0) |
| , fSchemaGrammar(0) |
| , fTrailing(false) |
| , fXsiType(0) |
| , fXsiTypeValidator(0) |
| , fNil(false) |
| { |
| } |
| |
| SchemaValidator::~SchemaValidator() |
| { |
| delete fXsiType; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // SchemaValidator: Implementation of the XMLValidator interface |
| // --------------------------------------------------------------------------- |
| int SchemaValidator::checkContent (XMLElementDecl* const elemDecl |
| , QName** const children |
| , const unsigned int childCount) |
| { |
| // |
| // Look up the element id in our element decl pool. This will get us |
| // the element decl in our own way of looking at them. |
| // |
| if (!elemDecl) |
| ThrowXML(RuntimeException, XMLExcepts::Val_InvalidElemId); |
| |
| // |
| // Get the content spec type of this element. This will tell us what |
| // to do to validate it. |
| // |
| const SchemaElementDecl::ModelTypes modelType = ((SchemaElementDecl*) elemDecl)->getModelType(); |
| |
| if (modelType == SchemaElementDecl::Empty) |
| { |
| // |
| // We can do this one here. It cannot have any children. If it does |
| // we return 0 as the index of the first bad child. |
| // |
| if (childCount) |
| return 0; |
| } |
| else if (modelType == SchemaElementDecl::Any) |
| { |
| // We pass no judgement on this one, anything goes |
| } |
| else if ((modelType == SchemaElementDecl::Mixed_Simple) |
| || (modelType == SchemaElementDecl::Mixed_Complex) |
| || (modelType == SchemaElementDecl::Children)) |
| { |
| // if nillable, it's an error to have value |
| // XML Schema REC: Validation Rule: Element Locally Valid (Element) |
| // 3.2.1 The element information item must have no |
| // character or element information item [children]. |
| // |
| if (fNil) { |
| if (childCount > 0 || XMLString::compareString(fDatatypeBuffer.getRawBuffer(), XMLUni::fgZeroLenString)) |
| emitError(XMLValid::NilAttrNotEmpty, elemDecl->getFullName()); |
| |
| } |
| else { |
| // Get the element's content model or fault it in |
| XMLContentModel* elemCM = elemDecl->getContentModel(); |
| |
| // Ask it to validate and return its return |
| unsigned int emptyNS = getScanner()->getEmptyNamespaceId(); |
| int result = elemCM->validateContent(children, childCount, emptyNS); |
| if (result != -1) { |
| result = elemCM->validateContentSpecial(children |
| , childCount |
| , emptyNS |
| , fGrammarResolver |
| , getScanner()->getURIStringPool()); |
| } |
| return result; |
| } |
| } |
| else if (modelType == SchemaElementDecl::Simple) |
| { |
| if (childCount > 0) { |
| emitError(XMLValid::SimpleTypeHasChild, elemDecl->getFullName()); |
| } else { |
| try { |
| DatatypeValidator* fCurrentDV = ((SchemaElementDecl*)elemDecl)->getDatatypeValidator(); |
| // If there is xsi:type validator, substitute it. |
| if (fXsiTypeValidator) { |
| fCurrentDV = fXsiTypeValidator; |
| fXsiTypeValidator = 0; |
| } |
| if (!fCurrentDV) { |
| emitError(XMLValid::NoDatatypeValidatorForSimpleType, elemDecl->getFullName()); |
| } else { |
| XMLCh* value = fDatatypeBuffer.getRawBuffer(); |
| XMLCh* elemDefaultValue = ((SchemaElementDecl*) elemDecl)->getDefaultValue(); |
| |
| if (elemDefaultValue) { |
| // a default value was specified |
| |
| // if nillable, it's an error to have default value |
| if (fNil) |
| emitError(XMLValid::NilAttrNotEmpty, elemDecl->getFullName()); |
| |
| if (!XMLString::compareString(value, XMLUni::fgZeroLenString)) { |
| // if this element didn't specified any value |
| // use default value |
| if (getScanner()->getDocHandler()) |
| getScanner()->getDocHandler()->docCharacters(elemDefaultValue, XMLString::stringLen(elemDefaultValue), false); |
| } |
| else { |
| // this element has specified some value |
| // if the flag is FIXED, then this value must be same as default value |
| if ((((SchemaElementDecl*)elemDecl)->getMiscFlags() == SchemaSymbols::FIXED) != 0) { |
| if (fCurrentDV->compare(value, elemDefaultValue) != 0 ) |
| emitError(XMLValid::FixedDifferentFromActual, elemDecl->getFullName()); |
| } |
| |
| // if nillable, it's an error to have value |
| if (fNil) |
| emitError(XMLValid::NilAttrNotEmpty, elemDecl->getFullName()); |
| else |
| fCurrentDV->validate(value); |
| } |
| } |
| else { |
| // no default value, then check nillable |
| if (!XMLString::compareString(value, XMLUni::fgZeroLenString)) { |
| if ((((SchemaElementDecl*)elemDecl)->getMiscFlags() & SchemaSymbols::NILLABLE) == 0) |
| fCurrentDV->validate(value); |
| } |
| else if (fNil) { |
| emitError(XMLValid::NilAttrNotEmpty, elemDecl->getFullName()); |
| } |
| else |
| fCurrentDV->validate(value); |
| } |
| } |
| } catch (InvalidDatatypeValueException idve) { |
| emitError (XMLValid::DatatypeError, idve.getType(), idve.getMessage()); |
| } |
| catch (InvalidDatatypeFacetException idve) { |
| emitError (XMLValid::DatatypeError, idve.getType(), idve.getMessage()); |
| } |
| catch (...) { |
| emitError(XMLValid::GenericError); |
| throw; |
| } |
| } |
| } |
| else |
| { |
| ThrowXML(RuntimeException, XMLExcepts::CM_UnknownCMType); |
| } |
| |
| fDatatypeBuffer.reset(); |
| fNil = false; |
| fTrailing=false; |
| |
| // Went ok, so return success |
| return -1; |
| } |
| |
| void SchemaValidator::faultInAttr (XMLAttr& toFill, const XMLAttDef& attDef) const |
| { |
| // |
| // At this level, we cannot set the URI id. So we just set it to zero |
| // and leave it at that. The scanner, who called us, will look at the |
| // prefix we stored (if any), resolve it, and store the URL id if any. |
| // |
| SchemaAttDef* schemaAttDef = (SchemaAttDef*) &attDef; |
| QName* attName = schemaAttDef->getAttName(); |
| |
| toFill.set |
| ( |
| attName->getURI() |
| , attName->getLocalPart() |
| , attName->getPrefix() |
| , schemaAttDef->getValue() |
| , schemaAttDef->getType() |
| ); |
| } |
| |
| void SchemaValidator::reset() |
| { |
| fTrailing = false; |
| delete fXsiType; |
| fXsiType = 0; |
| fXsiTypeValidator = 0; |
| fNil = false; |
| fDatatypeBuffer.reset(); |
| } |
| |
| bool SchemaValidator::requiresNamespaces() const |
| { |
| return true; |
| } |
| |
| void SchemaValidator::validateAttrValue (const XMLAttDef* attDef |
| , const XMLCh* const attrValue) |
| { |
| // |
| // Get quick refs to lot of the stuff in the passed objects in |
| // order to simplify the code below, which will reference them very |
| // often. |
| // |
| XMLAttDef::AttTypes type = attDef->getType(); |
| const XMLAttDef::DefAttTypes defType = attDef->getDefaultType(); |
| const XMLCh* const fullName = attDef->getFullName(); |
| |
| // |
| // If the default type is fixed, then make sure the passed value maps |
| // to the fixed value. |
| // |
| if (defType == XMLAttDef::Fixed || defType == XMLAttDef::Required_And_Fixed) |
| { |
| const XMLCh* const valueText = attDef->getValue(); |
| if (XMLString::compareString(attrValue, valueText)) |
| emitError(XMLValid::NotSameAsFixedValue, fullName, attrValue, valueText); |
| } |
| |
| // An empty string cannot be valid for non_CDATA any of the other types |
| if (!attrValue[0] && type != XMLAttDef::Simple) |
| { |
| emitError(XMLValid::InvalidEmptyAttValue, fullName); |
| return; |
| } |
| |
| DatatypeValidator* attDefDV = ((SchemaAttDef*) attDef)->getDatatypeValidator(); |
| if (!attDefDV) { |
| emitError(XMLValid::NoDatatypeValidatorForAttribute, fullName); |
| } |
| else { |
| try { |
| DatatypeValidator::ValidatorType attDefDVType = attDefDV->getType(); |
| |
| // set up the entitydeclpool in ENTITYDatatypeValidator |
| // and the idreflist in ID/IDREFDatatypeValidator |
| |
| if (attDefDVType == DatatypeValidator::List) { |
| DatatypeValidator* itemDTV = ((ListDatatypeValidator*)attDefDV)->getItemTypeDTV(); |
| DatatypeValidator::ValidatorType itemDTVType = itemDTV->getType(); |
| if (itemDTVType == DatatypeValidator::ENTITY) |
| ((ENTITYDatatypeValidator*)itemDTV)->setEntityDeclPool(getScanner()->getEntityDeclPool()); |
| else if (itemDTVType == DatatypeValidator::ID) |
| ((IDDatatypeValidator*)itemDTV)->setIDRefList(getScanner()->getIDRefList()); |
| else if (itemDTVType == DatatypeValidator::IDREF) |
| ((IDREFDatatypeValidator*)itemDTV)->setIDRefList(getScanner()->getIDRefList()); |
| } |
| else if (attDefDVType == DatatypeValidator::Union) { |
| RefVectorOf<DatatypeValidator>* memberDTV = ((UnionDatatypeValidator*)attDefDV)->getMemberTypeValidators(); |
| unsigned int memberTypeNumber = memberDTV->size(); |
| for ( unsigned int memberIndex = 0; memberIndex < memberTypeNumber; ++memberIndex) |
| { |
| DatatypeValidator::ValidatorType memberDTVType = memberDTV->elementAt(memberIndex)->getType(); |
| if (memberDTVType == DatatypeValidator::ENTITY) |
| ((ENTITYDatatypeValidator*)memberDTV->elementAt(memberIndex))->setEntityDeclPool(getScanner()->getEntityDeclPool()); |
| else if (memberDTVType == DatatypeValidator::ID) |
| ((IDDatatypeValidator*)memberDTV->elementAt(memberIndex))->setIDRefList(getScanner()->getIDRefList()); |
| else if (memberDTVType == DatatypeValidator::IDREF) |
| ((IDREFDatatypeValidator*)memberDTV->elementAt(memberIndex))->setIDRefList(getScanner()->getIDRefList()); |
| } |
| } |
| else if (attDefDVType == DatatypeValidator::ENTITY) |
| ((ENTITYDatatypeValidator*)attDefDV)->setEntityDeclPool(getScanner()->getEntityDeclPool()); |
| else if (attDefDVType == DatatypeValidator::ID) |
| ((IDDatatypeValidator*)attDefDV)->setIDRefList(getScanner()->getIDRefList()); |
| else if (attDefDVType == DatatypeValidator::IDREF) |
| ((IDREFDatatypeValidator*)attDefDV)->setIDRefList(getScanner()->getIDRefList()); |
| |
| // now validate the attribute value |
| // if notation, need to bind URI to notation first |
| if (attDefDVType == DatatypeValidator::NOTATION) |
| { |
| // |
| // Make sure that this value maps to one of the |
| // notation values in the enumList parameter. We don't have to |
| // look it up in the notation pool (if a notation) because we |
| // will look up the enumerated values themselves. If they are in |
| // the notation pool (after the Grammar is parsed), then obviously |
| // this value will be legal since it matches one of them. |
| // |
| XMLBuffer nameBuf(XMLString::stringLen(attrValue)+1); |
| XMLBuffer prefixBuf(XMLString::stringLen(attrValue)+1); |
| XMLBuffer notationBuf; |
| unsigned int uriId = getScanner()->resolveQName(attrValue, nameBuf, prefixBuf, ElemStack::Mode_Element); |
| notationBuf.set(getScanner()->getURIText(uriId)); |
| notationBuf.append(chColon); |
| notationBuf.append(nameBuf.getRawBuffer()); |
| |
| attDefDV->validate(notationBuf.getRawBuffer()); |
| } |
| else |
| attDefDV->validate(attrValue); |
| } catch (InvalidDatatypeValueException idve) { |
| emitError (XMLValid::DatatypeError, idve.getType(), idve.getMessage()); |
| } |
| catch (InvalidDatatypeFacetException idve) { |
| emitError (XMLValid::DatatypeError, idve.getType(), idve.getMessage()); |
| } |
| catch (...) { |
| emitError(XMLValid::GenericError); |
| throw; |
| } |
| } |
| fDatatypeBuffer.reset(); |
| fTrailing = false; |
| } |
| |
| void SchemaValidator::validateElement(const XMLElementDecl* elemDef) |
| { |
| if (fXsiType) { |
| // handle "xsi:type" right here |
| unsigned int uri = fXsiType->getURI(); |
| const XMLCh* localPart = fXsiType->getLocalPart(); |
| |
| if (uri != XMLElementDecl::fgInvalidElemId && |
| uri != XMLElementDecl::fgPCDataElemId && |
| uri != XMLContentModel::gEpsilonFakeId && |
| uri != XMLContentModel::gEOCFakeId) { |
| // retrieve Grammar for the uri |
| const XMLCh* uriStr = getScanner()->getURIText(uri); |
| SchemaGrammar* sGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(uriStr); |
| |
| if (!sGrammar) { |
| |
| // Check built-in simple types |
| if (!XMLString::compareString(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { |
| |
| fXsiTypeValidator = fGrammarResolver->getDatatypeRegistry()->getDatatypeValidator(localPart); |
| |
| if (!fXsiTypeValidator) |
| emitError(XMLValid::BadXsiType, fXsiType->getRawName()); |
| else { |
| DatatypeValidator* ancestorValidator = ((SchemaElementDecl*)elemDef)->getDatatypeValidator(); |
| if (ancestorValidator && !ancestorValidator->isSubstitutableBy(fXsiTypeValidator)) { |
| // the type is not derived from ancestor |
| emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName()); |
| } |
| else { |
| // the type is derived from ancestor |
| if (((SchemaElementDecl*)elemDef)->getBlockSet() == SchemaSymbols::RESTRICTION) |
| emitError(XMLValid::NoSubforBlock, fXsiType->getRawName(), elemDef->getFullName()); |
| if (elemDef->hasAttDefs()) { |
| // if we have an attribute but xsi:type's type is simple, we have a problem... |
| emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName()); |
| } |
| } |
| } |
| } |
| else { |
| // Grammar not found |
| emitError(XMLValid::GrammarNotFound, uriStr); |
| } |
| } |
| else if (sGrammar->getGrammarType() != Grammar::SchemaGrammarType) { |
| emitError(XMLValid::GrammarNotFound, uriStr); |
| } |
| else { |
| // retrieve complexType registry and DatatypeValidator registry |
| RefHashTableOf<ComplexTypeInfo>* complexTypeRegistry = sGrammar->getComplexTypeRegistry(); |
| DatatypeValidatorFactory* dataTypeReg = fGrammarResolver->getDatatypeRegistry(); |
| |
| if (!complexTypeRegistry || !dataTypeReg) |
| emitError(XMLValid::BadXsiType, fXsiType->getRawName()); |
| else { |
| // retrieve the typeInfo specified in xsi:type |
| XMLBuffer aBuffer; |
| aBuffer.set(uriStr); |
| aBuffer.append(chComma); |
| aBuffer.append(localPart); |
| ComplexTypeInfo* typeInfo = complexTypeRegistry->get(aBuffer.getRawBuffer()); |
| |
| if (typeInfo) { |
| // typeInfo is found |
| bool error = false; |
| |
| if (typeInfo->getAbstract()) { |
| emitError(XMLValid::NoAbstractInXsiType, aBuffer.getRawBuffer()); |
| error = true; |
| } |
| |
| ComplexTypeInfo* destType = ((SchemaElementDecl*)elemDef)->getComplexTypeInfo(); |
| ComplexTypeInfo* tempType = typeInfo; |
| if (destType) { |
| while (tempType) { |
| if (!XMLString::compareString(tempType->getTypeName(), destType->getTypeName())) |
| break; |
| tempType = tempType->getBaseComplexTypeInfo(); |
| } |
| if (!tempType) { |
| emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName()); |
| error = true; |
| } |
| else { |
| int derivationMethod = typeInfo->getDerivedBy(); |
| if ((((SchemaElementDecl*)elemDef)->getBlockSet() & derivationMethod) != 0) { |
| emitError(XMLValid::NoSubforBlock, fXsiType->getRawName(), elemDef->getFullName()); |
| error = true; |
| } |
| } |
| } |
| else { |
| // if the original type is a simple type, check derivation ok. |
| DatatypeValidator* ancestorValidator = ((SchemaElementDecl*)elemDef)->getDatatypeValidator(); |
| if (ancestorValidator && !ancestorValidator->isSubstitutableBy(fXsiTypeValidator)) { |
| // the type is not derived from ancestor |
| emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName()); |
| error = true; |
| } |
| } |
| |
| if (!error) |
| ((SchemaElementDecl*)elemDef)->setXsiComplexTypeInfo(typeInfo); |
| } |
| else { |
| // typeInfo not found |
| if (!XMLString::compareString(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) |
| fXsiTypeValidator = dataTypeReg->getDatatypeValidator(localPart); |
| else |
| fXsiTypeValidator = dataTypeReg->getDatatypeValidator(aBuffer.getRawBuffer()); |
| |
| if (!fXsiTypeValidator) |
| emitError(XMLValid::BadXsiType, fXsiType->getRawName()); |
| else { |
| DatatypeValidator* ancestorValidator = ((SchemaElementDecl*)elemDef)->getDatatypeValidator(); |
| if (ancestorValidator && !ancestorValidator->isSubstitutableBy(fXsiTypeValidator)) { |
| // the type is not derived from ancestor |
| emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName()); |
| } |
| else { |
| // the type is derived from ancestor |
| if (((SchemaElementDecl*)elemDef)->getBlockSet() == SchemaSymbols::RESTRICTION) |
| emitError(XMLValid::NoSubforBlock, fXsiType->getRawName(), elemDef->getFullName()); |
| if (elemDef->hasAttDefs()) { |
| // if we have an attribute but xsi:type's type is simple, we have a problem... |
| emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName()); |
| } |
| } |
| |
| } |
| } |
| } |
| } |
| } |
| delete fXsiType; |
| fXsiType = 0; |
| } |
| else { |
| // |
| // xsi:type was not specified... |
| // If the corresponding type is abstract, detect an error |
| // |
| ComplexTypeInfo* typeInfo = ((SchemaElementDecl*)elemDef)->getComplexTypeInfo(); |
| |
| if (typeInfo) { |
| if (typeInfo->getAbstract()) { |
| emitError(XMLValid::NoUseAbstractType, elemDef->getFullName()); |
| } |
| } |
| } |
| |
| // |
| // Check whether this element is abstract. If so, an error |
| // |
| int miscFlags = ((SchemaElementDecl*)elemDef)->getMiscFlags(); |
| if ((miscFlags & SchemaSymbols::ABSTRACT) != 0) { |
| emitError(XMLValid::NoDirectUseAbstractElement, elemDef->getFullName()); |
| } |
| |
| // |
| // Check whether this element allows Nillable |
| // |
| if (fNil && (miscFlags & SchemaSymbols::NILLABLE) == 0 ) { |
| fNil = false; |
| emitError(XMLValid::NillNotAllowed, elemDef->getFullName()); |
| } |
| |
| fDatatypeBuffer.reset(); |
| fTrailing = false; |
| } |
| |
| void SchemaValidator::preContentValidation(bool reuseGrammar) |
| { |
| // Lets go through all the grammar in the GrammarResolver |
| // and validate those that has not been validated yet |
| // |
| // Lets enumerate all of the elements in the element decl pool |
| // and put out an error for any that did not get declared. |
| // We also check all of the attributes as well. |
| // |
| // And enumerate all the complextype info in the grammar |
| // and do Unique Particle Attribution Checking |
| |
| RefHashTableOfEnumerator<Grammar> grammarEnum = fGrammarResolver->getGrammarEnumerator(); |
| while (grammarEnum.hasMoreElements()) |
| { |
| SchemaGrammar& sGrammar = (SchemaGrammar&) grammarEnum.nextElement(); |
| if (sGrammar.getGrammarType() != Grammar::SchemaGrammarType || sGrammar.getUPAChecked()) |
| continue; |
| |
| sGrammar.setUPAChecked(true); |
| |
| RefHash3KeysIdPoolEnumerator<SchemaElementDecl> elemEnum = sGrammar.getElemEnumerator(); |
| |
| while (elemEnum.hasMoreElements()) |
| { |
| SchemaElementDecl& curElem = elemEnum.nextElement(); |
| |
| // First check if declared or not |
| // |
| // See if this element decl was ever marked as declared. If |
| // not, then put out an error. In some cases its just |
| // a warning, such as being referenced in a content model. |
| // |
| const SchemaElementDecl::CreateReasons reason = curElem.getCreateReason(); |
| |
| if (reason != XMLElementDecl::Declared) |
| { |
| if (reason == XMLElementDecl::AttList) |
| { |
| getScanner()->emitError |
| ( |
| XMLErrs::UndeclaredElemInAttList |
| , curElem.getFullName() |
| ); |
| } |
| else if (reason == XMLElementDecl::AsRootElem) |
| { |
| emitError |
| ( |
| XMLValid::UndeclaredElemInDocType |
| , curElem.getFullName() |
| ); |
| } |
| else if (reason == XMLElementDecl::InContentModel) |
| { |
| getScanner()->emitError |
| ( |
| XMLErrs::UndeclaredElemInCM |
| , curElem.getFullName() |
| ); |
| } |
| else |
| { |
| } |
| } |
| |
| // |
| // Then check all of the attributes of the current element. |
| // We check for: |
| // |
| // 1) Multiple ID attributes |
| // 2) That all of the default values of attributes are |
| // valid for their type. |
| // 3) That for any notation types, that their lists |
| // of possible values refer to declared notations. |
| // |
| if (curElem.hasAttDefs()) { |
| XMLAttDefList& attDefList = curElem.getAttDefList(); |
| bool seenId = false; |
| while (attDefList.hasMoreElements()) |
| { |
| const XMLAttDef& curAttDef = attDefList.nextElement(); |
| |
| if (curAttDef.getType() == XMLAttDef::ID) |
| { |
| if (seenId) |
| { |
| emitError |
| ( |
| XMLValid::MultipleIdAttrs |
| , curElem.getFullName() |
| ); |
| break; |
| } |
| |
| seenId = true; |
| } |
| else if (curAttDef.getType() == XMLAttDef::Notation) |
| { |
| // |
| // We need to verify that all of its possible values |
| // (in the enum list) refer to valid notations. |
| // |
| XMLCh* list = XMLString::replicate(curAttDef.getEnumeration()); |
| ArrayJanitor<XMLCh> janList(list); |
| |
| // |
| // Search forward for a space or a null. If a null, |
| // we are done. If a space, cap it and look it up. |
| // |
| bool breakFlag = false; |
| XMLCh* listPtr = list; |
| XMLCh* lastPtr = listPtr; |
| while (true) |
| { |
| while (*listPtr && (*listPtr != chSpace)) |
| listPtr++; |
| |
| // |
| // If at the end, indicate we need to break after |
| // this one. Else, cap it off here. |
| // |
| if (!*listPtr) |
| breakFlag = true; |
| else |
| *listPtr = chNull; |
| |
| if (!sGrammar.getNotationDecl(lastPtr)) |
| { |
| emitError |
| ( |
| XMLValid::UnknownNotRefAttr |
| , curAttDef.getFullName() |
| , lastPtr |
| ); |
| } |
| |
| // Break out if we hit the end last time |
| if (breakFlag) |
| break; |
| |
| // Else move upwards and try again |
| listPtr++; |
| lastPtr = listPtr; |
| } |
| } |
| |
| // If it has a default/fixed value, then validate it |
| if (curAttDef.getValue()) |
| { |
| validateAttrValue |
| ( |
| &curAttDef |
| , curAttDef.getValue() |
| ); |
| } |
| } |
| } |
| } |
| |
| // For each complex type info, check the Unique Particle Attribution |
| if (getScanner()->getValidationSchemaFullChecking()) { |
| RefHashTableOf<ComplexTypeInfo>* complexTypeRegistry = sGrammar.getComplexTypeRegistry(); |
| |
| RefHashTableOfEnumerator<ComplexTypeInfo> complexTypeEnum(complexTypeRegistry); |
| while (complexTypeEnum.hasMoreElements()) |
| { |
| ComplexTypeInfo& curTypeInfo = complexTypeEnum.nextElement(); |
| curTypeInfo.checkUniqueParticleAttribution(&sGrammar, fGrammarResolver, getScanner()->getURIStringPool(), this); |
| } |
| } |
| } |
| } |
| |
| void SchemaValidator::postParseValidation() |
| { |
| // |
| // At this time, there is nothing to do here. The scanner itself handles |
| // ID/IDREF validation, since that is the same no matter what kind of |
| // validator. |
| // |
| } |
| |
| // --------------------------------------------------------------------------- |
| // SchemaValidator: Validator method |
| // --------------------------------------------------------------------------- |
| // Do Schema Normalization depends on the WhiteSpace Facet |
| // preserve : No normalization is done |
| // replace : All occurrences of #x9 (tab), #xA (linefeed) and #xD (carriage return) |
| // are replaced with #x20 (space). |
| // collapse : Subsequent to the replacements specified above under replace, |
| // contiguous sequences of #x20s are collapsed to a single #x20, |
| // and initial and/or final #x20s are deleted. |
| // |
| void SchemaValidator::normalizeWhiteSpace(DatatypeValidator* dV, const XMLCh* const value, XMLBuffer& toFill) |
| { |
| short fWhiteSpace = DatatypeValidator::PRESERVE; |
| if (dV) |
| fWhiteSpace = dV->getWSFacet(); |
| |
| enum States |
| { |
| InWhitespace |
| , InContent |
| }; |
| |
| States curState = InContent; |
| toFill.reset(); |
| |
| // |
| // Loop through the chars of the source value and normalize it according |
| // to the whitespace facet |
| // |
| bool firstNonWS = false; |
| XMLCh nextCh; |
| const XMLCh* srcPtr = value; |
| |
| if ((fWhiteSpace==DatatypeValidator::COLLAPSE) && fTrailing) |
| toFill.append(chSpace); |
| |
| while (*srcPtr) |
| { |
| nextCh = *srcPtr; |
| |
| if (fWhiteSpace == DatatypeValidator::PRESERVE) |
| { |
| // do nothing |
| } |
| else if (fWhiteSpace == DatatypeValidator::REPLACE) |
| { |
| if (XMLReader::isWhitespace(nextCh)) |
| nextCh = chSpace; |
| } |
| else // COLLAPSE case |
| { |
| if (curState == InWhitespace) |
| { |
| if (!XMLReader::isWhitespace(nextCh)) |
| { |
| if (firstNonWS) |
| toFill.append(chSpace); |
| curState = InContent; |
| firstNonWS = true; |
| } |
| else |
| { |
| srcPtr++; |
| continue; |
| } |
| } |
| else if (curState == InContent) |
| { |
| if (XMLReader::isWhitespace(nextCh)) |
| { |
| curState = InWhitespace; |
| srcPtr++; |
| continue; |
| } |
| firstNonWS = true; |
| } |
| } |
| // Add this char to the target buffer |
| toFill.append(nextCh); |
| |
| // stored the content for validation later |
| //fDatatypeBuffer.append(nextCh); |
| |
| // And move up to the next character in the source |
| srcPtr++; |
| } |
| srcPtr--; |
| nextCh = *srcPtr; |
| if (XMLReader::isWhitespace(nextCh)) |
| fTrailing = true; |
| |
| fDatatypeBuffer.append(toFill.getRawBuffer()); |
| } |
| |