| /* |
| * 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. |
| */ |
| |
| /* |
| * $Id$ |
| */ |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #include <xercesc/validators/schema/TraverseSchema.hpp> |
| #include <xercesc/framework/XMLEntityHandler.hpp> |
| #include <xercesc/framework/XMLValidityCodes.hpp> |
| #include <xercesc/validators/schema/identity/IC_Key.hpp> |
| #include <xercesc/validators/schema/identity/IC_KeyRef.hpp> |
| #include <xercesc/validators/schema/identity/IC_Unique.hpp> |
| #include <xercesc/validators/schema/identity/IC_Field.hpp> |
| #include <xercesc/validators/schema/identity/IC_Selector.hpp> |
| #include <xercesc/validators/schema/identity/XercesXPath.hpp> |
| #include <xercesc/util/XMLStringTokenizer.hpp> |
| #include <xercesc/validators/schema/XUtil.hpp> |
| #include <xercesc/validators/common/GrammarResolver.hpp> |
| #include <xercesc/internal/XMLReader.hpp> |
| #include <xercesc/validators/schema/ComplexTypeInfo.hpp> |
| #include <xercesc/validators/schema/NamespaceScope.hpp> |
| #include <xercesc/validators/schema/SchemaAttDefList.hpp> |
| #include <xercesc/internal/XMLScanner.hpp> |
| #include <xercesc/framework/LocalFileInputSource.hpp> |
| #include <xercesc/framework/URLInputSource.hpp> |
| #include <xercesc/framework/XMLGrammarPool.hpp> |
| #include <xercesc/framework/XMLSchemaDescription.hpp> |
| #include <xercesc/validators/schema/identity/XPathException.hpp> |
| #include <xercesc/validators/schema/GeneralAttributeCheck.hpp> |
| #include <xercesc/validators/schema/XercesGroupInfo.hpp> |
| #include <xercesc/validators/schema/XercesAttGroupInfo.hpp> |
| #include <xercesc/validators/schema/XSDLocator.hpp> |
| #include <xercesc/validators/schema/XSDDOMParser.hpp> |
| #include <xercesc/dom/DOMNamedNodeMap.hpp> |
| #include <xercesc/dom/DOMText.hpp> |
| #include <xercesc/dom/impl/XSDElementNSImpl.hpp> |
| #include <xercesc/util/OutOfMemoryException.hpp> |
| #include <xercesc/util/NumberFormatException.hpp> |
| #include <xercesc/util/XMLEntityResolver.hpp> |
| #include <xercesc/util/XMLUri.hpp> |
| #include <xercesc/framework/psvi/XSAnnotation.hpp> |
| #include <xercesc/framework/MemBufInputSource.hpp> |
| #include <xercesc/internal/XSAXMLScanner.hpp> |
| |
| namespace XERCES_CPP_NAMESPACE { |
| |
| // --------------------------------------------------------------------------- |
| // TraverseSchema: Local declaration |
| // --------------------------------------------------------------------------- |
| |
| // This helper class will handle the parsing of namespace prefixes for a given DOMElement, and its winding back |
| class NamespaceScopeManager |
| { |
| public: |
| NamespaceScopeManager(const DOMElement* const node, SchemaInfo* info, TraverseSchema* traverser) |
| { |
| fScopeAdded=node?traverser->retrieveNamespaceMapping(node):false; |
| fSchemaInfo=info; |
| } |
| ~NamespaceScopeManager() |
| { |
| if(fScopeAdded) |
| fSchemaInfo->getNamespaceScope()->decreaseDepth(); |
| |
| } |
| protected: |
| bool fScopeAdded; |
| SchemaInfo* fSchemaInfo; |
| }; |
| |
| // --------------------------------------------------------------------------- |
| // TraverseSchema: Static member data |
| // --------------------------------------------------------------------------- |
| |
| |
| // --------------------------------------------------------------------------- |
| // TraverseSchema: Local const data |
| // --------------------------------------------------------------------------- |
| static const XMLCh fgAnonSNamePrefix[] = |
| { |
| chUnderscore, chUnderscore, chLatin_A, chLatin_n, chLatin_o, chLatin_n, chLatin_S, chNull |
| }; |
| |
| static const XMLCh fgAnonCNamePrefix[] = |
| { |
| chUnderscore, chUnderscore, chLatin_A, chLatin_n, chLatin_o, chLatin_n, chLatin_C, chNull |
| }; |
| |
| static const XMLCh fgUnbounded[] = |
| { |
| chLatin_u, chLatin_n, chLatin_b, chLatin_o, chLatin_u, chLatin_n, chLatin_d, |
| chLatin_e, chLatin_d, chNull |
| }; |
| |
| static const XMLCh fgValueOne[] = |
| { |
| chDigit_1, chNull |
| }; |
| |
| static const XMLCh fgValueZero[] = |
| { |
| chDigit_0, chNull |
| }; |
| |
| static const XMLCh* fgIdentityConstraints[] = |
| { |
| SchemaSymbols::fgELT_UNIQUE, |
| SchemaSymbols::fgELT_KEY, |
| SchemaSymbols::fgELT_KEYREF |
| }; |
| |
| static const XMLCh fgSynthetic_Annotation[] = |
| { |
| chLatin_S, chLatin_y, chLatin_n, chLatin_t, chLatin_h, chLatin_e, chLatin_t |
| , chLatin_i, chLatin_c, chUnderscore |
| , chLatin_A, chLatin_n, chLatin_n, chLatin_o, chLatin_t, chLatin_a, chLatin_t |
| , chLatin_i, chLatin_o, chLatin_n, chNull |
| }; |
| |
| |
| // Flags for global declaration |
| enum { |
| ENUM_ELT_SIMPLETYPE, |
| ENUM_ELT_COMPLEXTYPE, |
| ENUM_ELT_ELEMENT, |
| ENUM_ELT_ATTRIBUTE, |
| ENUM_ELT_ATTRIBUTEGROUP, |
| ENUM_ELT_GROUP, |
| ENUM_ELT_SIZE |
| }; |
| |
| typedef JanitorMemFunCall<TraverseSchema> CleanupType; |
| |
| // --------------------------------------------------------------------------- |
| // TraverseSchema: Constructors and Destructor |
| // --------------------------------------------------------------------------- |
| TraverseSchema::TraverseSchema( DOMElement* const schemaRoot |
| , XMLStringPool* const uriStringPool |
| , SchemaGrammar* const schemaGrammar |
| , GrammarResolver* const grammarResolver |
| , RefHash2KeysTableOf<SchemaInfo>* cachedSchemaInfoList |
| , RefHash2KeysTableOf<SchemaInfo>* schemaInfoList |
| , XMLScanner* const xmlScanner |
| , const XMLCh* const schemaURL |
| , XMLEntityHandler* const entityHandler |
| , XMLErrorReporter* const errorReporter |
| , MemoryManager* const manager |
| , bool multipleImport) |
| : fFullConstraintChecking(false) |
| , fTargetNSURI(-1) |
| , fEmptyNamespaceURI(-1) |
| , fCurrentScope(Grammar::TOP_LEVEL_SCOPE) |
| , fScopeCount(schemaGrammar->getScopeCount ()) |
| , fAnonXSTypeCount(schemaGrammar->getAnonTypeCount ()) |
| , fCircularCheckIndex(0) |
| , fTargetNSURIString(0) |
| , fDatatypeRegistry(0) |
| , fGrammarResolver(grammarResolver) |
| , fSchemaGrammar(schemaGrammar) |
| , fEntityHandler(entityHandler) |
| , fErrorReporter(errorReporter) |
| , fURIStringPool(uriStringPool) |
| , fStringPool(0) |
| , fBuffer(1023, manager) |
| , fScanner(xmlScanner) |
| , fAttributeDeclRegistry(0) |
| , fComplexTypeRegistry(0) |
| , fGroupRegistry(0) |
| , fAttGroupRegistry(0) |
| , fIC_ElementsNS(0) |
| , fPreprocessedNodes(0) |
| , fSchemaInfo(0) |
| , fCurrentGroupInfo(0) |
| , fCurrentAttGroupInfo(0) |
| , fCurrentComplexType(0) |
| , fCurrentTypeNameStack(0) |
| , fCurrentGroupStack(0) |
| , fIC_Elements(0) |
| , fDeclStack(0) |
| , fGlobalDeclarations(0) |
| , fNonXSAttList(0) |
| , fImportedNSList(0) |
| , fIC_NodeListNS(0) |
| , fNotationRegistry(0) |
| , fRedefineComponents(0) |
| , fIdentityConstraintNames(0) |
| , fValidSubstitutionGroups(0) |
| , fSchemaInfoList(schemaInfoList) |
| , fCachedSchemaInfoList (cachedSchemaInfoList) |
| , fParser(0) |
| , fLocator(0) |
| , fMemoryManager(manager) |
| , fGrammarPoolMemoryManager(fGrammarResolver->getGrammarPoolMemoryManager()) |
| , fAnnotation(0) |
| , fAttributeCheck(manager) |
| { |
| CleanupType cleanup(this, &TraverseSchema::cleanUp); |
| |
| try { |
| |
| if (fGrammarResolver && schemaRoot && fURIStringPool) { |
| |
| init(); |
| |
| if (multipleImport) |
| { |
| // If we are working on an existing schema, do some |
| // intitialization that is otherwise done by preprocessSchema. |
| // |
| fComplexTypeRegistry = fSchemaGrammar->getComplexTypeRegistry(); |
| fGroupRegistry = fSchemaGrammar->getGroupInfoRegistry(); |
| fAttGroupRegistry = fSchemaGrammar->getAttGroupInfoRegistry(); |
| fAttributeDeclRegistry = fSchemaGrammar->getAttributeDeclRegistry(); |
| fValidSubstitutionGroups = fSchemaGrammar->getValidSubstitutionGroups(); |
| } |
| |
| preprocessSchema(schemaRoot, schemaURL, multipleImport); |
| doTraverseSchema(schemaRoot); |
| |
| // Store the scope and anon type counts in case we need to add |
| // more to this grammar (multi-import case). schemaGrammar and |
| // fSchemaGrammar should be the same here. |
| // |
| fSchemaGrammar->setScopeCount (fScopeCount); |
| fSchemaGrammar->setAnonTypeCount (fAnonXSTypeCount); |
| } |
| |
| } |
| catch(const OutOfMemoryException&) |
| { |
| cleanup.release(); |
| |
| throw; |
| } |
| |
| cleanup.release(); |
| } |
| |
| |
| TraverseSchema::~TraverseSchema() |
| { |
| cleanUp(); |
| } |
| |
| |
| // --------------------------------------------------------------------------- |
| // TraverseSchema: Traversal methods |
| // --------------------------------------------------------------------------- |
| void TraverseSchema::doTraverseSchema(const DOMElement* const schemaRoot) { |
| |
| // process children nodes |
| processChildren(schemaRoot); |
| |
| // Handle identity constraints - keyref |
| if (fIC_ElementsNS && fIC_ElementsNS->containsKey(fTargetNSURIString)) { |
| |
| fIC_Elements = fIC_ElementsNS->get(fTargetNSURIString); |
| |
| XMLSize_t icListSize = fIC_Elements->size(); |
| |
| for (XMLSize_t i=0; i < icListSize; i++) { |
| |
| SchemaElementDecl* curElem = fIC_Elements->elementAt(i); |
| ValueVectorOf<DOMElement*>* icNodes = fIC_NodeListNS->get(curElem); |
| XMLSize_t icNodesSize = icNodes->size(); |
| |
| for (XMLSize_t j = 0; j < icNodesSize; j++) { |
| traverseKeyRef(icNodes->elementAt(j), curElem); |
| } |
| } |
| } |
| |
| if (fScanner->getValidateAnnotations() && !fSchemaGrammar->getAnnotations()->isEmpty()) |
| { |
| validateAnnotations(); |
| } |
| fSchemaInfo->setProcessed(); |
| } |
| |
| void TraverseSchema::preprocessSchema(DOMElement* const schemaRoot, |
| const XMLCh* const schemaURL, |
| bool multipleImport) { |
| if (!multipleImport) { |
| // Make sure namespace binding is defaulted |
| const XMLCh* rootPrefix = schemaRoot->getPrefix(); |
| |
| if (rootPrefix == 0 || !*rootPrefix) { |
| |
| const XMLCh* xmlnsStr = schemaRoot->getAttribute(XMLUni::fgXMLNSString); |
| |
| if (!xmlnsStr || !*xmlnsStr) { |
| schemaRoot->setAttribute(XMLUni::fgXMLNSString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA); |
| } |
| } |
| |
| // Set schemaGrammar data and add it to GrammarResolver |
| // For complex type registry, attribute decl registry , group/attGroup |
| // and namespace mapping, needs to check whether the passed in |
| // Grammar was a newly instantiated one. |
| fComplexTypeRegistry = fSchemaGrammar->getComplexTypeRegistry(); |
| |
| if (fComplexTypeRegistry == 0 ) { |
| |
| fComplexTypeRegistry = new (fGrammarPoolMemoryManager) RefHashTableOf<ComplexTypeInfo>(29, fGrammarPoolMemoryManager); |
| fSchemaGrammar->setComplexTypeRegistry(fComplexTypeRegistry); |
| } |
| |
| fGroupRegistry = fSchemaGrammar->getGroupInfoRegistry(); |
| |
| if (fGroupRegistry == 0 ) { |
| |
| fGroupRegistry = new (fGrammarPoolMemoryManager) RefHashTableOf<XercesGroupInfo>(13, fGrammarPoolMemoryManager); |
| fSchemaGrammar->setGroupInfoRegistry(fGroupRegistry); |
| } |
| |
| fAttGroupRegistry = fSchemaGrammar->getAttGroupInfoRegistry(); |
| |
| if (fAttGroupRegistry == 0 ) { |
| |
| fAttGroupRegistry = new (fGrammarPoolMemoryManager) RefHashTableOf<XercesAttGroupInfo>(13, fGrammarPoolMemoryManager); |
| fSchemaGrammar->setAttGroupInfoRegistry(fAttGroupRegistry); |
| } |
| |
| fAttributeDeclRegistry = fSchemaGrammar->getAttributeDeclRegistry(); |
| |
| if (fAttributeDeclRegistry == 0) { |
| |
| fAttributeDeclRegistry = new (fGrammarPoolMemoryManager) RefHashTableOf<XMLAttDef>(29, fGrammarPoolMemoryManager); |
| fSchemaGrammar->setAttributeDeclRegistry(fAttributeDeclRegistry); |
| } |
| |
| fValidSubstitutionGroups = fSchemaGrammar->getValidSubstitutionGroups(); |
| |
| if (!fValidSubstitutionGroups) { |
| |
| fValidSubstitutionGroups = new (fGrammarPoolMemoryManager) RefHash2KeysTableOf<ElemVector>(29, fGrammarPoolMemoryManager); |
| fSchemaGrammar->setValidSubstitutionGroups(fValidSubstitutionGroups); |
| } |
| |
| //Retrieve the targetnamespace URI information |
| const XMLCh* targetNSURIStr = schemaRoot->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE); |
| fSchemaGrammar->setTargetNamespace(targetNSURIStr); |
| |
| fCurrentScope = Grammar::TOP_LEVEL_SCOPE; |
| fTargetNSURIString = fSchemaGrammar->getTargetNamespace(); |
| fTargetNSURI = fURIStringPool->addOrFind(fTargetNSURIString); |
| |
| XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) fSchemaGrammar->getGrammarDescription(); |
| gramDesc->setTargetNamespace(fTargetNSURIString); |
| |
| fGrammarResolver->putGrammar(fSchemaGrammar); |
| } |
| else { |
| fCurrentScope = Grammar::TOP_LEVEL_SCOPE; |
| |
| fTargetNSURIString = fSchemaGrammar->getTargetNamespace(); |
| fTargetNSURI = fURIStringPool->addOrFind(fTargetNSURIString); |
| } |
| |
| SchemaInfo* currInfo = new (fMemoryManager) SchemaInfo(0, 0, 0, fTargetNSURI, |
| 0, |
| schemaURL, |
| fTargetNSURIString, schemaRoot, |
| fScanner, |
| fGrammarPoolMemoryManager); |
| |
| currInfo->getNamespaceScope()->reset(fEmptyNamespaceURI); |
| // Add mapping for the xml prefix |
| currInfo->getNamespaceScope()->addPrefix(XMLUni::fgXMLString, fURIStringPool->addOrFind(XMLUni::fgXMLURIName)); |
| |
| if (fSchemaInfo) |
| fSchemaInfo->addSchemaInfo(currInfo, SchemaInfo::IMPORT); |
| |
| addImportedNS(currInfo->getTargetNSURI()); |
| |
| fSchemaInfo = currInfo; |
| fSchemaInfoList->put((void*) fSchemaInfo->getCurrentSchemaURL(), fSchemaInfo->getTargetNSURI(), fSchemaInfo); |
| fSchemaInfo->addSchemaInfo(fSchemaInfo, SchemaInfo::INCLUDE); |
| traverseSchemaHeader(schemaRoot); |
| |
| // preprocess chidren |
| preprocessChildren(schemaRoot); |
| } |
| |
| |
| void TraverseSchema::traverseSchemaHeader(const DOMElement* const schemaRoot) { |
| |
| // Make sure that the root element is <xsd:schema> |
| if (!XMLString::equals(schemaRoot->getLocalName(), SchemaSymbols::fgELT_SCHEMA)) { |
| reportSchemaError(schemaRoot, XMLUni::fgXMLErrDomain, XMLErrs::InvalidXMLSchemaRoot); |
| } |
| |
| // Make sure that the targetNamespace value is not empty string |
| checkForEmptyTargetNamespace(schemaRoot); |
| |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| schemaRoot, GeneralAttributeCheck::E_Schema, this |
| , true, fSchemaInfo->getNonXSAttList() |
| ); |
| |
| retrieveNamespaceMapping(schemaRoot); |
| // Add mapping for the default namespace |
| if ((!fTargetNSURIString || !*fTargetNSURIString) && schemaRoot->getAttributeNode(XMLUni::fgXMLNSString)==NULL) |
| fSchemaInfo->getNamespaceScope()->addPrefix(XMLUni::fgZeroLenString, fEmptyNamespaceURI); |
| |
| unsigned short elemAttrDefaultQualified = 0; |
| |
| if (XMLString::equals(schemaRoot->getAttribute(SchemaSymbols::fgATT_ELEMENTFORMDEFAULT), |
| SchemaSymbols::fgATTVAL_QUALIFIED)) { |
| elemAttrDefaultQualified |= Elem_Def_Qualified; |
| } |
| |
| if (XMLString::equals(schemaRoot->getAttribute(SchemaSymbols::fgATT_ATTRIBUTEFORMDEFAULT), |
| SchemaSymbols::fgATTVAL_QUALIFIED)) { |
| elemAttrDefaultQualified |= Attr_Def_Qualified; |
| } |
| |
| fSchemaInfo->setElemAttrDefaultQualified(elemAttrDefaultQualified); |
| fSchemaInfo->setBlockDefault(parseBlockSet(schemaRoot, ES_Block, true)); |
| fSchemaInfo->setFinalDefault(parseFinalSet(schemaRoot, ECS_Final, true)); |
| } |
| |
| |
| XSAnnotation* |
| TraverseSchema::traverseAnnotationDecl(const DOMElement* const annotationElem, |
| ValueVectorOf<DOMNode*>* const nonXSAttList, |
| const bool topLevel) { |
| |
| NamespaceScopeManager nsMgr(annotationElem, fSchemaInfo, this); |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| annotationElem, GeneralAttributeCheck::E_Annotation, this, topLevel |
| ); |
| |
| const XMLCh* contents = 0; |
| DOMElement* child = XUtil::getFirstChildElement(annotationElem); |
| if (child) { |
| for (; |
| child != 0; |
| child = XUtil::getNextSiblingElement(child)) { |
| |
| const XMLCh* name = child->getLocalName(); |
| |
| if (XMLString::equals(name, SchemaSymbols::fgELT_APPINFO)) { |
| |
| DOMNode* textContent = child->getFirstChild(); |
| if (textContent && textContent->getNodeType() == DOMNode::TEXT_NODE) |
| contents = ((DOMText*) textContent)->getData(); |
| |
| fAttributeCheck.checkAttributes(child, GeneralAttributeCheck::E_Appinfo, this); |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_DOCUMENTATION)) { |
| |
| DOMNode* textContent = child->getFirstChild(); |
| if (textContent && textContent->getNodeType() == DOMNode::TEXT_NODE) |
| contents = ((DOMText*) textContent)->getData(); |
| |
| fAttributeCheck.checkAttributes(child, GeneralAttributeCheck::E_Documentation, this); |
| } |
| else { |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAnnotationContent); |
| } |
| } |
| } |
| else |
| { |
| // If the Annotation has no children, get the text directly |
| DOMNode* textContent = annotationElem->getFirstChild(); |
| if (textContent && textContent->getNodeType() == DOMNode::TEXT_NODE) |
| contents = ((DOMText*) textContent)->getData(); |
| } |
| |
| if (contents && !fScanner->getIgnoreAnnotations()) |
| { |
| XSAnnotation* theAnnotation = 0; |
| |
| XMLSize_t nonXSAttSize = nonXSAttList->size(); |
| |
| if (nonXSAttSize) |
| { |
| int annotTokenStart = XMLString::patternMatch( |
| contents, SchemaSymbols::fgELT_ANNOTATION); |
| |
| if (annotTokenStart == -1) // something is wrong |
| return 0; |
| |
| // set annotation element |
| fBuffer.set(contents, annotTokenStart + 10); |
| |
| for (XMLSize_t i=0; i<nonXSAttSize; i++) |
| { |
| DOMNode* attNode = nonXSAttList->elementAt(i); |
| |
| if (!XMLString::equals( |
| annotationElem->getAttributeNS( |
| attNode->getNamespaceURI(), attNode->getLocalName()) |
| , XMLUni::fgZeroLenString) |
| ) |
| { |
| continue; |
| } |
| |
| fBuffer.append(chSpace); |
| fBuffer.append(attNode->getNodeName()); |
| fBuffer.append(chEqual); |
| fBuffer.append(chDoubleQuote); |
| processAttValue(attNode->getNodeValue(), fBuffer); |
| fBuffer.append(chDoubleQuote); |
| } |
| |
| // add remaining annotation content |
| fBuffer.append(contents + annotTokenStart + 10); |
| |
| theAnnotation = new (fGrammarPoolMemoryManager) XSAnnotation(fBuffer.getRawBuffer(), fGrammarPoolMemoryManager); |
| } |
| else |
| { |
| theAnnotation = new (fGrammarPoolMemoryManager) XSAnnotation(contents, fGrammarPoolMemoryManager); |
| } |
| |
| /*** |
| * set line, col and systemId info |
| ***/ |
| theAnnotation->setLineCol( |
| ((XSDElementNSImpl*)annotationElem)->getLineNo() |
| , ((XSDElementNSImpl*)annotationElem)->getColumnNo() |
| ); |
| theAnnotation->setSystemId(fSchemaInfo->getCurrentSchemaURL()); |
| |
| return theAnnotation; |
| } |
| |
| return 0; |
| } |
| |
| |
| /** |
| * Traverse include |
| * |
| * <include |
| * id = ID |
| * schemaLocation = anyURI |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation?) |
| * </include> |
| */ |
| void TraverseSchema::preprocessInclude(const DOMElement* const elem) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_Include, this, true, fNonXSAttList); |
| |
| // ----------------------------------------------------------------------- |
| // First, handle any ANNOTATION declaration |
| // ----------------------------------------------------------------------- |
| if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected); |
| |
| if (fAnnotation) |
| fSchemaGrammar->addAnnotation(fAnnotation); |
| else if (fScanner->getGenerateSyntheticAnnotations() && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| fSchemaGrammar->addAnnotation(fAnnotation); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Get 'schemaLocation' attribute |
| // ----------------------------------------------------------------------- |
| const XMLCh* schemaLocation = getElementAttValue(elem, SchemaSymbols::fgATT_SCHEMALOCATION, DatatypeValidator::AnyURI); |
| |
| if (!schemaLocation || !*schemaLocation) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNoSchemaLocation, SchemaSymbols::fgELT_INCLUDE); |
| return; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Resolve schema location |
| // ------------------------------------------------------------------ |
| fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0, |
| ((XSDElementNSImpl*) elem)->getLineNo(), |
| ((XSDElementNSImpl*) elem)->getColumnNo()); |
| InputSource* srcToFill = resolveSchemaLocation(schemaLocation, |
| XMLResourceIdentifier::SchemaInclude); |
| Janitor<InputSource> janSrc(srcToFill); |
| |
| // Nothing to do |
| if (!srcToFill) { |
| return; |
| } |
| |
| const XMLCh* includeURL = srcToFill->getSystemId(); |
| SchemaInfo* includeSchemaInfo = fCachedSchemaInfoList->get(includeURL, fTargetNSURI); |
| |
| if (!includeSchemaInfo && fSchemaInfoList != fCachedSchemaInfoList) |
| includeSchemaInfo = fSchemaInfoList->get(includeURL, fTargetNSURI); |
| |
| if (includeSchemaInfo) { |
| |
| fSchemaInfo->addSchemaInfo(includeSchemaInfo, SchemaInfo::INCLUDE); |
| return; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Parse input source |
| // ------------------------------------------------------------------ |
| if (!fParser) |
| fParser = new (fGrammarPoolMemoryManager) XSDDOMParser(0, fGrammarPoolMemoryManager, 0); |
| |
| fParser->setValidationScheme(XercesDOMParser::Val_Never); |
| fParser->setDoNamespaces(true); |
| fParser->setUserEntityHandler(fEntityHandler); |
| fParser->setUserErrorReporter(fErrorReporter); |
| |
| // Should just issue warning if the schema is not found |
| bool flag = srcToFill->getIssueFatalErrorIfNotFound(); |
| srcToFill->setIssueFatalErrorIfNotFound(false); |
| |
| fParser->parse(*srcToFill); |
| |
| // Reset the InputSource |
| srcToFill->setIssueFatalErrorIfNotFound(flag); |
| |
| if (fParser->getSawFatal() && fScanner->getExitOnFirstFatal()) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::SchemaScanFatalError); |
| |
| // ------------------------------------------------------------------ |
| // Get root element |
| // ------------------------------------------------------------------ |
| DOMDocument* document = fParser->getDocument(); |
| |
| if (document) { |
| |
| DOMElement* root = document->getDocumentElement(); |
| |
| if (root) { |
| |
| const XMLCh* targetNSURIString = root->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE); |
| |
| // check to see if targetNameSpace is right |
| if (*targetNSURIString |
| && !XMLString::equals(targetNSURIString,fTargetNSURIString)){ |
| reportSchemaError(root, XMLUni::fgXMLErrDomain, XMLErrs::IncludeNamespaceDifference, |
| schemaLocation, targetNSURIString); |
| return; |
| } |
| |
| // if targetNamespace is empty, change it to includ'g schema |
| // targetNamespace |
| if (!*targetNSURIString && root->getAttributeNode(XMLUni::fgXMLNSString) == 0 |
| && fTargetNSURI != fEmptyNamespaceURI) { |
| root->setAttribute(XMLUni::fgXMLNSString, fTargetNSURIString); |
| } |
| |
| // -------------------------------------------------------- |
| // Update schema information with included schema |
| // -------------------------------------------------------- |
| SchemaInfo* saveInfo = fSchemaInfo; |
| |
| fSchemaInfo = new (fMemoryManager) SchemaInfo(0, 0, 0, fTargetNSURI, |
| 0, |
| includeURL, |
| fTargetNSURIString, root, |
| fScanner, |
| fGrammarPoolMemoryManager); |
| |
| fSchemaInfo->getNamespaceScope()->reset(fEmptyNamespaceURI); |
| // Add mapping for the xml prefix |
| fSchemaInfo->getNamespaceScope()->addPrefix(XMLUni::fgXMLString, fURIStringPool->addOrFind(XMLUni::fgXMLURIName)); |
| |
| fSchemaInfoList->put((void*) fSchemaInfo->getCurrentSchemaURL(), |
| fSchemaInfo->getTargetNSURI(), fSchemaInfo); |
| fPreprocessedNodes->put((void*) elem, fSchemaInfo); |
| saveInfo->addSchemaInfo(fSchemaInfo, SchemaInfo::INCLUDE); |
| traverseSchemaHeader(root); |
| preprocessChildren(root); |
| fSchemaInfo = saveInfo; |
| } |
| } |
| } |
| |
| |
| void TraverseSchema::traverseInclude(const DOMElement* const elem) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| SchemaInfo* includeInfo = fPreprocessedNodes->get(elem); |
| |
| if (includeInfo) { |
| |
| SchemaInfo* saveInfo = fSchemaInfo; |
| |
| fSchemaInfo = includeInfo; |
| processChildren(includeInfo->getRoot()); |
| fSchemaInfo = saveInfo; |
| } |
| } |
| |
| |
| /** |
| * Traverse import |
| * |
| * <import |
| * id = ID |
| * namespace = anyURI |
| * schemaLocation = anyURI |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation?) |
| * </import> |
| */ |
| void TraverseSchema::preprocessImport(const DOMElement* const elem) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_Import, this, true, fNonXSAttList); |
| |
| // ----------------------------------------------------------------------- |
| // First, handle any ANNOTATION declaration |
| // ----------------------------------------------------------------------- |
| if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected); |
| |
| if (fAnnotation) |
| fSchemaGrammar->addAnnotation(fAnnotation); |
| else if (fScanner->getGenerateSyntheticAnnotations() && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| fSchemaGrammar->addAnnotation(fAnnotation); |
| } |
| // ----------------------------------------------------------------------- |
| // Handle 'namespace' attribute |
| // ----------------------------------------------------------------------- |
| const XMLCh* nameSpace = getElementAttValue(elem, SchemaSymbols::fgATT_NAMESPACE, DatatypeValidator::AnyURI); |
| const XMLCh* nameSpaceValue = nameSpace ? nameSpace : XMLUni::fgZeroLenString; |
| |
| if (XMLString::equals(nameSpaceValue, fTargetNSURIString)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::Import_1_1); |
| return; |
| } |
| |
| if (!*nameSpaceValue && fTargetNSURI == fEmptyNamespaceURI) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::Import_1_2); |
| return; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Get 'schemaLocation' attribute |
| // ------------------------------------------------------------------ |
| const XMLCh* schemaLocation = getElementAttValue(elem, SchemaSymbols::fgATT_SCHEMALOCATION, DatatypeValidator::AnyURI); |
| |
| // ------------------------------------------------------------------ |
| // Resolve namespace to a grammar |
| // ------------------------------------------------------------------ |
| Grammar* aGrammar = 0; |
| |
| { |
| XMLSchemaDescription* gramDesc =fGrammarResolver->getGrammarPool()->createSchemaDescription(nameSpaceValue); |
| Janitor<XMLSchemaDescription> janName(gramDesc); |
| gramDesc->setContextType(XMLSchemaDescription::CONTEXT_IMPORT); |
| gramDesc->setLocationHints(schemaLocation); |
| aGrammar = fGrammarResolver->getGrammar(gramDesc); |
| } |
| |
| bool grammarFound = (aGrammar && (aGrammar->getGrammarType() == Grammar::SchemaGrammarType)); |
| |
| if (grammarFound) { |
| addImportedNS(fURIStringPool->addOrFind(nameSpaceValue)); |
| } |
| |
| // a bare <xs:import/> doesn't load anything |
| if(!schemaLocation && !nameSpace) |
| return; |
| |
| // ------------------------------------------------------------------ |
| // Resolve schema location |
| // ------------------------------------------------------------------ |
| fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0, |
| ((XSDElementNSImpl*) elem)->getLineNo(), |
| ((XSDElementNSImpl*) elem)->getColumnNo()); |
| InputSource* srcToFill = resolveSchemaLocation(schemaLocation, |
| XMLResourceIdentifier::SchemaImport, nameSpace); |
| |
| // Nothing to do |
| if (!srcToFill) { |
| if (!grammarFound) { |
| addImportedNS(fURIStringPool->addOrFind(nameSpaceValue)); |
| } |
| |
| return; |
| } |
| |
| Janitor<InputSource> janSrc(srcToFill); |
| const XMLCh* importURL = srcToFill->getSystemId(); |
| unsigned int nameSpaceId = nameSpace ? fURIStringPool->addOrFind(nameSpace) : fEmptyNamespaceURI; |
| |
| SchemaInfo* importSchemaInfo = fCachedSchemaInfoList->get(importURL, nameSpaceId); |
| |
| if (!importSchemaInfo && fSchemaInfoList != fCachedSchemaInfoList) |
| importSchemaInfo = fSchemaInfoList->get(importURL, nameSpaceId); |
| |
| if (importSchemaInfo) { |
| fSchemaInfo->addSchemaInfo(importSchemaInfo, SchemaInfo::IMPORT); |
| addImportedNS(importSchemaInfo->getTargetNSURI()); |
| return; |
| } |
| |
| if (grammarFound) { |
| if (!fScanner->getHandleMultipleImports()) |
| return; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Parse input source |
| // ------------------------------------------------------------------ |
| if (!fParser) |
| fParser = new (fGrammarPoolMemoryManager) XSDDOMParser(0, fGrammarPoolMemoryManager, 0); |
| |
| fParser->setValidationScheme(XercesDOMParser::Val_Never); |
| fParser->setDoNamespaces(true); |
| fParser->setUserEntityHandler(fEntityHandler); |
| fParser->setUserErrorReporter(fErrorReporter); |
| |
| // Should just issue warning if the schema is not found |
| bool flag = srcToFill->getIssueFatalErrorIfNotFound(); |
| srcToFill->setIssueFatalErrorIfNotFound(false); |
| |
| fParser->parse(*srcToFill) ; |
| |
| // Reset the InputSource |
| srcToFill->setIssueFatalErrorIfNotFound(flag); |
| |
| if (fParser->getSawFatal() && fScanner->getExitOnFirstFatal()) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::SchemaScanFatalError); |
| |
| // ------------------------------------------------------------------ |
| // Get root element |
| // ------------------------------------------------------------------ |
| DOMDocument* document = fParser->getDocument(); |
| |
| if (document) { |
| |
| DOMElement* root = document->getDocumentElement(); |
| |
| if (!root) { |
| return; |
| } |
| |
| const XMLCh* targetNSURIString = root->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE); |
| |
| if (!XMLString::equals(targetNSURIString, nameSpaceValue)) { |
| reportSchemaError(root, XMLUni::fgXMLErrDomain, XMLErrs::ImportNamespaceDifference, |
| schemaLocation, targetNSURIString, nameSpaceValue); |
| } |
| else { |
| |
| // -------------------------------------------------------- |
| // Preprocess new schema |
| // -------------------------------------------------------- |
| SchemaInfo* saveInfo = fSchemaInfo; |
| fSchemaGrammar->setScopeCount (fScopeCount); |
| fSchemaGrammar->setAnonTypeCount (fAnonXSTypeCount); |
| if (grammarFound) { |
| fSchemaGrammar = (SchemaGrammar*) aGrammar; |
| } |
| else { |
| fSchemaGrammar = new (fGrammarPoolMemoryManager) SchemaGrammar(fGrammarPoolMemoryManager); |
| } |
| fScopeCount = fSchemaGrammar->getScopeCount (); |
| fAnonXSTypeCount = fSchemaGrammar->getAnonTypeCount (); |
| |
| XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) fSchemaGrammar->getGrammarDescription(); |
| gramDesc->setContextType(XMLSchemaDescription::CONTEXT_IMPORT); |
| gramDesc->setLocationHints(importURL); |
| |
| preprocessSchema(root, importURL, grammarFound); |
| fPreprocessedNodes->put((void*) elem, fSchemaInfo); |
| |
| // -------------------------------------------------------- |
| // Restore old schema information |
| // -------------------------------------------------------- |
| restoreSchemaInfo(saveInfo, SchemaInfo::IMPORT); |
| } |
| } |
| } |
| |
| |
| void TraverseSchema::traverseImport(const DOMElement* const elem) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| SchemaInfo* importInfo = fPreprocessedNodes->get(elem); |
| |
| if (importInfo) { |
| |
| // -------------------------------------------------------- |
| // Traverse new schema |
| // -------------------------------------------------------- |
| SchemaInfo* saveInfo = fSchemaInfo; |
| |
| restoreSchemaInfo(importInfo, SchemaInfo::IMPORT); |
| doTraverseSchema(importInfo->getRoot()); |
| |
| // -------------------------------------------------------- |
| // Restore old schema information |
| // -------------------------------------------------------- |
| restoreSchemaInfo(saveInfo, SchemaInfo::IMPORT); |
| } |
| } |
| |
| |
| /** |
| * Traverse redefine declaration |
| * |
| * <redefine> |
| * schemaLocation = uriReference |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation | ( |
| * attributeGroup | complexType | group | simpleType))* |
| * </redefine> |
| */ |
| void TraverseSchema::preprocessRedefine(const DOMElement* const redefineElem) { |
| |
| NamespaceScopeManager nsMgr(redefineElem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| redefineElem, GeneralAttributeCheck::E_Redefine, this, true |
| ); |
| |
| // First, we look through the children of redefineElem. Each one will |
| // correspond to an element of the redefined schema that we need to |
| // redefine. To do this, we rename the element of the redefined schema, |
| // and rework the base or ref tag of the kid we're working on to refer to |
| // the renamed group or derive the renamed type. Once we've done this, we |
| // actually go through the schema being redefined and convert it to a |
| // grammar. Only then do we run through redefineDecl's kids and put them |
| // in the grammar. |
| SchemaInfo* redefiningInfo = fSchemaInfo; |
| |
| if (!openRedefinedSchema(redefineElem)) { |
| |
| redefiningInfo->addFailedRedefine(redefineElem); |
| return; |
| } |
| |
| if (!fRedefineComponents) { |
| fRedefineComponents = new (fMemoryManager) RefHash2KeysTableOf<XMLCh>(13, (bool) false, fMemoryManager); |
| } |
| |
| SchemaInfo* redefinedInfo = fSchemaInfo; |
| renameRedefinedComponents(redefineElem, redefiningInfo, redefinedInfo); |
| |
| // Now we have to preprocess our nicely-renamed schemas. |
| if (fPreprocessedNodes->containsKey(redefineElem)) { |
| |
| fSchemaInfo = redefinedInfo; |
| preprocessChildren(fSchemaInfo->getRoot()); |
| } |
| |
| fSchemaInfo = redefiningInfo; |
| } |
| |
| void TraverseSchema::traverseRedefine(const DOMElement* const redefineElem) { |
| |
| NamespaceScopeManager nsMgr(redefineElem, fSchemaInfo, this); |
| |
| SchemaInfo* saveInfo = fSchemaInfo; |
| SchemaInfo* redefinedInfo = fPreprocessedNodes->get(redefineElem); |
| |
| if (redefinedInfo) { |
| |
| // Now we have to march through our nicely-renamed schemas. When |
| // we do these traversals other <redefine>'s may perhaps be |
| // encountered; we leave recursion to sort this out. |
| fSchemaInfo = redefinedInfo; |
| processChildren(fSchemaInfo->getRoot()); |
| fSchemaInfo = saveInfo; |
| |
| // Now traverse our own <redefine> |
| processChildren(redefineElem); |
| } |
| } |
| |
| |
| /** |
| * Traverse the Choice, Sequence declaration |
| * |
| * <choice-sequence |
| * id = ID |
| * maxOccurs = (nonNegativeInteger | unbounded) : 1 |
| * minOccurs = nonNegativeInteger : 1 |
| * Content: (annotation?, (element | group | choice | sequence | any)*) |
| * </choice-sequence> |
| */ |
| ContentSpecNode* |
| TraverseSchema::traverseChoiceSequence(const DOMElement* const elem, |
| const int modelGroupType, |
| bool& hasChildren) |
| { |
| hasChildren = false; |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_Sequence, this, false, fNonXSAttList |
| ); |
| |
| // ----------------------------------------------------------------------- |
| // Process contents |
| // ----------------------------------------------------------------------- |
| DOMElement* child = checkContent(elem, XUtil::getFirstChildElement(elem), true); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| Janitor<ContentSpecNode> left(0); |
| Janitor<ContentSpecNode> right(0); |
| |
| bool hadContent = false; |
| |
| Janitor<ContentSpecNode> contentSpecNode(0); |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| hasChildren = true; |
| contentSpecNode.release(); |
| bool seeParticle = false; |
| bool wasAny = false; |
| const XMLCh* childName = child->getLocalName(); |
| |
| if (XMLString::equals(childName, SchemaSymbols::fgELT_ELEMENT)) { |
| |
| SchemaElementDecl* elemDecl = traverseElementDecl(child); |
| |
| if (!elemDecl ) |
| continue; |
| |
| contentSpecNode.reset(new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| elemDecl |
| , fGrammarPoolMemoryManager |
| )); |
| seeParticle = true; |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_GROUP)) { |
| |
| XercesGroupInfo* grpInfo = traverseGroupDecl(child, false); |
| |
| if (!grpInfo) { |
| continue; |
| } |
| |
| ContentSpecNode* grpContentSpecNode = grpInfo->getContentSpec(); |
| |
| if (!grpContentSpecNode) { |
| continue; |
| } |
| |
| if (grpContentSpecNode->hasAllContent()) { |
| |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::AllContentLimited); |
| continue; |
| } |
| |
| contentSpecNode.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*grpContentSpecNode)); |
| seeParticle = true; |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_CHOICE)) { |
| bool hasChild; |
| contentSpecNode.reset(traverseChoiceSequence(child,ContentSpecNode::Choice, hasChild)); |
| seeParticle = true; |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_SEQUENCE)) { |
| bool hasChild; |
| contentSpecNode.reset(traverseChoiceSequence(child,ContentSpecNode::Sequence, hasChild)); |
| seeParticle = true; |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_ANY)) { |
| |
| contentSpecNode.reset(traverseAny(child)); |
| seeParticle = true; |
| wasAny = true; |
| } |
| else { |
| reportSchemaError(child, XMLUni::fgValidityDomain, XMLValid::GroupContentRestricted, |
| childName, |
| ((ContentSpecNode::NodeTypes) modelGroupType) == ContentSpecNode::Choice?SchemaSymbols::fgELT_CHOICE:SchemaSymbols::fgELT_SEQUENCE); |
| } |
| |
| if (seeParticle) { |
| checkMinMax(contentSpecNode.get(), child, Not_All_Context); |
| if (wasAny && contentSpecNode.get()->getMaxOccurs() == 0) { |
| contentSpecNode.reset(0); |
| } |
| } |
| |
| if (contentSpecNode.get()) { |
| hadContent = true; |
| } |
| |
| if (left.get() == 0) { |
| left.reset(contentSpecNode.release()); |
| } |
| else if (right.get() == 0) { |
| right.reset(contentSpecNode.release()); |
| } |
| else { |
| ContentSpecNode* newNode = |
| new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| (ContentSpecNode::NodeTypes) modelGroupType |
| , left.get() |
| , right.get() |
| , true |
| , true |
| , fGrammarPoolMemoryManager |
| ); |
| |
| left.release(); |
| right.release(); |
| |
| left.reset(newNode); |
| right.reset(contentSpecNode.release()); |
| } |
| } |
| contentSpecNode.release(); |
| |
| if (hadContent) |
| { |
| ContentSpecNode* newNode = |
| new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| ((ContentSpecNode::NodeTypes) modelGroupType) == ContentSpecNode::Choice |
| ? ContentSpecNode::ModelGroupChoice : ContentSpecNode::ModelGroupSequence |
| , left.get() |
| , right.get() |
| , true |
| , true |
| , fGrammarPoolMemoryManager |
| ); |
| |
| left.release(); |
| |
| left.reset(newNode); |
| |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(left.get(), janAnnot.release()); |
| } |
| |
| right.release(); |
| return left.release(); |
| } |
| |
| /** |
| * Traverse SimpleType declaration: |
| * <simpleType |
| * id = ID |
| * name = NCName> |
| * Content: (annotation? , ((list | restriction | union))) |
| * </simpleType> |
| * |
| * traverse <list>|<restriction>|<union> |
| */ |
| DatatypeValidator* |
| TraverseSchema::traverseSimpleTypeDecl(const DOMElement* const childElem, |
| const bool topLevel, int baseRefContext) |
| { |
| NamespaceScopeManager nsMgr(childElem, fSchemaInfo, this); |
| |
| // ------------------------------------------------------------------ |
| // Process contents |
| // ------------------------------------------------------------------ |
| const XMLCh* name = getElementAttValue(childElem,SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| bool nameEmpty = (!name || !*name); |
| |
| if (topLevel && nameEmpty) { |
| reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameGlobalElement, |
| SchemaSymbols::fgELT_SIMPLETYPE); |
| return 0; |
| } |
| else if(!topLevel && !nameEmpty) { |
| reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeDisallowedLocal, |
| SchemaSymbols::fgATT_NAME, childElem->getLocalName()); |
| return 0; |
| } |
| |
| if (nameEmpty) { // anonymous simpleType |
| name = genAnonTypeName(fgAnonSNamePrefix); |
| } |
| else if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name)) ) { |
| |
| reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, |
| SchemaSymbols::fgELT_SIMPLETYPE, name); |
| return 0; |
| } |
| |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(name); |
| |
| unsigned int fullTypeNameId = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| const XMLCh* fullName = fStringPool->getValueForId(fullTypeNameId); |
| |
| //check if we have already traversed the same simpleType decl |
| DatatypeValidator* dv = fDatatypeRegistry->getDatatypeValidator(fullName); |
| |
| if (!dv) { |
| |
| // ------------------------------------------------------------------- |
| // Check attributes |
| // ------------------------------------------------------------------- |
| unsigned short scope = (topLevel) ? GeneralAttributeCheck::E_SimpleTypeGlobal |
| : GeneralAttributeCheck::E_SimpleTypeLocal; |
| |
| fAttributeCheck.checkAttributes( |
| childElem, scope, this, topLevel, fNonXSAttList |
| ); |
| |
| // Circular constraint checking |
| if (fCurrentTypeNameStack->containsElement(fullTypeNameId)) { |
| |
| reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, name); |
| return 0; |
| } |
| |
| fCurrentTypeNameStack->addElement(fullTypeNameId); |
| |
| // Get 'final' values |
| int finalSet = parseFinalSet(childElem, S_Final); |
| |
| // annotation?,(list|restriction|union) |
| DOMElement* content= checkContent( |
| childElem, XUtil::getFirstChildElement(childElem), false); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(childElem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| if (content == 0) { |
| |
| reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::EmptySimpleTypeContent); |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| const XMLCh* varietyName = content->getLocalName(); |
| |
| // Remark: some code will be repeated in list|restriction| union but it |
| // is cleaner that way |
| if (XMLString::equals(varietyName, SchemaSymbols::fgELT_LIST)) { //traverse List |
| if ((baseRefContext & SchemaSymbols::XSD_LIST) != 0) { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AtomicItemType); |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| dv = traverseByList(childElem, content, name, fullName, finalSet, &janAnnot); |
| } |
| else if (XMLString::equals(varietyName, SchemaSymbols::fgELT_RESTRICTION)) { //traverse Restriction |
| dv = traverseByRestriction(childElem, content, name, fullName, finalSet, &janAnnot); |
| } |
| else if (XMLString::equals(varietyName, SchemaSymbols::fgELT_UNION)) { //traverse union |
| dv = traverseByUnion(childElem, content, name, fullName, finalSet, baseRefContext, &janAnnot); |
| } |
| else { |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::FeatureUnsupported, varietyName); |
| popCurrentTypeNameStack(); |
| } |
| |
| if (dv) { |
| if (nameEmpty) |
| dv->setAnonymous(); |
| |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(dv, janAnnot.release()); |
| } |
| } |
| |
| return dv; |
| } |
| |
| /** |
| * Traverse ComplexType Declaration - CR Implementation. |
| * |
| * <complexType |
| * abstract = boolean |
| * block = #all or (possibly empty) subset of {extension, restriction} |
| * final = #all or (possibly empty) subset of {extension, restriction} |
| * id = ID |
| * mixed = boolean : false |
| * name = NCName> |
| * Content: (annotation? , (simpleContent | complexContent | |
| * ( (group | all | choice | sequence)? , |
| * ( (attribute | attributeGroup)* , anyAttribute?)))) |
| * </complexType> |
| */ |
| int TraverseSchema::traverseComplexTypeDecl(const DOMElement* const elem, |
| const bool topLevel, |
| const XMLCh* const recursingTypeName) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // Get the attributes of the complexType |
| const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| bool isAnonymous = false; |
| |
| if (!name || !*name) { |
| |
| if (topLevel) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelNoNameComplexType); |
| return -1; |
| } |
| |
| if (recursingTypeName) |
| name = recursingTypeName; |
| else { |
| name = genAnonTypeName(fgAnonCNamePrefix); |
| isAnonymous = true; |
| } |
| } |
| |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name)) ) { |
| |
| //REVISIT - Should we return or continue and save type with wrong name? |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, |
| SchemaSymbols::fgELT_COMPLEXTYPE, name); |
| return -1; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Check if the type has already been registered |
| // ------------------------------------------------------------------ |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(name); |
| |
| int typeNameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| const XMLCh* fullName = fStringPool->getValueForId(typeNameIndex); |
| ComplexTypeInfo* typeInfo = 0; |
| |
| if (topLevel || recursingTypeName) { |
| |
| typeInfo = fComplexTypeRegistry->get(fullName); |
| |
| if (typeInfo && !typeInfo->getPreprocessed()) { |
| return typeNameIndex; |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| bool preProcessFlag = (typeInfo) ? typeInfo->getPreprocessed() : false; |
| if (!preProcessFlag) { |
| fAttributeCheck.checkAttributes( |
| elem, (topLevel) ? GeneralAttributeCheck::E_ComplexTypeGlobal |
| : GeneralAttributeCheck::E_ComplexTypeLocal |
| , this, topLevel, fNonXSAttList |
| ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Create a new instance |
| // ----------------------------------------------------------------------- |
| XMLSize_t previousCircularCheckIndex = fCircularCheckIndex; |
| unsigned int previousScope = fCurrentScope; |
| |
| if (preProcessFlag) { |
| |
| fCurrentScope = typeInfo->getScopeDefined(); |
| typeInfo->setPreprocessed(false); |
| } |
| else { |
| |
| // ------------------------------------------------------------------ |
| // Register the type |
| // ------------------------------------------------------------------ |
| typeInfo = new (fGrammarPoolMemoryManager) ComplexTypeInfo(fGrammarPoolMemoryManager); |
| if(isAnonymous) { |
| typeInfo->setAnonymous(); |
| } |
| |
| fCurrentScope = fScopeCount++; |
| fComplexTypeRegistry->put((void*) fullName, typeInfo); |
| typeInfo->setTypeName(fullName); |
| typeInfo->setScopeDefined(fCurrentScope); |
| |
| if (fFullConstraintChecking) { |
| |
| XSDLocator* aLocator = new (fGrammarPoolMemoryManager) XSDLocator(); |
| aLocator->setValues(fStringPool->getValueForId(fStringPool->addOrFind(fSchemaInfo->getCurrentSchemaURL())), |
| 0, ((XSDElementNSImpl*) elem)->getLineNo(), |
| ((XSDElementNSImpl*) elem)->getColumnNo()); |
| typeInfo->setLocator(aLocator); |
| } |
| } |
| |
| fCurrentTypeNameStack->addElement(typeNameIndex); |
| ComplexTypeInfo* saveTypeInfo = fCurrentComplexType; |
| fCurrentComplexType = typeInfo; |
| |
| // ------------------------------------------------------------------ |
| // First, handle any ANNOTATION declaration and get next child |
| // ------------------------------------------------------------------ |
| DOMElement* child = checkContent(elem, XUtil::getFirstChildElement(elem), true, !preProcessFlag); |
| |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| |
| // ------------------------------------------------------------------ |
| // Process the content of the complex type declaration |
| // ------------------------------------------------------------------ |
| try { |
| |
| const XMLCh* mixedVal = getElementAttValue(elem,SchemaSymbols::fgATT_MIXED, DatatypeValidator::Boolean); |
| bool isMixed = false; |
| |
| if ((mixedVal && *mixedVal) |
| && (XMLString::equals(SchemaSymbols::fgATTVAL_TRUE, mixedVal) |
| || XMLString::equals(fgValueOne, mixedVal))) { |
| isMixed = true; |
| } |
| |
| if (child == 0) { |
| // EMPTY complexType with complexContent |
| processComplexContent(elem, name, child, typeInfo, 0, isMixed); |
| } |
| else { |
| |
| const XMLCh* childName = child->getLocalName(); |
| |
| if (XMLString::equals(childName, SchemaSymbols::fgELT_SIMPLECONTENT)) { |
| |
| // SIMPLE CONTENT element |
| traverseSimpleContentDecl(name, fullName, child, typeInfo, &janAnnot); |
| |
| if (XUtil::getNextSiblingElement(child) != 0) { |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildFollowingSimpleContent); |
| } |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_COMPLEXCONTENT)) { |
| |
| // COMPLEX CONTENT element |
| traverseComplexContentDecl(name, child, typeInfo, isMixed, &janAnnot); |
| |
| if (XUtil::getNextSiblingElement(child) != 0) { |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildFollowingConplexContent); |
| } |
| } |
| else if (fCurrentGroupInfo) { |
| typeInfo->setPreprocessed(true); |
| } |
| else { |
| // We must have .... |
| // GROUP, ALL, SEQUENCE or CHOICE, followed by optional attributes |
| // Note that it's possible that only attributes are specified. |
| processComplexContent(elem, name, child, typeInfo, 0, isMixed); |
| } |
| } |
| } |
| catch(const TraverseSchema::ExceptionCodes aCode) { |
| if (aCode == TraverseSchema::InvalidComplexTypeInfo) |
| defaultComplexTypeInfo(typeInfo); |
| else if (aCode == TraverseSchema::RecursingElement) |
| typeInfo->setPreprocessed(); |
| } |
| |
| // ------------------------------------------------------------------ |
| // Finish the setup of the typeInfo |
| // ------------------------------------------------------------------ |
| if (!preProcessFlag) { |
| |
| const XMLCh* abstractAttVal = getElementAttValue(elem, SchemaSymbols::fgATT_ABSTRACT, DatatypeValidator::Boolean); |
| int blockSet = parseBlockSet(elem, C_Block); |
| int finalSet = parseFinalSet(elem, EC_Final); |
| |
| typeInfo->setBlockSet(blockSet); |
| typeInfo->setFinalSet(finalSet); |
| |
| if ((abstractAttVal && *abstractAttVal) |
| && (XMLString::equals(abstractAttVal, SchemaSymbols::fgATTVAL_TRUE) |
| || XMLString::equals(abstractAttVal, fgValueOne))) { |
| typeInfo->setAbstract(true); |
| } |
| else { |
| typeInfo->setAbstract(false); |
| } |
| } |
| |
| // Store Annotation |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(typeInfo, janAnnot.release()); |
| |
| // ------------------------------------------------------------------ |
| // Before exiting, restore the scope, mainly for nested anonymous types |
| // ------------------------------------------------------------------ |
| popCurrentTypeNameStack(); |
| fCircularCheckIndex = previousCircularCheckIndex; |
| fCurrentScope = previousScope; |
| fCurrentComplexType = saveTypeInfo; |
| |
| return typeNameIndex; |
| } |
| |
| /** |
| * Traverse Group Declaration. |
| * |
| * <group |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger |
| * name = NCName |
| * ref = QName> |
| * Content: (annotation? , (all | choice | sequence)?) |
| * <group/> |
| * |
| */ |
| XercesGroupInfo* |
| TraverseSchema::traverseGroupDecl(const DOMElement* const elem, |
| const bool topLevel) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| const XMLCh* ref = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName); |
| bool nameEmpty = (!name || !*name); |
| bool refEmpty = (!ref || !*ref); |
| |
| if (nameEmpty && topLevel) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameGlobalElement, |
| SchemaSymbols::fgELT_GROUP); |
| return 0; |
| } |
| |
| if (nameEmpty && refEmpty) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefGroup); |
| return 0; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Check attributes |
| // ------------------------------------------------------------------ |
| unsigned short scope = (topLevel) ? GeneralAttributeCheck::E_GroupGlobal |
| : GeneralAttributeCheck::E_GroupRef; |
| fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList); |
| |
| // ------------------------------------------------------------------ |
| // Handle "ref=" |
| // ------------------------------------------------------------------ |
| if (!topLevel) { |
| |
| if (refEmpty) { |
| return 0; |
| } |
| |
| return processGroupRef(elem, ref); |
| } |
| |
| // name must be a valid NCName |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, |
| SchemaSymbols::fgELT_GROUP, name); |
| return 0; |
| } |
| |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(name); |
| |
| unsigned int nameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| const XMLCh* fullName = fStringPool->getValueForId(nameIndex); |
| XercesGroupInfo* groupInfo = fGroupRegistry->get(fullName); |
| |
| if (groupInfo) { |
| return groupInfo; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Check for annotations |
| // ------------------------------------------------------------------ |
| DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| // ------------------------------------------------------------------ |
| // Process contents of global groups |
| // ------------------------------------------------------------------ |
| unsigned int saveScope = fCurrentScope; |
| Janitor<ContentSpecNode> specNode(0); |
| XercesGroupInfo* saveGroupInfo = fCurrentGroupInfo; |
| |
| Janitor<XercesGroupInfo> newGroupInfoJan(new (fGrammarPoolMemoryManager) XercesGroupInfo( |
| fStringPool->addOrFind(name), fTargetNSURI, fGrammarPoolMemoryManager)); |
| fCurrentGroupStack->addElement(nameIndex); |
| XercesGroupInfo* const newGroupInfo = newGroupInfoJan.get(); |
| fCurrentGroupInfo = newGroupInfo; |
| |
| fCurrentScope = fScopeCount++; |
| fCurrentGroupInfo->setScope(fCurrentScope); |
| |
| if (content == 0) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::GroupContentError, name); |
| } |
| else { |
| |
| if (content->getAttributeNode(SchemaSymbols::fgATT_MINOCCURS) != 0 |
| || content->getAttributeNode(SchemaSymbols::fgATT_MAXOCCURS) != 0) { |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::MinMaxOnGroupChild); |
| } |
| |
| bool illegalChild = false; |
| const XMLCh* childName = content->getLocalName(); |
| bool hasChild; |
| |
| |
| if (XMLString::equals(childName, SchemaSymbols::fgELT_SEQUENCE)) { |
| specNode.reset(traverseChoiceSequence(content, ContentSpecNode::Sequence, hasChild)); |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_CHOICE)) { |
| specNode.reset(traverseChoiceSequence(content, ContentSpecNode::Choice, hasChild)); |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_ALL)) { |
| specNode.reset(traverseAll(content, hasChild)); |
| } |
| else { |
| illegalChild = true; |
| } |
| |
| if (illegalChild || XUtil::getNextSiblingElement(content) != 0) { |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::GroupContentError, name); |
| } |
| |
| // copy local elements to complex type if it exists |
| if (fCurrentComplexType) |
| processElements(elem, fCurrentGroupInfo, fCurrentComplexType); |
| } |
| |
| // ------------------------------------------------------------------ |
| // Set groupInfo and pop group name from stack |
| // ------------------------------------------------------------------ |
| XMLSize_t stackSize = fCurrentGroupStack->size(); |
| |
| if (stackSize != 0) { |
| fCurrentGroupStack->removeElementAt(stackSize - 1); |
| } |
| |
| fCurrentGroupInfo->setContentSpec(specNode.release()); |
| fGroupRegistry->put((void*) fullName, fCurrentGroupInfo); |
| newGroupInfoJan.release(); |
| fCurrentGroupInfo = saveGroupInfo; |
| fCurrentScope = saveScope; |
| |
| // Store Annotation |
| if (!janAnnot.isDataNull()) { |
| fSchemaGrammar->putAnnotation(newGroupInfo, janAnnot.release()); |
| } |
| |
| if (fFullConstraintChecking) { |
| |
| XSDLocator* aLocator = new (fGrammarPoolMemoryManager) XSDLocator(); |
| |
| newGroupInfo->setLocator(aLocator); |
| aLocator->setValues(fStringPool->getValueForId(fStringPool->addOrFind(fSchemaInfo->getCurrentSchemaURL())), |
| 0, ((XSDElementNSImpl*) elem)->getLineNo(), |
| ((XSDElementNSImpl*) elem)->getColumnNo()); |
| |
| if (fRedefineComponents && fRedefineComponents->get(SchemaSymbols::fgELT_GROUP, nameIndex)) |
| { |
| |
| fBuffer.set(fullName); |
| fBuffer.append(SchemaSymbols::fgRedefIdentifier); |
| unsigned int rdfNameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| |
| if (fCurrentGroupStack->containsElement(rdfNameIndex)) |
| { |
| reportSchemaError(aLocator, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, name); |
| } |
| else |
| { |
| XercesGroupInfo* baseGroup = fGroupRegistry->get(fBuffer.getRawBuffer()); |
| if (baseGroup) |
| { |
| newGroupInfo->setBaseGroup(baseGroup); |
| } |
| else |
| { |
| fBuffer.set(name); |
| fBuffer.append(SchemaSymbols::fgRedefIdentifier); |
| SchemaInfo* saveInfo = fSchemaInfo; |
| DOMElement* groupElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Group, |
| SchemaSymbols::fgELT_GROUP, fBuffer.getRawBuffer(), &fSchemaInfo); |
| |
| if (groupElem != 0) { |
| baseGroup = traverseGroupDecl(groupElem); |
| newGroupInfo->setBaseGroup(baseGroup); |
| fSchemaInfo = saveInfo; |
| } |
| else |
| { |
| reportSchemaError(aLocator, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound, |
| SchemaSymbols::fgELT_GROUP, fTargetNSURIString, fBuffer.getRawBuffer()); |
| } |
| } |
| } |
| } |
| } |
| |
| return newGroupInfo; |
| } |
| |
| |
| /** |
| * Traverse attributeGroup Declaration. |
| * |
| * <attributeGroup |
| * id = ID |
| * name = NCName |
| * ref = QName> |
| * Content: (annotation? , (attribute|attributeGroup)*, anyAttribute?) |
| * <attributeGroup/> |
| * |
| */ |
| XercesAttGroupInfo* |
| TraverseSchema::traverseAttributeGroupDecl(const DOMElement* const elem, |
| ComplexTypeInfo* const typeInfo, |
| const bool topLevel) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| const XMLCh* ref = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName); |
| bool nameEmpty = (!name || !*name) ? true : false; |
| bool refEmpty = (!ref || !*ref) ? true : false; |
| |
| if (nameEmpty && topLevel) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameGlobalElement, |
| SchemaSymbols::fgELT_ATTRIBUTEGROUP); |
| return 0; |
| } |
| |
| if (nameEmpty && refEmpty) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefAttGroup); |
| return 0; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Check attributes |
| // ------------------------------------------------------------------ |
| unsigned short scope = (topLevel) ? GeneralAttributeCheck::E_AttributeGroupGlobal |
| : GeneralAttributeCheck::E_AttributeGroupRef; |
| fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList); |
| |
| // ------------------------------------------------------------------ |
| // Handle "ref=" |
| // ------------------------------------------------------------------ |
| XercesAttGroupInfo* attGroupInfo; |
| Janitor<XercesAttGroupInfo> janAttGroupInfo(0); |
| if (!topLevel) { |
| |
| if (refEmpty) { |
| return 0; |
| } |
| |
| attGroupInfo = processAttributeGroupRef(elem, ref, typeInfo); |
| } |
| else |
| { |
| // name must be a valid NCName |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, |
| SchemaSymbols::fgELT_ATTRIBUTEGROUP, name); |
| return 0; |
| } |
| |
| // Check for annotations |
| DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| |
| // Process contents of global attributeGroups |
| XercesAttGroupInfo* saveAttGroupInfo = fCurrentAttGroupInfo; |
| janAttGroupInfo.reset(new (fGrammarPoolMemoryManager) XercesAttGroupInfo( |
| fStringPool->addOrFind(name), fTargetNSURI, fGrammarPoolMemoryManager)); |
| |
| fDeclStack->addElement(elem); |
| fCurrentAttGroupInfo = janAttGroupInfo.get(); |
| |
| for (; content !=0; content = XUtil::getNextSiblingElement(content)) { |
| |
| if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ATTRIBUTE)) { |
| traverseAttributeDecl(content, typeInfo); |
| } |
| else if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ATTRIBUTEGROUP)) { |
| traverseAttributeGroupDecl(content, typeInfo); |
| } |
| else { |
| break; |
| } |
| } |
| |
| if (content != 0) { |
| |
| if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ANYATTRIBUTE)) { |
| |
| SchemaAttDef* anyAtt = traverseAnyAttribute(content); |
| |
| if (anyAtt) { |
| fCurrentAttGroupInfo->addAnyAttDef(anyAtt); |
| } |
| |
| if (XUtil::getNextSiblingElement(content) != 0) { |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AttGroupContentError, name); |
| } |
| } |
| else { |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AttGroupContentError, name); |
| } |
| } |
| |
| // Pop declaration |
| fDeclStack->removeElementAt(fDeclStack->size() - 1); |
| |
| fAttGroupRegistry->put((void*) fStringPool->getValueForId(fStringPool->addOrFind(name)), janAttGroupInfo.get()); |
| // Restore old attGroupInfo |
| attGroupInfo = janAttGroupInfo.release(); |
| fCurrentAttGroupInfo = saveAttGroupInfo; |
| |
| // Check Attribute Derivation Restriction OK |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(name); |
| |
| unsigned int nameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| |
| if (fRedefineComponents && fRedefineComponents->get(SchemaSymbols::fgELT_ATTRIBUTEGROUP, nameIndex)) { |
| |
| fBuffer.set(name); |
| fBuffer.append(SchemaSymbols::fgRedefIdentifier); |
| XercesAttGroupInfo* baseAttGroupInfo = fAttGroupRegistry->get(fBuffer.getRawBuffer()); |
| |
| if (baseAttGroupInfo) |
| checkAttDerivationOK(elem, baseAttGroupInfo, attGroupInfo); |
| } |
| |
| // Store annotation |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(attGroupInfo, janAnnot.release()); |
| } |
| |
| // calculate complete wildcard if necessary |
| if (attGroupInfo) |
| { |
| XMLSize_t anyAttCount = attGroupInfo->anyAttributeCount(); |
| if (anyAttCount && !attGroupInfo->getCompleteWildCard()) |
| { |
| SchemaAttDef* attGroupWildCard = new (fGrammarPoolMemoryManager) |
| SchemaAttDef(attGroupInfo->anyAttributeAt(0)); |
| |
| for (XMLSize_t k= 1; k < anyAttCount; k++) |
| attWildCardIntersection(attGroupWildCard, attGroupInfo->anyAttributeAt(k)); |
| |
| attGroupInfo->setCompleteWildCard(attGroupWildCard); |
| } |
| } |
| |
| return attGroupInfo; |
| } |
| |
| |
| inline XercesAttGroupInfo* |
| TraverseSchema::traverseAttributeGroupDeclNS(const DOMElement* const elem, |
| const XMLCh* const uriStr, |
| const XMLCh* const name) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // ------------------------------------------------------------------ |
| // Get grammar information |
| // ------------------------------------------------------------------ |
| Grammar* aGrammar = fGrammarResolver->getGrammar(uriStr); |
| |
| if (!aGrammar || aGrammar->getGrammarType() != Grammar::SchemaGrammarType) { |
| |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr); |
| return 0; |
| } |
| |
| XercesAttGroupInfo* attGroupInfo = ((SchemaGrammar*)aGrammar)->getAttGroupInfoRegistry()->get(name); |
| |
| return attGroupInfo; |
| } |
| |
| /** |
| * Traverse Any declaration |
| * |
| * <any |
| * id = ID |
| * maxOccurs = (nonNegativeInteger | unbounded) : 1 |
| * minOccurs = nonNegativeInteger : 1 |
| * namespace = ((##any | ##other) | List of (anyURI | |
| * (##targetNamespace | ##local)) ) : ##any |
| * processContents = (lax | skip | strict) : strict |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation?) |
| * </any> |
| */ |
| ContentSpecNode* |
| TraverseSchema::traverseAny(const DOMElement* const elem) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_Any, this, false, fNonXSAttList |
| ); |
| |
| // ------------------------------------------------------------------ |
| // First, handle any ANNOTATION declaration |
| // ------------------------------------------------------------------ |
| if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| |
| // ------------------------------------------------------------------ |
| // Get attributes |
| // ------------------------------------------------------------------ |
| const XMLCh* const processContents = getElementAttValue(elem, SchemaSymbols::fgATT_PROCESSCONTENTS); |
| const XMLCh* const nameSpace = getElementAttValue(elem, SchemaSymbols::fgATT_NAMESPACE); |
| |
| // ------------------------------------------------------------------ |
| // Set default node type based on 'processContents' value |
| // ------------------------------------------------------------------ |
| ContentSpecNode::NodeTypes anyType = ContentSpecNode::Any; |
| ContentSpecNode::NodeTypes anyLocalType = ContentSpecNode::Any_NS; |
| ContentSpecNode::NodeTypes anyOtherType = ContentSpecNode::Any_Other; |
| |
| if ((processContents && *processContents) |
| && !XMLString::equals(processContents, SchemaSymbols::fgATTVAL_STRICT)) { |
| |
| if (XMLString::equals(processContents, SchemaSymbols::fgATTVAL_LAX)) { |
| |
| anyType = ContentSpecNode::Any_Lax; |
| anyOtherType = ContentSpecNode::Any_Other_Lax; |
| anyLocalType = ContentSpecNode::Any_NS_Lax; |
| } |
| else if (XMLString::equals(processContents, SchemaSymbols::fgATTVAL_SKIP)) { |
| |
| anyType = ContentSpecNode::Any_Skip; |
| anyOtherType = ContentSpecNode::Any_Other_Skip; |
| anyLocalType = ContentSpecNode::Any_NS_Skip; |
| } |
| } |
| |
| // ------------------------------------------------------------------ |
| // Process 'namespace' attribute |
| // ------------------------------------------------------------------ |
| ContentSpecNode* retSpecNode = 0; |
| |
| if ((!nameSpace || !*nameSpace) |
| || XMLString::equals(nameSpace, SchemaSymbols::fgATTVAL_TWOPOUNDANY)) { |
| retSpecNode = new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| new (fGrammarPoolMemoryManager) QName |
| ( |
| XMLUni::fgZeroLenString |
| , XMLUni::fgZeroLenString |
| , fEmptyNamespaceURI |
| , fGrammarPoolMemoryManager |
| ) |
| , false |
| , fGrammarPoolMemoryManager |
| ); |
| retSpecNode->setType(anyType); |
| } |
| else if (XMLString::equals(nameSpace, SchemaSymbols::fgATTVAL_TWOPOUNDOTHER)) { |
| retSpecNode = new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| new (fGrammarPoolMemoryManager) QName |
| ( |
| XMLUni::fgZeroLenString |
| , XMLUni::fgZeroLenString |
| , fTargetNSURI, fGrammarPoolMemoryManager |
| ) |
| , false |
| , fGrammarPoolMemoryManager |
| ); |
| retSpecNode->setType(anyOtherType); |
| } |
| else { |
| |
| XMLStringTokenizer nameSpaceTokens(nameSpace, fMemoryManager); |
| ValueVectorOf<unsigned int> uriList(8, fGrammarPoolMemoryManager); |
| Janitor<ContentSpecNode> firstNode(0); |
| Janitor<ContentSpecNode> secondNode(0); |
| DatatypeValidator* anyURIDV = fDatatypeRegistry->getDatatypeValidator(SchemaSymbols::fgDT_ANYURI); |
| |
| while (nameSpaceTokens.hasMoreTokens()) { |
| |
| const XMLCh* tokenElem = nameSpaceTokens.nextToken(); |
| int uriIndex = fEmptyNamespaceURI; |
| |
| if (!XMLString::equals(tokenElem,SchemaSymbols::fgATTVAL_TWOPOUNDLOCAL)) { // not ##local |
| |
| if (XMLString::equals(tokenElem,SchemaSymbols::fgATTVAL_TWOPOUNDTRAGETNAMESPACE)) { |
| uriIndex = fTargetNSURI; |
| } |
| else { |
| try { |
| anyURIDV->validate(tokenElem |
| , fSchemaInfo->getValidationContext() |
| , fMemoryManager); |
| } |
| catch(const XMLException& excep) { |
| reportSchemaError(elem, excep); |
| } |
| uriIndex = fURIStringPool->addOrFind(tokenElem); |
| } |
| } |
| |
| if (uriList.containsElement(uriIndex)) { |
| continue; |
| } |
| |
| uriList.addElement(uriIndex); |
| |
| firstNode.release(); |
| firstNode.reset( new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| new (fGrammarPoolMemoryManager) QName |
| ( |
| XMLUni::fgZeroLenString |
| , XMLUni::fgZeroLenString |
| , uriIndex, fGrammarPoolMemoryManager |
| ) |
| , false |
| , fGrammarPoolMemoryManager |
| )); |
| firstNode.get()->setType(anyLocalType); |
| |
| if (secondNode.get() == 0) { |
| secondNode.reset(firstNode.release()); |
| } |
| else { |
| ContentSpecNode* newNode = new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| ContentSpecNode::Any_NS_Choice |
| , secondNode.get() |
| , firstNode.get() |
| , true |
| , true |
| , fGrammarPoolMemoryManager |
| ); |
| secondNode.release(); |
| secondNode.reset(newNode); |
| firstNode.release(); |
| } |
| } |
| firstNode.release(); |
| retSpecNode = secondNode.release(); |
| } |
| |
| // Store annotation |
| if (retSpecNode && !janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(retSpecNode, janAnnot.release()); |
| |
| return retSpecNode; |
| } |
| |
| |
| /** |
| * Traverse all |
| * |
| * <all |
| * id = ID |
| * maxOccurs = 1 : 1 |
| * minOccurs = (0 | 1) : 1 |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation?, element*) |
| * </all> |
| */ |
| ContentSpecNode* |
| TraverseSchema::traverseAll(const DOMElement* const elem, bool& hasChildren) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| hasChildren = false; |
| |
| // ----------------------------------------------------------------------- |
| // Check attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_All, this, false, fNonXSAttList |
| ); |
| |
| // ----------------------------------------------------------------------- |
| // Process contents |
| // ----------------------------------------------------------------------- |
| DOMElement* child = checkContent(elem, XUtil::getFirstChildElement(elem), true); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| |
| if (child == 0) { |
| return 0; |
| } |
| |
| Janitor<ContentSpecNode> left(0); |
| Janitor<ContentSpecNode> right(0); |
| Janitor<ContentSpecNode> contentSpecNode(0); |
| bool hadContent = false; |
| |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| hasChildren = true; |
| contentSpecNode.release(); |
| const XMLCh* childName = child->getLocalName(); |
| |
| if (XMLString::equals(childName, SchemaSymbols::fgELT_ELEMENT)) { |
| |
| SchemaElementDecl* elemDecl = traverseElementDecl(child); |
| |
| if (!elemDecl) |
| continue; |
| |
| contentSpecNode.reset(new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| elemDecl |
| , fGrammarPoolMemoryManager |
| )); |
| checkMinMax(contentSpecNode.get(), child, All_Element); |
| } |
| else { |
| |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::AllContentError, childName); |
| continue; |
| } |
| |
| hadContent = true; |
| |
| if (!left.get()) { |
| left.reset(contentSpecNode.release()); |
| } |
| else if (!right.get()) { |
| right.reset(contentSpecNode.release()); |
| } |
| else { |
| ContentSpecNode* newNode = new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| ContentSpecNode::All |
| , left.get() |
| , right.get() |
| , true |
| , true |
| , fGrammarPoolMemoryManager |
| ); |
| left.release(); |
| left.reset(newNode); |
| right.release(); |
| right.reset(contentSpecNode.release()); |
| } |
| } |
| contentSpecNode.release(); |
| |
| if (hadContent) { |
| ContentSpecNode* newNode = new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| ContentSpecNode::All |
| , left.get() |
| , right.get() |
| , true |
| , true |
| , fGrammarPoolMemoryManager |
| ); |
| |
| left.release(); |
| left.reset(newNode); |
| |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(left.get(), janAnnot.release()); |
| } |
| right.release(); |
| return left.release(); |
| } |
| |
| /** |
| * Traverses Schema attribute declaration. |
| * |
| * <attribute |
| * fixed = string |
| * default = string |
| * form = qualified | unqualified |
| * id = ID |
| * name = NCName |
| * ref = QName |
| * type = QName |
| * use = optional | prohibited | required : optional |
| > |
| * Content: (annotation? , simpleType?) |
| * <attribute/> |
| * |
| * @param elem: the declaration of the attribute under consideration |
| * |
| * @param typeInfo: Contains the complex type info of the element to which |
| * the attribute declaration is attached. |
| * |
| */ |
| void TraverseSchema::traverseAttributeDecl(const DOMElement* const elem, |
| ComplexTypeInfo* const typeInfo, |
| const bool topLevel) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| const XMLCh* ref = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName); |
| bool nameEmpty = (!name || !*name); |
| bool refEmpty = (!ref || !*ref); |
| |
| if (nameEmpty && refEmpty) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefAttribute); |
| return; |
| } |
| |
| if (topLevel && nameEmpty) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelNoNameAttribute); |
| return; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Check attributes |
| // ------------------------------------------------------------------ |
| unsigned short scope = (topLevel) |
| ? GeneralAttributeCheck::E_AttributeGlobal |
| : (refEmpty) ? GeneralAttributeCheck::E_AttributeLocal |
| : GeneralAttributeCheck::E_AttributeRef; |
| |
| fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList); |
| |
| const XMLCh* defaultVal = getElementAttValue(elem, SchemaSymbols::fgATT_DEFAULT); |
| const XMLCh* fixedVal = getElementAttValue(elem, SchemaSymbols::fgATT_FIXED); |
| const XMLCh* useVal = getElementAttValue(elem, SchemaSymbols::fgATT_USE); |
| const XMLCh* attForm = getElementAttValue(elem, SchemaSymbols::fgATT_FORM); |
| const XMLCh* dvType = getElementAttValue(elem, SchemaSymbols::fgATT_TYPE, DatatypeValidator::QName); |
| DOMElement* simpleType = checkContent(elem, XUtil::getFirstChildElement(elem), true); |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| bool badContent = false; |
| |
| while (simpleType != 0) { |
| |
| const XMLCh* contentName = simpleType->getLocalName(); |
| |
| if (XMLString::equals(SchemaSymbols::fgELT_SIMPLETYPE, contentName)) { |
| |
| if (XUtil::getNextSiblingElement(simpleType) != 0) { |
| badContent = true; |
| } |
| break; |
| } |
| |
| badContent = true; |
| simpleType = XUtil::getNextSiblingElement(simpleType); |
| } |
| |
| if (badContent) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAttributeContent, |
| (name) ? name : ref); |
| } |
| |
| if (defaultVal) { |
| |
| if (fixedVal) { |
| |
| fixedVal = 0; |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeDefaultFixedValue, |
| (name) ? name : ref); |
| } |
| |
| if ((useVal && *useVal) |
| && !XMLString::equals(useVal, SchemaSymbols::fgATTVAL_OPTIONAL)) { |
| |
| useVal = 0; |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NotOptionalDefaultAttValue, |
| (name) ? name : ref); |
| } |
| } |
| |
| // processing ref |
| if (!refEmpty && !topLevel) { |
| |
| // Check ref representation OK - 3.2.3::3.2 |
| if (attForm || dvType || (simpleType != 0)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeRefContentError, |
| (name) ? name : ref); |
| } |
| |
| processAttributeDeclRef(elem, typeInfo, ref, useVal, defaultVal, fixedVal); |
| return; |
| } |
| |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| janAnnot.reset(fAnnotation); |
| } |
| |
| // processing 'name' |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name)) |
| || XMLString::equals(name, XMLUni::fgXMLNSString)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, SchemaSymbols::fgELT_ATTRIBUTE, name); |
| return; |
| } |
| |
| // Check for duplicate declaration |
| const XMLCh* qualified = SchemaSymbols::fgATTVAL_QUALIFIED; |
| int uriIndex = fEmptyNamespaceURI; |
| |
| if ((fTargetNSURIString && *fTargetNSURIString) |
| && (topLevel || XMLString::equals(attForm, qualified) |
| || ((fSchemaInfo->getElemAttrDefaultQualified() & Attr_Def_Qualified) |
| && (!attForm || !*attForm)))) { |
| uriIndex = fTargetNSURI; |
| } |
| |
| // make sure that attribute namespace is not xsi uri |
| if (XMLString::equals(fTargetNSURIString, SchemaSymbols::fgURI_XSI)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAttTNS, name); |
| return; |
| } |
| |
| if (typeInfo && typeInfo->getAttDef(name, uriIndex) != 0) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, name); |
| return; |
| } |
| else if (fCurrentAttGroupInfo && fCurrentAttGroupInfo->containsAttribute(name, uriIndex)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, name); |
| return; |
| } |
| |
| DatatypeValidator* dv = 0; |
| XMLAttDef::AttTypes attType = XMLAttDef::Simple; |
| SchemaInfo* saveInfo = fSchemaInfo; |
| |
| if (simpleType != 0) { |
| |
| if (dvType && *dvType) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeWithTypeAndSimpleType, name); |
| } |
| |
| dv = traverseSimpleTypeDecl(simpleType, false); |
| } |
| else if (!dvType || !*dvType) { |
| dv = fDatatypeRegistry->getDatatypeValidator(SchemaSymbols::fgDT_ANYSIMPLETYPE); |
| } |
| else { |
| |
| checkEnumerationRequiredNotation(elem, name, dvType); |
| |
| const XMLCh* localPart = getLocalPart(dvType); |
| const XMLCh* prefix = getPrefix(dvType); |
| const XMLCh* typeURI = resolvePrefixToURI(elem, prefix); |
| DatatypeValidator* dvBack = 0; |
| |
| if (XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { |
| dv = fDatatypeRegistry->getDatatypeValidator(localPart); |
| dvBack = dv; |
| } |
| else { //isn't of the schema for schemas namespace... |
| |
| dv = getAttrDatatypeValidatorNS(elem, localPart, typeURI); |
| dvBack = dv; |
| |
| while(dv != 0 && !XMLString::equals(dv->getTypeUri(), SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { |
| dv = dv->getBaseValidator(); |
| } |
| |
| if(dv) |
| localPart = dv->getTypeLocalName(); |
| } |
| |
| if(dv) { |
| if (XMLString::equals(localPart,XMLUni::fgIDString)) { |
| attType = XMLAttDef::ID; |
| } |
| else if (XMLString::equals(localPart,XMLUni::fgIDRefString)) { |
| attType = XMLAttDef::IDRef; |
| } |
| else if (XMLString::equals(localPart,XMLUni::fgIDRefsString)) { |
| attType = XMLAttDef::IDRefs; |
| } |
| else if (XMLString::equals(localPart,XMLUni::fgEntityString)) { |
| attType = XMLAttDef::Entity; |
| } |
| else if (XMLString::equals(localPart,XMLUni::fgEntitiesString)) { |
| attType = XMLAttDef::Entities; |
| } |
| else if (XMLString::equals(localPart,XMLUni::fgNmTokenString)) { |
| attType = XMLAttDef::NmToken; |
| } |
| else if (XMLString::equals(localPart,XMLUni::fgNmTokensString)) { |
| attType = XMLAttDef::NmTokens; |
| } |
| else if (XMLString::equals(localPart,XMLUni::fgNotationString)) { |
| attType = XMLAttDef::Notation; |
| } |
| else { |
| attType = XMLAttDef::Simple; |
| } |
| } |
| else |
| attType = XMLAttDef::Simple; |
| |
| dv = dvBack; |
| |
| if (!dv) { |
| reportSchemaError |
| ( |
| elem |
| , XMLUni::fgXMLErrDomain |
| , XMLErrs::AttributeSimpleTypeNotFound |
| , typeURI |
| , localPart |
| , name |
| ); |
| } |
| } |
| |
| // restore schema information, if necessary |
| fSchemaInfo = saveInfo; |
| |
| bool required = false; |
| bool prohibited = false; |
| |
| if (useVal && *useVal) { |
| |
| if (XMLString::equals(useVal, SchemaSymbols::fgATTVAL_REQUIRED)) { |
| required = true; |
| } |
| else if (XMLString::equals(useVal, SchemaSymbols::fgATTVAL_PROHIBITED)) { |
| prohibited = true; |
| } |
| } |
| |
| // validate fixed/default values |
| const XMLCh* valueToCheck = defaultVal ? defaultVal : fixedVal; |
| bool ofTypeID = (dv && dv->getType() == DatatypeValidator::ID); |
| |
| if (attType == XMLAttDef::Simple && dv && valueToCheck) { |
| |
| short wsFacet = dv->getWSFacet(); |
| if((wsFacet == DatatypeValidator::REPLACE && !XMLString::isWSReplaced(valueToCheck)) || |
| (wsFacet == DatatypeValidator::COLLAPSE && !XMLString::isWSCollapsed(valueToCheck))) |
| { |
| XMLCh* normalizedValue=XMLString::replicate(valueToCheck, fMemoryManager); |
| ArrayJanitor<XMLCh> tempURIName(normalizedValue, fMemoryManager); |
| if(wsFacet == DatatypeValidator::REPLACE) |
| XMLString::replaceWS(normalizedValue, fMemoryManager); |
| else if(wsFacet == DatatypeValidator::COLLAPSE) |
| XMLString::collapseWS(normalizedValue, fMemoryManager); |
| valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue)); |
| } |
| try { |
| dv->validate(valueToCheck |
| , fSchemaInfo->getValidationContext() |
| , fMemoryManager); |
| } |
| catch (const XMLException& excep) { |
| reportSchemaError(elem, excep); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch(...) { |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::DatatypeValidationFailure, valueToCheck); |
| } |
| } |
| else if((attType == XMLAttDef::NmTokens || attType==XMLAttDef::IDRefs || attType==XMLAttDef::Entities) && |
| valueToCheck && !XMLString::isWSCollapsed(valueToCheck)) |
| { |
| XMLCh* normalizedValue=XMLString::replicate(valueToCheck, fMemoryManager); |
| ArrayJanitor<XMLCh> tempURIName(normalizedValue, fMemoryManager); |
| XMLString::collapseWS(normalizedValue, fMemoryManager); |
| valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue)); |
| } |
| |
| if (ofTypeID && valueToCheck) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect3, name); |
| } |
| |
| // check for multiple attributes with type derived from ID |
| if (!topLevel && ofTypeID) { |
| |
| if (fCurrentAttGroupInfo) { |
| |
| if (fCurrentAttGroupInfo->containsTypeWithId()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttGrpPropCorrect3, name); |
| return; |
| } |
| |
| fCurrentAttGroupInfo->setTypeWithId(true); |
| } |
| else { |
| |
| if (typeInfo->containsAttWithTypeId()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect5, name); |
| return; |
| } |
| |
| typeInfo->setAttWithTypeId(true); |
| } |
| } |
| |
| // create SchemaAttDef |
| SchemaAttDef* attDef = new (fGrammarPoolMemoryManager) SchemaAttDef |
| ( |
| XMLUni::fgZeroLenString |
| , name |
| , uriIndex |
| , attType |
| , XMLAttDef::Implied |
| , fGrammarPoolMemoryManager |
| ); |
| |
| attDef->setDatatypeValidator(dv); |
| |
| if (prohibited) { |
| attDef->setDefaultType(XMLAttDef::Prohibited); |
| } |
| else if (required) { |
| |
| if (fixedVal) { |
| attDef->setDefaultType(XMLAttDef::Required_And_Fixed); |
| } |
| else { |
| attDef->setDefaultType(XMLAttDef::Required); |
| } |
| } |
| else { |
| |
| if (fixedVal) { |
| attDef->setDefaultType(XMLAttDef::Fixed); |
| } |
| else if (defaultVal) { |
| attDef->setDefaultType(XMLAttDef::Default); |
| } |
| } |
| |
| if (valueToCheck) { |
| attDef->setValue(valueToCheck); |
| } |
| |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(attDef, janAnnot.release()); |
| |
| if (topLevel) |
| { |
| fAttributeDeclRegistry->put((void*) fStringPool->getValueForId(fStringPool->addOrFind(name)), attDef); |
| attDef->setPSVIScope(PSVIDefs::SCP_GLOBAL); |
| } |
| else |
| { |
| if (typeInfo) |
| { |
| typeInfo->addAttDef(attDef); |
| if (!fCurrentAttGroupInfo) |
| attDef->setPSVIScope(PSVIDefs::SCP_LOCAL); |
| } |
| |
| if (fCurrentAttGroupInfo) { |
| fCurrentAttGroupInfo->addAttDef(attDef, (typeInfo != 0)); |
| } |
| } |
| } |
| |
| |
| /** |
| * Traverses Schema element declaration. |
| * |
| * <element |
| * abstract = boolean : false |
| * block = (#all | List of (substitution | extension | restriction |
| * | list | union)) |
| * default = string |
| * final = (#all | List of (extension | restriction)) |
| * fixed = string |
| * form = (qualified | unqualified) |
| * id = ID |
| * maxOccurs = (nonNegativeInteger | unbounded) : 1 |
| * minOccurs = nonNegativeInteger : 1 |
| * name = NCName |
| * nillable = boolean : false |
| * ref = QName |
| * substitutionGroup = QName |
| * type = QName |
| * Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*)) |
| * </element> |
| * |
| * @param elem: the declaration of the element under consideration |
| */ |
| SchemaElementDecl* |
| TraverseSchema::traverseElementDecl(const DOMElement* const elem, |
| const bool topLevel) |
| { |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // if local element and ref attribute exists |
| if (!topLevel) |
| { |
| const XMLCh* refName = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName); |
| if (refName) |
| return processElementDeclRef(elem, refName); |
| } |
| |
| // check for empty name |
| const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| if (!name || !*name) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefElement); |
| return 0; |
| } |
| |
| // make sure that name is a valid NCName |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, |
| XMLErrs::InvalidDeclarationName, SchemaSymbols::fgELT_ELEMENT, name); |
| return 0; |
| } |
| |
| // if element already exists, just return --- revisit, it should not happen |
| if (topLevel) |
| { |
| SchemaElementDecl* retDecl = (SchemaElementDecl*) fSchemaGrammar->getElemDecl(fTargetNSURI, name, 0, Grammar::TOP_LEVEL_SCOPE); |
| if (retDecl) |
| return retDecl; |
| } |
| |
| // Check attributes |
| unsigned short scope = (topLevel) ? GeneralAttributeCheck::E_ElementGlobal |
| : GeneralAttributeCheck::E_ElementLocal; |
| |
| fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList); |
| |
| // check annotation |
| const DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true); |
| // Put annotations on all elements for the situation where there is a group of |
| // elements and not all have annotations. |
| //if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| if (!fAnnotation && fScanner->getGenerateSyntheticAnnotations()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| |
| // Create element decl |
| bool isDuplicate = false; |
| const XMLCh* valueConstraint = 0; |
| SchemaElementDecl* elemDecl = |
| createSchemaElementDecl(elem, name, isDuplicate, valueConstraint, topLevel); |
| |
| if (!isDuplicate) { |
| |
| fSchemaGrammar->putElemDecl(elemDecl); |
| |
| if (valueConstraint) |
| elemDecl->setDefaultValue(valueConstraint); |
| |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(elemDecl, janAnnot.release()); |
| |
| if (fCurrentComplexType && |
| elemDecl->getEnclosingScope() == fCurrentComplexType->getScopeDefined()) { |
| fCurrentComplexType->addElement(elemDecl); |
| elemDecl->setPSVIScope(PSVIDefs::SCP_LOCAL); |
| } |
| |
| if (fCurrentGroupInfo && |
| elemDecl->getEnclosingScope() == fCurrentGroupInfo->getScope()) { |
| fCurrentGroupInfo->addElement(elemDecl); |
| elemDecl->setPSVIScope(PSVIDefs::SCP_ABSENT); |
| } |
| } |
| else { |
| if (fAnnotation) { |
| XSAnnotation* xsAnnot = fSchemaGrammar->getAnnotation(elemDecl); |
| if (!xsAnnot) { |
| fSchemaGrammar->putAnnotation(elemDecl, janAnnot.release()); |
| } |
| else { |
| xsAnnot->setNext(janAnnot.release()); |
| } |
| } |
| } |
| |
| // Process children |
| bool anonymousType = false; |
| ComplexTypeInfo* typeInfo = 0; |
| DatatypeValidator* validator = 0; |
| |
| if (content != 0) |
| { |
| const XMLCh* contentName = content->getLocalName(); |
| |
| if (XMLString::equals(contentName, SchemaSymbols::fgELT_COMPLEXTYPE)) |
| { |
| const XMLCh* temp = content->getAttribute(SchemaSymbols::fgATT_NAME); |
| |
| if (temp && *temp) |
| { |
| // REVISIT - we are bypassing the complex type declaration. |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AnonComplexTypeWithName, name); |
| } |
| else |
| { |
| typeInfo = checkForComplexTypeInfo(content); |
| |
| if (typeInfo) |
| { |
| validator = typeInfo->getDatatypeValidator(); |
| |
| if (!isDuplicate) { |
| |
| //Recursing element |
| if (typeInfo->getPreprocessed()) { |
| |
| const XMLCh* typeInfoName = typeInfo->getTypeName(); |
| fSchemaInfo->addRecursingType(content, typeInfoName + XMLString::indexOf(typeInfoName, chComma) + 1); |
| } |
| } |
| } |
| } |
| |
| anonymousType = true; |
| content = XUtil::getNextSiblingElement(content); |
| } |
| else if (XMLString::equals(contentName, SchemaSymbols::fgELT_SIMPLETYPE)) |
| { |
| const XMLCh* temp = content->getAttribute(SchemaSymbols::fgATT_NAME); |
| if (temp && *temp) |
| // REVISIT - we are bypassing the simple type declaration. |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AnonSimpleTypeWithName, name); |
| else |
| validator = checkForSimpleTypeValidator(content); |
| |
| anonymousType = true; |
| content = XUtil::getNextSiblingElement(content); |
| } |
| |
| // Check for identity constraints |
| if (content != 0) |
| { |
| content = checkIdentityConstraintContent(content); |
| if (content != 0) |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::InvalidElementContent); |
| } |
| } |
| |
| // Handle 'type' attribute |
| const XMLCh* typeStr = getElementAttValue(elem, SchemaSymbols::fgATT_TYPE, DatatypeValidator::QName); |
| if (typeStr) |
| { |
| if (anonymousType) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::ElementWithTypeAndAnonType, name); |
| } |
| else if (*typeStr) |
| { |
| const XMLCh* typeLocalPart = getLocalPart(typeStr); |
| const XMLCh* typePrefix = getPrefix(typeStr); |
| const XMLCh* typeURI = resolvePrefixToURI(elem, typePrefix); |
| |
| if (!XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA) |
| || !XMLString::equals(typeLocalPart, SchemaSymbols::fgATTVAL_ANYTYPE)) |
| { |
| checkEnumerationRequiredNotation(elem, name, typeStr); |
| |
| bool noErrorFound = true; |
| const XMLCh* anotherSchemaURI = checkTypeFromAnotherSchema(elem, typeStr); |
| |
| // get complex type info |
| typeInfo = getElementComplexTypeInfo(elem, typeStr, anotherSchemaURI); |
| |
| // get simple type validtor - if not a complex type |
| if (typeInfo) |
| validator = typeInfo->getDatatypeValidator(); |
| else |
| validator = getElementTypeValidator(elem, typeStr, noErrorFound, anotherSchemaURI); |
| } |
| } |
| } |
| |
| // check for duplicate elements with different types. |
| if (isDuplicate) |
| { |
| DatatypeValidator* eltDV = elemDecl->getDatatypeValidator(); |
| ComplexTypeInfo* eltTypeInfo = elemDecl->getComplexTypeInfo(); |
| |
| if ( (eltTypeInfo != typeInfo) || (eltDV != validator)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateElementDeclaration, name); |
| } |
| } |
| // Set element declararion type information |
| else |
| { |
| elemDecl->setDatatypeValidator(validator); |
| elemDecl->setComplexTypeInfo(typeInfo); |
| |
| if (validator) |
| elemDecl->setModelType(SchemaElementDecl::Simple); |
| else if (typeInfo) |
| elemDecl->setModelType((SchemaElementDecl::ModelTypes)typeInfo->getContentType()); |
| |
| if (topLevel) { |
| |
| // Handle the substitutionGroup |
| const XMLCh* subsGroupName = getElementAttValue(elem, SchemaSymbols::fgATT_SUBSTITUTIONGROUP, DatatypeValidator::QName); |
| if (subsGroupName && *subsGroupName) |
| processSubstitutionGroup(elem, elemDecl, typeInfo, validator, subsGroupName); |
| } |
| |
| // process identity constraints |
| DOMElement* ic = XUtil::getFirstChildElementNS( |
| elem, fgIdentityConstraints, SchemaSymbols::fgURI_SCHEMAFORSCHEMA, 3); |
| |
| if (ic) |
| processElemDeclIC(ic, elemDecl); |
| } |
| |
| if (!typeInfo && !validator) |
| { |
| if (!isDuplicate) |
| { |
| elemDecl->setModelType(SchemaElementDecl::Any); |
| elemDecl->setAttWildCard( |
| new (fGrammarPoolMemoryManager) SchemaAttDef( |
| XMLUni::fgZeroLenString, XMLUni::fgZeroLenString, |
| fEmptyNamespaceURI, XMLAttDef::Any_Any, |
| XMLAttDef::ProcessContents_Lax, fGrammarPoolMemoryManager |
| ) |
| ); |
| } |
| } |
| else if (valueConstraint) |
| { |
| if (!checkElemDeclValueConstraint(elem, elemDecl, valueConstraint, typeInfo, validator) |
| && !isDuplicate) |
| { |
| int miscFlags = elemDecl->getMiscFlags(); |
| miscFlags &= ~ SchemaSymbols::XSD_FIXED; |
| elemDecl->setDefaultValue(0); |
| elemDecl->setMiscFlags(miscFlags); |
| } |
| } |
| |
| return elemDecl; |
| } |
| |
| /** |
| * Traverses Schema notation declaration. |
| * |
| * <notation |
| * id = ID |
| * name = NCName |
| * public = token |
| * system = anyURI |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation?) |
| * </notation> |
| * |
| * @param elem: the declaration of the element under consideration |
| */ |
| const XMLCh* TraverseSchema::traverseNotationDecl(const DOMElement* const elem) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_Notation, this, true, fNonXSAttList |
| ); |
| |
| // ----------------------------------------------------------------------- |
| // Process notation attributes/elements |
| // ----------------------------------------------------------------------- |
| const XMLCh* name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| bool nameEmpty = (!name || !*name) ? true : false; |
| |
| if (nameEmpty) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameGlobalElement, |
| SchemaSymbols::fgELT_NOTATION); |
| return 0; |
| } |
| |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, |
| SchemaSymbols::fgELT_NOTATION, name); |
| return 0; |
| } |
| |
| if (fNotationRegistry->containsKey(name, fTargetNSURI)) { |
| return name; |
| } |
| |
| if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected); |
| |
| const XMLCh* publicId = getElementAttValue(elem, SchemaSymbols::fgATT_PUBLIC); |
| const XMLCh* systemId = getElementAttValue(elem, SchemaSymbols::fgATT_SYSTEM, DatatypeValidator::AnyURI); |
| |
| fNotationRegistry->put((void*) fStringPool->getValueForId(fStringPool->addOrFind(name)), |
| fTargetNSURI, 0); |
| |
| // for PSVI we need to store the notational decl |
| XMLNotationDecl* decl = new (fGrammarPoolMemoryManager) XMLNotationDecl |
| ( |
| name, |
| publicId, |
| systemId, |
| 0, |
| fGrammarPoolMemoryManager |
| ); |
| decl->setNameSpaceId(fTargetNSURI); |
| fSchemaGrammar->putNotationDecl(decl); |
| |
| if (fAnnotation) |
| fSchemaGrammar->putAnnotation(decl, fAnnotation); |
| else if (fScanner->getGenerateSyntheticAnnotations() && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| fSchemaGrammar->putAnnotation(decl, fAnnotation); |
| } |
| return name; |
| } |
| |
| const XMLCh* TraverseSchema::traverseNotationDecl(const DOMElement* const elem, |
| const XMLCh* const name, |
| const XMLCh* const uriStr) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| unsigned int uriId = fURIStringPool->addOrFind(uriStr); |
| SchemaInfo* saveInfo = fSchemaInfo; |
| |
| if (fTargetNSURI != (int) uriId) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(uriStr); |
| |
| if (!isImportingNS(uriId)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr); |
| return 0; |
| } |
| |
| Grammar* grammar = fGrammarResolver->getGrammar(uriStr); |
| |
| if (grammar == 0 || grammar->getGrammarType() != Grammar::SchemaGrammarType) { |
| |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr); |
| return 0; |
| } |
| |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId); |
| |
| if (!impInfo || impInfo->getProcessed()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, uriStr, name); |
| return 0; |
| } |
| |
| fSchemaInfo = impInfo; |
| fTargetNSURI = fSchemaInfo->getTargetNSURI(); |
| } |
| |
| DOMElement* notationElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Notation, |
| SchemaSymbols::fgELT_NOTATION, name, &fSchemaInfo); |
| |
| if (notationElem == 0) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::Notation_DeclNotFound, uriStr, name); |
| return 0; |
| } |
| |
| const XMLCh* notationName = traverseNotationDecl(notationElem); |
| |
| fSchemaInfo = saveInfo; |
| fTargetNSURI = fSchemaInfo->getTargetNSURI(); |
| |
| return notationName; |
| } |
| |
| /** |
| * Traverses Schema list simple type declaration. |
| * |
| * <list |
| * id = ID |
| * itemType = QName |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation?, simpleType?) |
| * </list> |
| * |
| */ |
| DatatypeValidator* |
| TraverseSchema::traverseByList(const DOMElement* const rootElem, |
| const DOMElement* const contentElem, |
| const XMLCh* const typeName, |
| const XMLCh* const qualifiedName, |
| const int finalSet, |
| Janitor<XSAnnotation>* const janAnnot) { |
| |
| NamespaceScopeManager nsMgr(contentElem, fSchemaInfo, this); |
| |
| DatatypeValidator* baseValidator = 0; |
| const XMLCh* baseTypeName = getElementAttValue(contentElem, SchemaSymbols::fgATT_ITEMTYPE, DatatypeValidator::QName); |
| |
| fAttributeCheck.checkAttributes( |
| contentElem, GeneralAttributeCheck::E_List, this, false, fNonXSAttList |
| ); |
| |
| const DOMElement* tempEl = XUtil::getNextSiblingElement(contentElem); |
| if (tempEl != 0) { |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::SimpleTypeContentError, tempEl->getLocalName()); |
| } |
| |
| DOMElement* content = 0; |
| |
| if (!baseTypeName || !*baseTypeName) { // must 'see' <simpleType> |
| |
| content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), false); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| |
| if (!content) { |
| |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::ExpectedSimpleTypeInList, typeName); |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) { |
| baseValidator = checkForSimpleTypeValidator(content, SchemaSymbols::XSD_LIST); |
| } |
| else { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::ListUnionRestrictionError, typeName); |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| content = XUtil::getNextSiblingElement(content); |
| } |
| else { // base was provided - get proper validator |
| |
| baseValidator = findDTValidator(contentElem, typeName, baseTypeName, SchemaSymbols::XSD_LIST); |
| content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), true); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| } |
| |
| DatatypeValidator* newDV = 0; |
| |
| if (baseValidator) { |
| |
| if (!baseValidator->isAtomic()) { |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::AtomicItemType, baseTypeName); |
| } |
| else { |
| |
| // 'content' should be empty |
| // If an annotation was encountered we have already traversed it in |
| // checkContent in the case of a base provided (only allowed child is |
| // an annotation). |
| if (content != 0) { // report an error and continue |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::SimpleTypeDerivationByListError, typeName); |
| } |
| |
| // create & register validator for "generated" type |
| try { |
| newDV = fDatatypeRegistry->createDatatypeValidator( |
| qualifiedName, baseValidator, 0, 0, true, finalSet, true, fGrammarPoolMemoryManager); |
| } |
| catch (const XMLException& excep) { |
| reportSchemaError(contentElem, excep); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch(...) { |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, |
| XMLErrs::DatatypeValidatorCreationError, typeName); |
| } |
| } |
| } |
| |
| popCurrentTypeNameStack(); |
| return newDV; |
| } |
| |
| /** |
| * Traverses Schema restriction simple type declaration. |
| * |
| * <restriction |
| * base = QName |
| * id = ID |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation?, (simpleType?, |
| * (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*)) |
| * </restriction> |
| * |
| */ |
| DatatypeValidator* |
| TraverseSchema::traverseByRestriction(const DOMElement* const rootElem, |
| const DOMElement* const contentElem, |
| const XMLCh* const typeName, |
| const XMLCh* const qualifiedName, |
| const int finalSet, |
| Janitor<XSAnnotation>* const janAnnot) { |
| |
| NamespaceScopeManager nsMgr(contentElem, fSchemaInfo, this); |
| |
| DatatypeValidator* baseValidator = 0; |
| DatatypeValidator* newDV = 0; |
| const XMLCh* baseTypeName = getElementAttValue(contentElem, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName); |
| |
| fAttributeCheck.checkAttributes( |
| contentElem, GeneralAttributeCheck::E_Restriction, this, false, fNonXSAttList |
| ); |
| |
| const DOMElement* tempEl = XUtil::getNextSiblingElement(contentElem); |
| if (tempEl != 0) { |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::SimpleTypeContentError, tempEl->getLocalName()); |
| } |
| |
| DOMElement* content = 0; |
| |
| if (!baseTypeName || !*baseTypeName) { // must 'see' <simpleType> |
| |
| content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), false); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| |
| if (content == 0) { |
| |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::ExpectedSimpleTypeInRestriction); |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) { |
| baseValidator = checkForSimpleTypeValidator(content); |
| } |
| else { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::ListUnionRestrictionError, typeName); |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| // Check for facets |
| content = XUtil::getNextSiblingElement(content); |
| } |
| else { // base was provided - get proper validator |
| |
| baseValidator = findDTValidator(contentElem, typeName, baseTypeName, SchemaSymbols::XSD_RESTRICTION); |
| content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), true); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| } |
| |
| if (baseValidator) { |
| |
| // Get facets if any existing |
| typedef RefHashTableOf<KVStringPair> KVRefHash; |
| Janitor<KVRefHash> janFacets(0); |
| //RefHashTableOf<KVStringPair>* facets = 0; |
| typedef RefArrayVectorOf<XMLCh> XMLChRefArray; |
| Janitor<XMLChRefArray> enums(0); |
| //RefArrayVectorOf<XMLCh>* enums = 0; |
| XMLBuffer pattern(128, fGrammarPoolMemoryManager); |
| Janitor<XSAnnotation> janEnumAnnot(0); |
| Janitor<XSAnnotation> janPatternAnnot(0); |
| XMLCh fixedFlagStr[16]; |
| unsigned int fixedFlag = 0; |
| unsigned short scope = 0; |
| bool isFirstPattern = true; |
| bool sawPattern = false; |
| |
| |
| while (content != 0) { |
| |
| if (content->getNodeType() == DOMNode::ELEMENT_NODE) { |
| |
| NamespaceScopeManager nsMgr(content, fSchemaInfo, this); |
| |
| const XMLCh* facetName = content->getLocalName(); |
| |
| bool bContinue=false; // workaround for Borland bug with 'continue' in 'catch' |
| try { |
| scope = fAttributeCheck.getFacetId(facetName, fMemoryManager); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch (...) { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::InvalidFacetName, facetName); |
| content = XUtil::getNextSiblingElement(content); |
| bContinue=true; |
| } |
| if(bContinue) |
| continue; |
| |
| fAttributeCheck.checkAttributes( |
| content, scope, this, false, fNonXSAttList |
| ); |
| if (checkContent(rootElem, XUtil::getFirstChildElement(content), true) != 0) |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected); |
| |
| const XMLCh* attValue = content->getAttribute(SchemaSymbols::fgATT_VALUE); |
| if (janFacets.get() == 0) { |
| janFacets.reset(new (fGrammarPoolMemoryManager) RefHashTableOf<KVStringPair>(29, true, fGrammarPoolMemoryManager)); |
| |
| } |
| |
| if (XMLString::equals(facetName, SchemaSymbols::fgELT_ENUMERATION)) { |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(content, fNonXSAttList); |
| } |
| if (fAnnotation) { |
| if (janEnumAnnot.isDataNull()) |
| janEnumAnnot.reset(fAnnotation); |
| else |
| janEnumAnnot.get()->setNext(fAnnotation); |
| } |
| |
| // REVISIT |
| // if validator is a notation datatype validator, we need |
| // to get the qualified name first before adding it to the |
| // enum buffer |
| if (!enums.get()) { |
| enums.reset(new (fGrammarPoolMemoryManager) RefArrayVectorOf<XMLCh>(8, true, fGrammarPoolMemoryManager)); |
| } |
| |
| if (baseValidator->getType() == DatatypeValidator::NOTATION) { |
| |
| const XMLCh* localPart = getLocalPart(attValue); |
| const XMLCh* prefix = getPrefix(attValue); |
| const XMLCh* uriStr = (prefix && *prefix) ? resolvePrefixToURI(content, prefix) : fTargetNSURIString; |
| unsigned int uriId = fURIStringPool->addOrFind(uriStr); |
| |
| if (!fNotationRegistry->containsKey(localPart, uriId)) { |
| traverseNotationDecl(content, localPart, uriStr); |
| } |
| |
| if (uriStr && *uriStr) { |
| fBuffer.set(uriStr); |
| fBuffer.append(chColon); |
| fBuffer.append(localPart); |
| enums.get()->addElement(XMLString::replicate(fBuffer.getRawBuffer(), fGrammarPoolMemoryManager)); |
| } |
| else { |
| enums.get()->addElement(XMLString::replicate(localPart, fGrammarPoolMemoryManager)); |
| } |
| |
| } |
| else if (baseValidator->getType() == DatatypeValidator::QName) { |
| // We need the URI string for the prefix to determine |
| // if that matches the value in the instance document. |
| // Code was just comparing the string of prefix:localname |
| // and if the schema and instance document had different |
| // prefixes with the same URI string then we were giving an error. |
| const XMLCh* prefix = getPrefix(attValue); |
| const XMLCh* uriStr = (prefix && *prefix) ? resolvePrefixToURI(content, prefix) : fTargetNSURIString; |
| |
| enums.get()->addElement(XMLString::replicate(attValue, fGrammarPoolMemoryManager)); |
| enums.get()->addElement(XMLString::replicate(uriStr, fGrammarPoolMemoryManager)); |
| } |
| else { |
| enums.get()->addElement(XMLString::replicate(attValue, fGrammarPoolMemoryManager)); |
| } |
| } |
| else if (XMLString::equals(facetName, SchemaSymbols::fgELT_PATTERN)) { |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(content, fNonXSAttList); |
| } |
| if (fAnnotation) { |
| if (janPatternAnnot.isDataNull()) |
| janPatternAnnot.reset(fAnnotation); |
| else |
| janPatternAnnot.get()->setNext(fAnnotation); |
| } |
| sawPattern = true; |
| if (isFirstPattern) { // fBuffer.isEmpty() - overhead call |
| |
| isFirstPattern = false; |
| pattern.set(attValue); |
| } |
| else { //datatypes: 5.2.4 pattern |
| |
| pattern.append(chPipe); |
| pattern.append(attValue); |
| } |
| } |
| else { |
| |
| if (janFacets.get()->containsKey(facetName)) { |
| |
| if (fAnnotation) |
| delete fAnnotation; |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateFacet, facetName); |
| } |
| else { |
| |
| if (XMLString::equals(facetName, SchemaSymbols::fgELT_WHITESPACE) |
| && baseValidator->getType() != DatatypeValidator::String |
| && !XMLString::equals(attValue, SchemaSymbols::fgWS_COLLAPSE)) { |
| |
| if (fAnnotation) |
| delete fAnnotation; |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::WS_CollapseExpected, attValue); |
| } |
| else { |
| |
| const XMLCh* facetStr = fStringPool->getValueForId(fStringPool->addOrFind(facetName)); |
| KVStringPair* kv = new (fGrammarPoolMemoryManager) KVStringPair(facetStr, attValue, fGrammarPoolMemoryManager); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(content, fNonXSAttList); |
| } |
| if (fAnnotation) |
| fSchemaGrammar->putAnnotation(kv, fAnnotation); |
| |
| janFacets.get()->put((void*) facetStr, kv); |
| checkFixedFacet(content, facetStr, baseValidator, fixedFlag); |
| } |
| } |
| } |
| } |
| |
| content = XUtil::getNextSiblingElement(content); |
| } // end while |
| |
| if (sawPattern) { |
| |
| KVStringPair* kv = new (fGrammarPoolMemoryManager) KVStringPair(SchemaSymbols::fgELT_PATTERN, pattern.getRawBuffer(), pattern.getLen(), fGrammarPoolMemoryManager); |
| if (!janPatternAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(kv, janPatternAnnot.release()); |
| janFacets.get()->put((void*) SchemaSymbols::fgELT_PATTERN, kv); |
| } |
| |
| if (fixedFlag) { |
| |
| XMLString::binToText(fixedFlag, fixedFlagStr, 15, 10, fGrammarPoolMemoryManager); |
| janFacets.get()->put((void*) SchemaSymbols::fgATT_FIXED, |
| new (fGrammarPoolMemoryManager) KVStringPair(SchemaSymbols::fgATT_FIXED, fixedFlagStr, fGrammarPoolMemoryManager)); |
| } |
| |
| if (enums.get() && !janEnumAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(enums.get(), janEnumAnnot.release()); |
| |
| try { |
| newDV = fDatatypeRegistry->createDatatypeValidator(qualifiedName, baseValidator, janFacets.release(), enums.release(), false, finalSet, true, fGrammarPoolMemoryManager); |
| } |
| catch (const XMLException& excep) { |
| reportSchemaError(contentElem, excep); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch(...) { |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, |
| XMLErrs::DatatypeValidatorCreationError, typeName); |
| } |
| } |
| popCurrentTypeNameStack(); |
| return newDV; |
| } |
| |
| /** |
| * Traverses Schema union simple type declaration. |
| * |
| * <union |
| * id = ID |
| * memberTypes = List of QName |
| * {any attributes with non-schema namespace . . .}> |
| * Content: (annotation?, simpleType*) |
| * </union> |
| * |
| */ |
| DatatypeValidator* |
| TraverseSchema::traverseByUnion(const DOMElement* const rootElem, |
| const DOMElement* const contentElem, |
| const XMLCh* const typeName, |
| const XMLCh* const qualifiedName, |
| const int finalSet, |
| int baseRefContext, |
| Janitor<XSAnnotation>* const janAnnot) { |
| |
| NamespaceScopeManager nsMgr(contentElem, fSchemaInfo, this); |
| |
| fAttributeCheck.checkAttributes( |
| contentElem, GeneralAttributeCheck::E_Union, this, false, fNonXSAttList |
| ); |
| |
| const DOMElement* tempEl = XUtil::getNextSiblingElement(contentElem); |
| if (tempEl != 0) { |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::SimpleTypeContentError, tempEl->getLocalName()); |
| } |
| |
| const XMLCh* baseTypeName = getElementAttValue(contentElem, SchemaSymbols::fgATT_MEMBERTYPES); |
| DatatypeValidator* baseValidator = 0; |
| RefVectorOf<DatatypeValidator>* validators = new (fGrammarPoolMemoryManager) RefVectorOf<DatatypeValidator>(4, false, fGrammarPoolMemoryManager); |
| Janitor<RefVectorOf<DatatypeValidator> > janValidators(validators); |
| DOMElement* content = 0; |
| |
| if (baseTypeName && *baseTypeName) { //base was provided - get proper validator. |
| |
| XMLStringTokenizer unionMembers(baseTypeName, fGrammarPoolMemoryManager); |
| int tokCount = unionMembers.countTokens(); |
| |
| for (int i = 0; i < tokCount; i++) { |
| |
| const XMLCh* memberTypeName = unionMembers.nextToken(); |
| |
| baseValidator = findDTValidator(contentElem, typeName, memberTypeName, SchemaSymbols::XSD_UNION); |
| |
| if (baseValidator == 0) { |
| |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| validators->addElement(baseValidator); |
| } |
| |
| content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), true); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| } |
| else { // must 'see' <simpleType> |
| |
| content = checkContent(rootElem, XUtil::getFirstChildElement(contentElem), false); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(contentElem, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| |
| if (content == 0) { |
| |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::ExpectedSimpleTypeInUnion, typeName); |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| if (!XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::ListUnionRestrictionError, typeName); |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| } |
| |
| // process union content of simpleType children if any |
| while (content != 0) { |
| |
| if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) { |
| |
| baseValidator = checkForSimpleTypeValidator(content, baseRefContext | SchemaSymbols::XSD_UNION); |
| |
| if (baseValidator == 0) { |
| |
| popCurrentTypeNameStack(); |
| return 0; |
| } |
| |
| validators->addElement(baseValidator); |
| } |
| else { |
| // REVISIT - should we break. For now, we will continue and move to |
| // the next sibling |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::ListUnionRestrictionError, typeName); |
| } |
| |
| content = XUtil::getNextSiblingElement(content); |
| } // end while |
| |
| DatatypeValidator* newDV = 0; |
| janValidators.orphan(); |
| |
| try { |
| newDV = fDatatypeRegistry->createDatatypeValidator(qualifiedName, validators, finalSet, true, fGrammarPoolMemoryManager); |
| } |
| catch (const XMLException& excep) { |
| reportSchemaError(contentElem, excep); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch(...) { |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, |
| XMLErrs::DatatypeValidatorCreationError, typeName); |
| } |
| |
| popCurrentTypeNameStack(); |
| return newDV; |
| } |
| |
| |
| /** |
| * Traverse SimpleContent Declaration |
| * |
| * <simpleContent |
| * id = ID |
| * {any attributes with non-schema namespace...}> |
| * |
| * Content: (annotation? , (restriction | extension)) |
| * </simpleContent> |
| * |
| * <restriction |
| * base = QNAME |
| * id = ID |
| * {any attributes with non-schema namespace...}> |
| * |
| * Content: (annotation?, (simpleType?, (minExclusive | minInclusive |
| * | maxExclusive | maxInclusive | totalDigits | fractionDigits |
| * | length | minLength | maxLength | enumeration | pattern |
| * | whiteSpace)*)?, ((attribute | attributeGroup)* , anyAttribute?)) |
| * </restriction> |
| * |
| * <extension |
| * base = QNAME |
| * id = ID |
| * {any attributes with non-schema namespace...}> |
| * Content: (annotation? , ((attribute | attributeGroup)* , anyAttribute?)) |
| * </extension> |
| * |
| */ |
| void TraverseSchema::traverseSimpleContentDecl(const XMLCh* const typeName, |
| const XMLCh* const qualifiedName, |
| const DOMElement* const contentDecl, |
| ComplexTypeInfo* const typeInfo, |
| Janitor<XSAnnotation>* const janAnnot) |
| { |
| NamespaceScopeManager nsMgr(contentDecl, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| bool preProcessFlag = typeInfo->getPreprocessed(); |
| |
| if (!preProcessFlag) { |
| fAttributeCheck.checkAttributes( |
| contentDecl, GeneralAttributeCheck::E_SimpleContent |
| , this, false, fNonXSAttList |
| ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Set the content type to be simple, and initialize content spec handle |
| // ----------------------------------------------------------------------- |
| typeInfo->setContentType(SchemaElementDecl::Simple); |
| |
| // ----------------------------------------------------------------------- |
| // Process annotation if any |
| // ----------------------------------------------------------------------- |
| DOMElement* simpleContent = checkContent(contentDecl, XUtil::getFirstChildElement(contentDecl), false, !preProcessFlag); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(contentDecl, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| |
| // If there are no children, return |
| if (simpleContent == 0) { |
| |
| reportSchemaError(contentDecl, XMLUni::fgXMLErrDomain, XMLErrs::EmptySimpleTypeContent); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| NamespaceScopeManager nsMgr2(simpleContent, fSchemaInfo, this); |
| // ----------------------------------------------------------------------- |
| // The content should be either "restriction" or "extension" |
| // ----------------------------------------------------------------------- |
| if (!preProcessFlag) { |
| const XMLCh* const contentName = simpleContent->getLocalName(); |
| |
| if (XMLString::equals(contentName, SchemaSymbols::fgATTVAL_RESTRICTION)) { |
| |
| fAttributeCheck.checkAttributes( |
| simpleContent, GeneralAttributeCheck::E_Restriction |
| , this, false, fNonXSAttList |
| ); |
| typeInfo->setDerivedBy(SchemaSymbols::XSD_RESTRICTION); |
| } |
| else if (XMLString::equals(contentName, SchemaSymbols::fgATTVAL_EXTENSION)) { |
| |
| fAttributeCheck.checkAttributes( |
| simpleContent, GeneralAttributeCheck::E_Extension |
| , this, false, fNonXSAttList |
| ); |
| typeInfo->setDerivedBy(SchemaSymbols::XSD_EXTENSION); |
| } |
| else { |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContent); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| |
| //Skip over any annotations in the restriction or extension elements |
| DOMElement* content = checkContent(simpleContent, XUtil::getFirstChildElement(simpleContent), true, !preProcessFlag); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(simpleContent, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Handle the base type name |
| // ----------------------------------------------------------------------- |
| const XMLCh* baseName = getElementAttValue(simpleContent, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName); |
| |
| if (!baseName || !*baseName) { |
| |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::UnspecifiedBase); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| const XMLCh* prefix = getPrefix(baseName); |
| const XMLCh* localPart = getLocalPart(baseName); |
| const XMLCh* uri = resolvePrefixToURI(simpleContent, prefix); |
| |
| // check for 'anyType' |
| if (XMLString::equals(uri, SchemaSymbols::fgURI_SCHEMAFORSCHEMA) |
| && XMLString::equals(localPart, SchemaSymbols::fgATTVAL_ANYTYPE)) { |
| |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContentBase, baseName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| processBaseTypeInfo(simpleContent, baseName, localPart, uri, typeInfo); |
| |
| ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo(); |
| DatatypeValidator* baseValidator = typeInfo->getBaseDatatypeValidator(); |
| |
| if (baseValidator != 0 && baseTypeInfo == 0) { |
| |
| // check that the simpleType does not preclude derivation by extension |
| if ((baseValidator->getFinalSet() & SchemaSymbols::XSD_EXTENSION) == typeInfo->getDerivedBy()) { |
| |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::DisallowedSimpleTypeExtension, |
| baseName, typeName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| //Schema Spec: 5.11: Complex Type Definition Properties Correct: 2 |
| if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION) { |
| |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidComplexTypeBase, baseName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| |
| // check that the base isn't a complex type with complex content |
| // and that derivation method is not included in 'final' |
| bool simpleTypeRequired = false; |
| |
| if (baseTypeInfo) { |
| |
| if (baseTypeInfo->getContentType() != SchemaElementDecl::Simple) { |
| |
| // Schema Errata: E1-27 |
| if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION |
| && ((baseTypeInfo->getContentType() == SchemaElementDecl::Mixed_Simple |
| || baseTypeInfo->getContentType() == SchemaElementDecl::Mixed_Complex) |
| && emptiableParticle(baseTypeInfo->getContentSpec()))) { |
| simpleTypeRequired = true; |
| } |
| else { |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContentBase, baseName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| |
| if ((baseTypeInfo->getFinalSet() & typeInfo->getDerivedBy()) != 0) { |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivation, baseName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Process the content of the derivation |
| // ----------------------------------------------------------------------- |
| if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION) { |
| |
| if(baseTypeInfo) |
| typeInfo->setBaseDatatypeValidator(baseTypeInfo->getDatatypeValidator()); |
| |
| if (content != 0) { |
| |
| // --------------------------------------------------------------- |
| // There may be a simple type definition in the restriction |
| // element. The data type validator will be based on it, if |
| // specified |
| // --------------------------------------------------------------- |
| if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) { |
| |
| DatatypeValidator* simpleTypeDV = traverseSimpleTypeDecl(content, false); |
| |
| if (simpleTypeDV) { |
| |
| // Check that the simpleType validator is validly derived |
| // from base |
| DatatypeValidator* baseDV = typeInfo->getBaseDatatypeValidator(); |
| |
| if (baseDV && !baseDV->isSubstitutableBy(simpleTypeDV)) { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::InvalidContentRestriction); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| typeInfo->setBaseDatatypeValidator(simpleTypeDV); |
| content = XUtil::getNextSiblingElement(content); |
| } |
| else { |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| // Schema Errata E1-27 |
| // Complex Type Definition Restriction OK: 2.2 |
| else if (simpleTypeRequired) { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::CT_SimpleTypeChildRequired); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| // --------------------------------------------------------------- |
| // Build up the facet info |
| // --------------------------------------------------------------- |
| RefHashTableOf<KVStringPair>* facets = 0; |
| RefArrayVectorOf<XMLCh>* enums = 0; |
| XMLBuffer pattern(128, fGrammarPoolMemoryManager); |
| XMLCh fixedFlagStr[16]; |
| unsigned int fixedFlag = 0; |
| unsigned short scope = 0; |
| bool isFirstPattern = true; |
| |
| while (content != 0) { |
| |
| const XMLCh* facetName = content->getLocalName(); |
| |
| bool bDoBreak=false; // workaround for Borland bug with 'break' in 'catch' |
| // if not a valid facet, break from the loop |
| try { |
| scope = fAttributeCheck.getFacetId(facetName, fMemoryManager); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch(...) { |
| bDoBreak=true; |
| } |
| if(bDoBreak) |
| break; |
| |
| if (content->getNodeType() == DOMNode::ELEMENT_NODE) { |
| |
| fAttributeCheck.checkAttributes(content, scope, this); |
| |
| const XMLCh* attValue = content->getAttribute(SchemaSymbols::fgATT_VALUE); |
| |
| if (facets == 0) { |
| facets = new (fGrammarPoolMemoryManager) RefHashTableOf<KVStringPair>(29, true, fGrammarPoolMemoryManager); |
| } |
| |
| if (XMLString::equals(facetName, SchemaSymbols::fgELT_ENUMERATION)) { |
| |
| if (!enums) { |
| enums = new (fGrammarPoolMemoryManager) RefArrayVectorOf<XMLCh>(8, true, fGrammarPoolMemoryManager); |
| } |
| |
| enums->addElement(XMLString::replicate(attValue, fGrammarPoolMemoryManager)); |
| } |
| else if (XMLString::equals(facetName, SchemaSymbols::fgELT_PATTERN)) { |
| |
| if (isFirstPattern) { // fBuffer.isEmpty() - overhead call |
| |
| isFirstPattern = false; |
| pattern.set(attValue); |
| } |
| else { //datatypes: 5.2.4 pattern |
| |
| pattern.append(chPipe); |
| pattern.append(attValue); |
| } |
| } |
| else { |
| |
| if (facets->containsKey(facetName)) { |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateFacet, facetName); |
| } |
| else { |
| |
| const XMLCh* facetNameStr = |
| fStringPool->getValueForId(fStringPool->addOrFind(facetName)); |
| |
| facets->put((void*) facetNameStr, new (fGrammarPoolMemoryManager) KVStringPair(facetNameStr, attValue, fGrammarPoolMemoryManager)); |
| checkFixedFacet(content, facetNameStr, typeInfo->getBaseDatatypeValidator(), fixedFlag); |
| } |
| } |
| } |
| |
| content = XUtil::getNextSiblingElement(content); |
| } |
| |
| if (facets) { |
| |
| if (!pattern.isEmpty()) { |
| facets->put |
| ( |
| (void*) SchemaSymbols::fgELT_PATTERN, |
| new (fGrammarPoolMemoryManager) KVStringPair |
| ( |
| SchemaSymbols::fgELT_PATTERN |
| , pattern.getRawBuffer() |
| , pattern.getLen() |
| , fGrammarPoolMemoryManager |
| ) |
| ); |
| } |
| |
| if (fixedFlag) { |
| |
| XMLString::binToText(fixedFlag, fixedFlagStr, 15, 10, fGrammarPoolMemoryManager); |
| facets->put((void*) SchemaSymbols::fgATT_FIXED, |
| new (fGrammarPoolMemoryManager) KVStringPair(SchemaSymbols::fgATT_FIXED, fixedFlagStr, fGrammarPoolMemoryManager)); |
| } |
| |
| try { |
| |
| DatatypeValidator* simpleDV = |
| fDatatypeRegistry->createDatatypeValidator |
| ( |
| qualifiedName, |
| typeInfo->getBaseDatatypeValidator(), |
| facets, enums, false, 0, true, fGrammarPoolMemoryManager |
| ); |
| simpleDV->setAnonymous(); |
| typeInfo->setDatatypeValidator(simpleDV); |
| } |
| catch (const XMLException& excep) { |
| reportSchemaError(simpleContent, excep); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch(...) { |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::DatatypeValidatorCreationError, typeName); |
| } |
| } |
| else { |
| typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator()); |
| } |
| } |
| else { |
| |
| // Schema Errata E1-27 |
| // Complex Type Definition Restriction OK: 2.2 |
| if (simpleTypeRequired) { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::CT_SimpleTypeChildRequired); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator()); |
| } |
| } // end RESTRICTION |
| else { // EXTENSION |
| |
| ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo(); |
| |
| if (baseTypeInfo!= 0) { |
| |
| typeInfo->setBaseDatatypeValidator(baseTypeInfo->getDatatypeValidator()); |
| } |
| |
| typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator()); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Process attributes if any |
| // ----------------------------------------------------------------------- |
| processAttributes(simpleContent, content, typeInfo); |
| |
| if (XUtil::getNextSiblingElement(simpleContent) != 0) { |
| reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInSimpleContent); |
| } |
| |
| } // End of function traverseSimpleContentDecl |
| |
| /** |
| * Traverse complexContent Declaration |
| * |
| * <complexContent |
| * id = ID |
| * mixed = boolean |
| * {any attributes with non-schema namespace...}> |
| * |
| * Content: (annotation? , (restriction | extension)) |
| * </complexContent> |
| * |
| * <restriction |
| * base = QNAME |
| * id = ID |
| * {any attributes with non-schema namespace...}> |
| * |
| * Content: (annotation? , (group | all | choice | sequence)?, |
| * ((attribute | attributeGroup)* , anyAttribute?)) |
| * </restriction> |
| * |
| * <extension |
| * base = QNAME |
| * id = ID |
| * {any attributes with non-schema namespace...}> |
| * Content: (annotation? , (group | all | choice | sequence)?, |
| * ((attribute | attributeGroup)* , anyAttribute?)) |
| * </extension> |
| */ |
| void TraverseSchema::traverseComplexContentDecl(const XMLCh* const typeName, |
| const DOMElement* const contentDecl, |
| ComplexTypeInfo* const typeInfo, |
| const bool isMixed, |
| Janitor<XSAnnotation>* const janAnnot) |
| { |
| NamespaceScopeManager nsMgr(contentDecl, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check attributes |
| // ----------------------------------------------------------------------- |
| bool preProcessFlag = typeInfo->getPreprocessed(); |
| |
| if (!preProcessFlag) { |
| fAttributeCheck.checkAttributes( |
| contentDecl, GeneralAttributeCheck::E_ComplexContent |
| , this, false, fNonXSAttList |
| ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Determine whether the content is mixed, or element-only |
| // Setting here overrides any setting on the complex type decl |
| // ----------------------------------------------------------------------- |
| const XMLCh* const mixed = getElementAttValue(contentDecl, SchemaSymbols::fgATT_MIXED, DatatypeValidator::Boolean); |
| bool mixedContent = isMixed; |
| |
| if (mixed) { |
| if (XMLString::equals(mixed, SchemaSymbols::fgATTVAL_TRUE) |
| || XMLString::equals(mixed, fgValueOne)) { |
| mixedContent = true; |
| } |
| else if (XMLString::equals(mixed, SchemaSymbols::fgATTVAL_FALSE) |
| || XMLString::equals(mixed, fgValueZero)) { |
| mixedContent = false; |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Since the type must have complex content, set the simple type validators |
| // to null |
| // ----------------------------------------------------------------------- |
| typeInfo->setDatatypeValidator(0); |
| typeInfo->setBaseDatatypeValidator(0); |
| |
| DOMElement* complexContent = checkContent(contentDecl,XUtil::getFirstChildElement(contentDecl),false, !preProcessFlag); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(contentDecl, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| |
| // If there are no children, return |
| if (complexContent == 0) { |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| NamespaceScopeManager nsMgr2(complexContent, fSchemaInfo, this); |
| // ----------------------------------------------------------------------- |
| // The content should be either "restriction" or "extension" |
| // ----------------------------------------------------------------------- |
| const XMLCh* const complexContentName = complexContent->getLocalName(); |
| |
| if (XMLString::equals(complexContentName, SchemaSymbols::fgELT_RESTRICTION)) { |
| typeInfo->setDerivedBy(SchemaSymbols::XSD_RESTRICTION); |
| } |
| else if (XMLString::equals(complexContentName, SchemaSymbols::fgELT_EXTENSION)) { |
| typeInfo->setDerivedBy(SchemaSymbols::XSD_EXTENSION); |
| } |
| else { |
| |
| reportSchemaError(complexContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidComplexContent); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Handle the base type name |
| // ----------------------------------------------------------------------- |
| const XMLCh* baseName = getElementAttValue(complexContent, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName); |
| |
| if (!baseName || !*baseName) { |
| |
| reportSchemaError(complexContent, XMLUni::fgXMLErrDomain, XMLErrs::UnspecifiedBase); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| const XMLCh* prefix = getPrefix(baseName); |
| const XMLCh* localPart = getLocalPart(baseName); |
| const XMLCh* uri = resolvePrefixToURI(complexContent, prefix); |
| bool isBaseAnyType = false; |
| |
| // ------------------------------------------------------------- |
| // check if the base is "anyType" |
| // ------------------------------------------------------------- |
| if (XMLString::equals(uri, SchemaSymbols::fgURI_SCHEMAFORSCHEMA) && |
| XMLString::equals(localPart, SchemaSymbols::fgATTVAL_ANYTYPE)) { |
| isBaseAnyType = true; |
| } |
| else { |
| |
| processBaseTypeInfo(complexContent, baseName, localPart, uri, typeInfo); |
| |
| //Check that the base is a complex type |
| if (typeInfo->getBaseComplexTypeInfo() == 0) { |
| |
| reportSchemaError(complexContent, XMLUni::fgXMLErrDomain, XMLErrs::BaseNotComplexType); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| |
| if (fCurrentGroupInfo) // defer processing until later |
| throw TraverseSchema::RecursingElement; |
| |
| // ----------------------------------------------------------------------- |
| // Process the content of the derivation |
| // ----------------------------------------------------------------------- |
| //Skip over any annotations in the restriction or extension elements |
| DOMElement* content = checkContent(complexContent, XUtil::getFirstChildElement(complexContent), true); |
| if (fAnnotation) |
| { |
| if (janAnnot->isDataNull()) |
| janAnnot->reset(fAnnotation); |
| else |
| janAnnot->get()->setNext(fAnnotation); |
| } |
| |
| processComplexContent(complexContent, typeName, content, typeInfo, localPart, |
| mixedContent, isBaseAnyType); |
| |
| if (XUtil::getNextSiblingElement(complexContent) != 0) { |
| reportSchemaError(complexContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexContent); |
| } |
| } |
| |
| |
| /** |
| * <anyAttribute |
| * id = ID |
| * namespace = ((##any | ##other) | list of (anyURI | (##targetNamespace | ##local)))> |
| * processContents = (lax | skip | strict) : strict |
| * Content: (annotation?) |
| * </anyAttribute> |
| */ |
| SchemaAttDef* TraverseSchema::traverseAnyAttribute(const DOMElement* const elem) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_AnyAttribute, this, false, fNonXSAttList |
| ); |
| |
| // ------------------------------------------------------------------ |
| // First, handle any ANNOTATION declaration |
| // ------------------------------------------------------------------ |
| if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AnyAttributeContentError); |
| } |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| // ------------------------------------------------------------------ |
| // Get attributes |
| // ------------------------------------------------------------------ |
| const XMLCh* const processContents = getElementAttValue(elem, SchemaSymbols::fgATT_PROCESSCONTENTS); |
| const XMLCh* const nameSpace = getElementAttValue(elem, SchemaSymbols::fgATT_NAMESPACE); |
| |
| // ------------------------------------------------------------------ |
| // Set default att type based on 'processContents' value |
| // ------------------------------------------------------------------ |
| XMLAttDef::DefAttTypes attDefType = XMLAttDef::ProcessContents_Strict; |
| |
| if ((!processContents || !*processContents) |
| || XMLString::equals(processContents, SchemaSymbols::fgATTVAL_STRICT)) { |
| // Do nothing - defaulted already |
| } |
| else if (XMLString::equals(processContents, SchemaSymbols::fgATTVAL_SKIP)) { |
| attDefType = XMLAttDef::ProcessContents_Skip; |
| } |
| else if (XMLString::equals(processContents, SchemaSymbols::fgATTVAL_LAX)) { |
| attDefType = XMLAttDef::ProcessContents_Lax; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Process 'namespace' attribute |
| // ------------------------------------------------------------------ |
| int uriIndex = fEmptyNamespaceURI; |
| XMLAttDef::AttTypes attType = XMLAttDef::Any_Any; |
| ValueVectorOf<unsigned int> namespaceList(8, fGrammarPoolMemoryManager); |
| |
| if ((!nameSpace || !*nameSpace) |
| || XMLString::equals(nameSpace, SchemaSymbols::fgATTVAL_TWOPOUNDANY)) { |
| // Do nothing - defaulted already |
| } |
| else if (XMLString::equals(nameSpace, SchemaSymbols::fgATTVAL_TWOPOUNDOTHER)) { |
| |
| attType = XMLAttDef::Any_Other; |
| uriIndex = fTargetNSURI; |
| } |
| else { |
| |
| XMLStringTokenizer tokenizer(nameSpace, fGrammarPoolMemoryManager); |
| DatatypeValidator* anyURIDV = fDatatypeRegistry->getDatatypeValidator(SchemaSymbols::fgDT_ANYURI); |
| |
| attType = XMLAttDef::Any_List; |
| |
| while (tokenizer.hasMoreTokens()) { |
| |
| const XMLCh* token = tokenizer.nextToken(); |
| |
| if (XMLString::equals(token, SchemaSymbols::fgATTVAL_TWOPOUNDLOCAL)) { |
| uriIndex = fEmptyNamespaceURI; |
| } |
| else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_TWOPOUNDTRAGETNAMESPACE)) { |
| uriIndex = fTargetNSURI; |
| } |
| else { |
| |
| try { |
| anyURIDV->validate(token |
| , fSchemaInfo->getValidationContext() |
| , fMemoryManager); |
| } |
| catch(const XMLException& excep) { |
| reportSchemaError(elem, excep); |
| } |
| uriIndex = fURIStringPool->addOrFind(token); |
| } |
| |
| if (!namespaceList.containsElement(uriIndex)) { |
| namespaceList.addElement(uriIndex); |
| } |
| } |
| |
| uriIndex = fEmptyNamespaceURI; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Create wildcard attribute |
| // ------------------------------------------------------------------ |
| SchemaAttDef* attDef = new (fGrammarPoolMemoryManager) SchemaAttDef(XMLUni::fgZeroLenString, |
| XMLUni::fgZeroLenString, |
| uriIndex, attType, attDefType, |
| fGrammarPoolMemoryManager); |
| |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(attDef, janAnnot.release()); |
| |
| if (namespaceList.size()) { |
| attDef->setNamespaceList(&namespaceList); |
| } |
| |
| return attDef; |
| } |
| |
| /** |
| * <key |
| * id = ID |
| * name = NCName |
| * Content: (annotation?, (selector, field+)) |
| * </key> |
| */ |
| void TraverseSchema::traverseKey(const DOMElement* const icElem, |
| SchemaElementDecl* const elemDecl) { |
| |
| NamespaceScopeManager nsMgr(icElem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| icElem, GeneralAttributeCheck::E_Key, this, false, fNonXSAttList |
| ); |
| |
| // ----------------------------------------------------------------------- |
| // Create identity constraint |
| // ----------------------------------------------------------------------- |
| const XMLCh* name = getElementAttValue(icElem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) { |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, |
| SchemaSymbols::fgELT_KEY, name); |
| return; |
| } |
| |
| |
| if (!fIdentityConstraintNames) { |
| fIdentityConstraintNames = new (fMemoryManager) RefHash2KeysTableOf<IdentityConstraint>(29, (bool) false, fMemoryManager); |
| } |
| else if (fIdentityConstraintNames->containsKey(name, fTargetNSURI)) { |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_DuplicateDecl, name); |
| return; |
| } |
| |
| IC_Key* icKey = new (fGrammarPoolMemoryManager) IC_Key(name, elemDecl->getBaseName(), fGrammarPoolMemoryManager); |
| Janitor<IC_Key> janKey(icKey); |
| |
| fIdentityConstraintNames->put((void*) name, fTargetNSURI, icKey); |
| |
| // ----------------------------------------------------------------------- |
| // Get selector and fields |
| // ----------------------------------------------------------------------- |
| if (!traverseIdentityConstraint(icKey, icElem)) { |
| |
| fIdentityConstraintNames->put((void*) name, fTargetNSURI, 0); |
| return; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Add key to element declaration |
| // ----------------------------------------------------------------------- |
| elemDecl->addIdentityConstraint(icKey); |
| icKey->setNamespaceURI(fTargetNSURI); |
| janKey.orphan(); |
| } |
| |
| /** |
| * <unique |
| * id = ID |
| * name = NCName |
| * Content: (annotation?, (selector, field+)) |
| * </unique> |
| */ |
| void TraverseSchema::traverseUnique(const DOMElement* const icElem, |
| SchemaElementDecl* const elemDecl) { |
| |
| NamespaceScopeManager nsMgr(icElem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| icElem, GeneralAttributeCheck::E_Unique, this, false, fNonXSAttList |
| ); |
| |
| // ----------------------------------------------------------------------- |
| // Create identity constraint |
| // ----------------------------------------------------------------------- |
| const XMLCh* name = getElementAttValue(icElem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) { |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, |
| SchemaSymbols::fgELT_UNIQUE, name); |
| return; |
| } |
| |
| if (!fIdentityConstraintNames) { |
| fIdentityConstraintNames = new (fGrammarPoolMemoryManager) RefHash2KeysTableOf<IdentityConstraint>(29, (bool) false, fGrammarPoolMemoryManager); |
| } |
| else if (fIdentityConstraintNames->containsKey(name, fTargetNSURI)) { |
| |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_DuplicateDecl, name); |
| return; |
| } |
| |
| IC_Unique* icUnique = new (fGrammarPoolMemoryManager) IC_Unique(name, elemDecl->getBaseName(), fGrammarPoolMemoryManager); |
| Janitor<IC_Unique> janUnique(icUnique); |
| |
| fIdentityConstraintNames->put((void*) name, fTargetNSURI, icUnique); |
| |
| // ----------------------------------------------------------------------- |
| // Get selector and fields |
| // ----------------------------------------------------------------------- |
| if (!traverseIdentityConstraint(icUnique, icElem)) { |
| |
| fIdentityConstraintNames->put((void*) name, fTargetNSURI, 0); |
| return; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Add identity cosntraints to element declaration |
| // ----------------------------------------------------------------------- |
| elemDecl->addIdentityConstraint(icUnique); |
| icUnique->setNamespaceURI(fTargetNSURI); |
| janUnique.orphan(); |
| } |
| |
| /** |
| * <keyref |
| * id = ID |
| * name = NCName |
| * refer = QName |
| * Content: (annotation?, (selector, field+)) |
| * </keyref> |
| */ |
| void TraverseSchema::traverseKeyRef(const DOMElement* const icElem, |
| SchemaElementDecl* const elemDecl) { |
| |
| NamespaceScopeManager nsMgr(icElem, fSchemaInfo, this); |
| |
| // ----------------------------------------------------------------------- |
| // Check Attributes |
| // ----------------------------------------------------------------------- |
| fAttributeCheck.checkAttributes( |
| icElem, GeneralAttributeCheck::E_KeyRef, this, false, fNonXSAttList |
| ); |
| |
| // ----------------------------------------------------------------------- |
| // Verify that key reference "refer" attribute is valid |
| // ----------------------------------------------------------------------- |
| const XMLCh* name = getElementAttValue(icElem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| const XMLCh* refer = getElementAttValue(icElem, SchemaSymbols::fgATT_REFER, DatatypeValidator::QName); |
| |
| if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))) { |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, |
| SchemaSymbols::fgELT_KEYREF, name); |
| return; |
| } |
| |
| const XMLCh* prefix = getPrefix(refer); |
| const XMLCh* localPart = getLocalPart(refer); |
| |
| // we use the DOM API, as the NamespaceScope is now pointing to a different place |
| const XMLCh* uriStr = icElem->lookupNamespaceURI(*prefix==0?NULL:prefix); |
| if ((!uriStr || !*uriStr) && (prefix && *prefix)) |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::UnresolvedPrefix, prefix); |
| if(!uriStr) |
| uriStr=XMLUni::fgZeroLenString; |
| |
| IdentityConstraint* icKey = (fIdentityConstraintNames) |
| ? fIdentityConstraintNames->get(localPart, fURIStringPool->addOrFind(uriStr)) : 0; |
| |
| if (!icKey) { |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_KeyRefReferNotFound, name, localPart); |
| return; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Create identity constraint |
| // ----------------------------------------------------------------------- |
| if(fIdentityConstraintNames->containsKey(name, fTargetNSURI)) { |
| |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_DuplicateDecl, name); |
| return; |
| } |
| |
| IC_KeyRef* icKeyRef = new (fGrammarPoolMemoryManager) IC_KeyRef(name, elemDecl->getBaseName(), icKey, fGrammarPoolMemoryManager); |
| Janitor<IC_KeyRef> janKeyRef(icKeyRef); |
| |
| fIdentityConstraintNames->put((void*) name, fTargetNSURI, icKeyRef); |
| |
| // ----------------------------------------------------------------------- |
| // Get selector and fields |
| // ----------------------------------------------------------------------- |
| if (!traverseIdentityConstraint(icKeyRef, icElem)) { |
| |
| fIdentityConstraintNames->put((void*) name, fTargetNSURI, 0); |
| return; |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Add key reference to element decl |
| // ----------------------------------------------------------------------- |
| if (icKeyRef->getFieldCount() != icKey->getFieldCount()) { |
| |
| fIdentityConstraintNames->put((void*) name, fTargetNSURI, 0); |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_KeyRefCardinality, |
| name, icKey->getIdentityConstraintName()); |
| } |
| else { |
| |
| elemDecl->addIdentityConstraint(icKeyRef); |
| icKeyRef->setNamespaceURI(fTargetNSURI); |
| janKeyRef.orphan(); |
| } |
| } |
| |
| |
| bool TraverseSchema::traverseIdentityConstraint(IdentityConstraint* const ic, |
| const DOMElement* const icElem) { |
| |
| NamespaceScopeManager nsMgr(icElem, fSchemaInfo, this); |
| |
| // ------------------------------------------------------------------ |
| // First, handle any ANNOTATION declaration |
| // ------------------------------------------------------------------ |
| DOMElement* elem = checkContent(icElem, XUtil::getFirstChildElement(icElem), false); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(icElem, fNonXSAttList); |
| } |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| |
| // ------------------------------------------------------------------ |
| // Get selector |
| // ------------------------------------------------------------------ |
| if (elem == 0) { |
| |
| // reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_BadContent); |
| return false; |
| } |
| |
| if (!XMLString::equals(elem->getLocalName(), SchemaSymbols::fgELT_SELECTOR)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::IC_BadContent); |
| return false; |
| } |
| |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_Selector, this, false, fNonXSAttList |
| ); |
| if (checkContent(icElem, XUtil::getFirstChildElement(elem), true) != 0) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot.isDataNull()) |
| janAnnot.reset(fAnnotation); |
| else |
| janAnnot.get()->setNext(fAnnotation); |
| } |
| |
| // ------------------------------------------------------------------ |
| // Get xpath attribute |
| // ------------------------------------------------------------------ |
| const XMLCh* xpathExpr = getElementAttValue(elem, SchemaSymbols::fgATT_XPATH); |
| XMLSize_t xpathLen = XMLString::stringLen(xpathExpr); |
| |
| if (!xpathExpr || !xpathLen) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::IC_XPathExprMissing); |
| return false; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Parse xpath expression |
| // ------------------------------------------------------------------ |
| try { |
| |
| XercesXPath* sXPath = new (fGrammarPoolMemoryManager) XercesXPath(xpathExpr, fStringPool, fSchemaInfo->getNamespaceScope(), fEmptyNamespaceURI, true, fGrammarPoolMemoryManager); |
| IC_Selector* icSelector = new (fGrammarPoolMemoryManager) IC_Selector(sXPath, ic); |
| ic->setSelector(icSelector); |
| } |
| catch (const XPathException& e) { |
| |
| reportSchemaError(elem, e); |
| return false; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Get fields |
| // ------------------------------------------------------------------ |
| elem = XUtil::getNextSiblingElement(elem); |
| |
| if (elem == 0) { |
| |
| reportSchemaError(icElem, XMLUni::fgXMLErrDomain, XMLErrs::IC_BadContent); |
| return false; |
| } |
| |
| while (elem != 0) { |
| |
| if (!XMLString::equals(elem->getLocalName(), SchemaSymbols::fgELT_FIELD)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::IC_BadContent); |
| } |
| else { |
| // General Attribute Checking |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_Field, this, false, fNonXSAttList |
| ); |
| if (checkContent(icElem, XUtil::getFirstChildElement(elem), true) != 0) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::OnlyAnnotationExpected); |
| if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size()) |
| { |
| fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList); |
| } |
| if (fAnnotation) |
| { |
| if (janAnnot.isDataNull()) |
| janAnnot.reset(fAnnotation); |
| else |
| janAnnot.get()->setNext(fAnnotation); |
| } |
| |
| // xpath expression parsing |
| xpathExpr = getElementAttValue(elem, SchemaSymbols::fgATT_XPATH); |
| |
| if (!xpathExpr || !*xpathExpr) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::IC_XPathExprMissing); |
| return false; |
| } |
| |
| try { |
| |
| XercesXPath* fieldXPath = new (fGrammarPoolMemoryManager) XercesXPath |
| ( |
| xpathExpr |
| , fStringPool |
| , fSchemaInfo->getNamespaceScope() |
| , fEmptyNamespaceURI |
| , false |
| , fGrammarPoolMemoryManager |
| ); |
| IC_Field* icField = new (fGrammarPoolMemoryManager) IC_Field(fieldXPath, ic); |
| ic->addField(icField); |
| } |
| catch (const XPathException& e) { |
| |
| reportSchemaError(elem, e); |
| return false; |
| } |
| } |
| |
| elem = XUtil::getNextSiblingElement(elem); |
| } |
| |
| if (!janAnnot.isDataNull()) |
| fSchemaGrammar->putAnnotation(ic, janAnnot.release()); |
| |
| if (ic->getFieldCount() == 0) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // TraverseSchema: Helper methods |
| // --------------------------------------------------------------------------- |
| bool TraverseSchema::retrieveNamespaceMapping(const DOMElement* const elem) { |
| |
| DOMNamedNodeMap* eltAttrs = elem->getAttributes(); |
| bool seenNS=false; |
| const XMLSize_t attrCount = eltAttrs->getLength(); |
| |
| for (XMLSize_t i = 0; i < attrCount; i++) { |
| |
| DOMNode* attribute = eltAttrs->item(i); |
| |
| if (!attribute) { |
| break; |
| } |
| |
| const XMLCh* attName = attribute->getNodeName(); |
| |
| // starts with 'xmlns:' |
| if (XMLString::startsWith(attName, XMLUni::fgXMLNSColonString)) { |
| if(!seenNS) |
| fSchemaInfo->getNamespaceScope()->increaseDepth(); |
| seenNS=true; |
| |
| int offsetIndex = XMLString::indexOf(attName, chColon); |
| const XMLCh* attValue = attribute->getNodeValue(); |
| |
| fSchemaInfo->getNamespaceScope()->addPrefix(attName + offsetIndex + 1, fURIStringPool->addOrFind(attValue)); |
| } |
| else if (XMLString::equals(attName, XMLUni::fgXMLNSString)) { // == 'xmlns' |
| if(!seenNS) |
| fSchemaInfo->getNamespaceScope()->increaseDepth(); |
| seenNS=true; |
| |
| const XMLCh* attValue = attribute->getNodeValue(); |
| fSchemaInfo->getNamespaceScope()->addPrefix(XMLUni::fgZeroLenString, fURIStringPool->addOrFind(attValue)); |
| } |
| } // end for |
| return seenNS; |
| } |
| |
| void TraverseSchema::processChildren(const DOMElement* const root) { |
| |
| NamespaceScopeManager nsMgr(root, fSchemaInfo, this); |
| |
| bool sawAnnotation = false; |
| // process <redefine>, <include> and <import> info items. |
| DOMElement* child = XUtil::getFirstChildElement(root); |
| |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| |
| const XMLCh* name = child->getLocalName(); |
| |
| if (XMLString::equals(name, SchemaSymbols::fgELT_ANNOTATION)) { |
| XSAnnotation* annot = traverseAnnotationDecl( |
| child, fSchemaInfo->getNonXSAttList(), true); |
| if (annot) { |
| fSchemaGrammar->addAnnotation(annot); |
| sawAnnotation = true; |
| } |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_INCLUDE)) { |
| traverseInclude(child); |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_IMPORT)) { |
| traverseImport(child); |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_REDEFINE)) { |
| traverseRedefine(child); |
| } |
| else |
| break; |
| } |
| |
| // child refers to the first info item which is not <annotation> or |
| // one of the schema inclusion/importation declarations. |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| |
| const XMLCh* name = child->getLocalName(); |
| const XMLCh* typeName = getElementAttValue(child, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| int fullNameId = 0; |
| |
| if (typeName) { |
| |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(typeName); |
| fullNameId = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| } |
| |
| if (XMLString::equals(name, SchemaSymbols::fgELT_ANNOTATION)) { |
| XSAnnotation* annot = traverseAnnotationDecl( |
| child, fSchemaInfo->getNonXSAttList(), true); |
| if (annot) { |
| fSchemaGrammar->addAnnotation(annot); |
| sawAnnotation = true; |
| } |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_SIMPLETYPE)) { |
| |
| if (typeName && *typeName) { |
| if (fGlobalDeclarations[ENUM_ELT_SIMPLETYPE]->containsElement(fullNameId) |
| || fGlobalDeclarations[ENUM_ELT_COMPLEXTYPE]->containsElement(fullNameId)) { |
| |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalType, |
| SchemaSymbols::fgELT_SIMPLETYPE, typeName, SchemaSymbols::fgELT_COMPLEXTYPE); |
| continue; |
| } |
| else { |
| fGlobalDeclarations[ENUM_ELT_SIMPLETYPE]->addElement(fullNameId); |
| } |
| } |
| |
| traverseSimpleTypeDecl(child); |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_COMPLEXTYPE)) { |
| |
| if (typeName && *typeName) { |
| if (fGlobalDeclarations[ENUM_ELT_SIMPLETYPE]->containsElement(fullNameId) |
| || fGlobalDeclarations[ENUM_ELT_COMPLEXTYPE]->containsElement(fullNameId)) { |
| |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalType, |
| SchemaSymbols::fgELT_COMPLEXTYPE, typeName, SchemaSymbols::fgELT_SIMPLETYPE); |
| continue; |
| } |
| else { |
| fGlobalDeclarations[ENUM_ELT_COMPLEXTYPE]->addElement(fullNameId); |
| } |
| } |
| |
| traverseComplexTypeDecl(child); |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_ELEMENT)) { |
| |
| if (typeName && *typeName) { |
| if (fGlobalDeclarations[ENUM_ELT_ELEMENT]->containsElement(fullNameId)) { |
| |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalDeclaration, |
| SchemaSymbols::fgELT_ELEMENT, typeName); |
| continue; |
| } |
| else { |
| fGlobalDeclarations[ENUM_ELT_ELEMENT]->addElement(fullNameId); |
| } |
| } |
| |
| traverseElementDecl(child, true); |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_ATTRIBUTEGROUP)) { |
| |
| if (typeName && *typeName) { |
| if (fGlobalDeclarations[ENUM_ELT_ATTRIBUTEGROUP]->containsElement(fullNameId)) { |
| |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalDeclaration, |
| SchemaSymbols::fgELT_ATTRIBUTEGROUP, typeName); |
| continue; |
| } |
| else { |
| fGlobalDeclarations[ENUM_ELT_ATTRIBUTEGROUP]->addElement(fullNameId); |
| } |
| } |
| |
| if (!typeName || !fAttGroupRegistry->containsKey(typeName)) { |
| traverseAttributeGroupDecl(child, 0, true); |
| } |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_ATTRIBUTE)) { |
| |
| if (typeName && *typeName) { |
| if (fGlobalDeclarations[ENUM_ELT_ATTRIBUTE]->containsElement(fullNameId)) { |
| |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, typeName); |
| continue; |
| } |
| else { |
| fGlobalDeclarations[ENUM_ELT_ATTRIBUTE]->addElement(fullNameId); |
| } |
| } |
| |
| if (!typeName || !fAttributeDeclRegistry->containsKey(typeName)) { |
| traverseAttributeDecl( child, 0, true); |
| } |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_GROUP)) { |
| |
| if (typeName && *typeName) { |
| if (fGlobalDeclarations[ENUM_ELT_GROUP]->containsElement(fullNameId)) { |
| |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateGlobalDeclaration, |
| SchemaSymbols::fgELT_GROUP, typeName); |
| continue; |
| } |
| else { |
| fGlobalDeclarations[ENUM_ELT_GROUP]->addElement(fullNameId); |
| } |
| } |
| |
| if (!typeName || !fGroupRegistry->containsKey(fBuffer.getRawBuffer())) { |
| traverseGroupDecl(child); |
| } |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_NOTATION)) { |
| traverseNotationDecl(child); |
| } |
| else { |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::SchemaElementContentError); |
| } |
| } // for each child node |
| |
| |
| if (fScanner->getGenerateSyntheticAnnotations() && fSchemaInfo->getNonXSAttList()->size() && !sawAnnotation) |
| { |
| // synthesize a global annotation here. |
| fSchemaGrammar->addAnnotation( |
| generateSyntheticAnnotation(root, fSchemaInfo->getNonXSAttList()) |
| ); |
| } |
| |
| // Handle recursing elements - if any |
| ValueVectorOf<const DOMElement*>* recursingAnonTypes = fSchemaInfo->getRecursingAnonTypes(); |
| |
| if (recursingAnonTypes) { |
| |
| ValueVectorOf<const XMLCh*>* recursingTypeNames = fSchemaInfo->getRecursingTypeNames(); |
| XMLSize_t recurseSize = recursingAnonTypes->size(); |
| |
| for (XMLSize_t i=0; i < recurseSize; i++) { |
| traverseComplexTypeDecl(recursingAnonTypes->elementAt(i), false, |
| recursingTypeNames->elementAt(i)); |
| } |
| |
| recursingAnonTypes->removeAllElements(); |
| recursingTypeNames->removeAllElements(); |
| } |
| } |
| |
| void TraverseSchema::preprocessChildren(const DOMElement* const root) { |
| |
| NamespaceScopeManager nsMgr(root, fSchemaInfo, this); |
| |
| // process <redefine>, <include> and <import> info items. |
| DOMElement* child = XUtil::getFirstChildElement(root); |
| |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| |
| const XMLCh* name = child->getLocalName(); |
| |
| if (XMLString::equals(name, SchemaSymbols::fgELT_ANNOTATION)) { |
| continue; |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_INCLUDE)) { |
| preprocessInclude(child); |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_IMPORT)) { |
| preprocessImport(child); |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_REDEFINE)) { |
| preprocessRedefine(child); |
| } |
| else |
| break; |
| } |
| } |
| |
| DOMElement* TraverseSchema::checkContent( const DOMElement* const rootElem |
| , DOMElement* const contentElem |
| , const bool isEmpty |
| , const bool processAnnot) |
| { |
| DOMElement* content = contentElem; |
| const XMLCh* name = getElementAttValue(rootElem,SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| |
| fAnnotation = 0; |
| Janitor<XSAnnotation> janAnnot(0); |
| if (!content) { |
| |
| if (!isEmpty) { |
| reportSchemaError(rootElem, XMLUni::fgXMLErrDomain, XMLErrs::ContentError, name); |
| } |
| |
| return 0; |
| } |
| |
| if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) { |
| |
| if (processAnnot) { |
| janAnnot.reset(traverseAnnotationDecl(content, fNonXSAttList)); |
| } |
| content = XUtil::getNextSiblingElement(content); |
| |
| if (!content) { // must be followed by content |
| |
| if (!isEmpty) { |
| reportSchemaError(contentElem, XMLUni::fgXMLErrDomain, XMLErrs::ContentError, name); |
| } |
| fAnnotation = janAnnot.release(); |
| return 0; |
| } |
| |
| if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) { |
| |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::AnnotationError, name); |
| return 0; |
| } |
| fAnnotation = janAnnot.release(); |
| } |
| return content; |
| } |
| |
| |
| DatatypeValidator* |
| TraverseSchema::getDatatypeValidator(const XMLCh* const uriStr, |
| const XMLCh* const localPartStr) { |
| |
| DatatypeValidator* dv = 0; |
| |
| if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { |
| dv = fDatatypeRegistry->getDatatypeValidator(localPartStr); |
| } |
| else { |
| |
| fBuffer.set(uriStr); |
| fBuffer.append(chComma); |
| fBuffer.append(localPartStr); |
| |
| if ((uriStr) && !XMLString::equals(uriStr, fTargetNSURIString)) { |
| |
| Grammar* grammar = fGrammarResolver->getGrammar(uriStr); |
| |
| if (grammar && grammar->getGrammarType() == Grammar::SchemaGrammarType) { |
| dv = ((SchemaGrammar*) grammar)->getDatatypeRegistry()->getDatatypeValidator(fBuffer.getRawBuffer()); |
| } |
| } |
| else { |
| dv = fDatatypeRegistry->getDatatypeValidator(fBuffer.getRawBuffer()); |
| } |
| } |
| |
| return dv; |
| } |
| |
| |
| DatatypeValidator* |
| TraverseSchema::checkForSimpleTypeValidator(const DOMElement* const content, |
| int baseRefContext) { |
| |
| DatatypeValidator* baseValidator = traverseSimpleTypeDecl(content, false, baseRefContext); |
| |
| if (!baseValidator) { |
| |
| const XMLCh* name = getElementAttValue(content,SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::UnknownSimpleType, name); |
| } |
| |
| return baseValidator; |
| } |
| |
| ComplexTypeInfo* |
| TraverseSchema::checkForComplexTypeInfo(const DOMElement* const content) { |
| |
| int typeNameIndex = traverseComplexTypeDecl(content, false); |
| ComplexTypeInfo* baseTypeInfo = 0; |
| |
| if (typeNameIndex != -1) { |
| baseTypeInfo = fComplexTypeRegistry->get(fStringPool->getValueForId(typeNameIndex)); |
| } |
| |
| if (typeNameIndex == -1 || baseTypeInfo == 0) { |
| |
| const XMLCh* name = getElementAttValue(content,SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::UnknownComplexType, name); |
| } |
| |
| return baseTypeInfo; |
| } |
| |
| DatatypeValidator* |
| TraverseSchema::findDTValidator(const DOMElement* const elem, |
| const XMLCh* const derivedTypeName, |
| const XMLCh* const baseTypeName, |
| const int baseRefContext) { |
| |
| const XMLCh* prefix = getPrefix(baseTypeName); |
| const XMLCh* localPart = getLocalPart(baseTypeName); |
| const XMLCh* uri = resolvePrefixToURI(elem, prefix); |
| DatatypeValidator* baseValidator = getDatatypeValidator(uri, localPart); |
| |
| if (baseValidator == 0) { |
| |
| // Check if the base is from the schema for schema namespace |
| // |
| if (XMLString::equals(uri, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, uri, localPart); |
| return 0; |
| } |
| |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| SchemaInfo* saveInfo = fSchemaInfo; |
| unsigned int saveScope = fCurrentScope; |
| |
| if (!XMLString::equals(uri, fTargetNSURIString) && (uri && *uri)) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(uri); |
| |
| if (!isImportingNS(uriId)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uri); |
| return 0; |
| } |
| |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId); |
| |
| if (!impInfo || impInfo->getProcessed()) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, uri, localPart); |
| return 0; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| |
| DOMElement* baseTypeNode = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_SimpleType, |
| SchemaSymbols::fgELT_SIMPLETYPE, localPart, &fSchemaInfo); |
| |
| if (baseTypeNode != 0) { |
| |
| baseValidator = traverseSimpleTypeDecl(baseTypeNode); |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| } |
| } |
| |
| if (baseValidator == 0) { |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::UnknownBaseDatatype, baseTypeName, derivedTypeName); |
| } |
| else if ((baseValidator->getFinalSet() & baseRefContext) != 0) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DisallowedBaseDerivation, baseTypeName); |
| return 0; |
| } |
| |
| return baseValidator; |
| } |
| |
| |
| const XMLCh* TraverseSchema::resolvePrefixToURI(const DOMElement* const elem, |
| const XMLCh* const prefix) { |
| |
| unsigned int nameSpaceIndex = fSchemaInfo->getNamespaceScope()->getNamespaceForPrefix(prefix); |
| const XMLCh* uriStr = fURIStringPool->getValueForId(nameSpaceIndex); |
| |
| if ((!uriStr || !*uriStr) && (prefix && *prefix)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::UnresolvedPrefix, prefix); |
| return XMLUni::fgZeroLenString; |
| } |
| |
| return uriStr; |
| } |
| |
| SchemaElementDecl* |
| TraverseSchema::processElementDeclRef(const DOMElement* const elem, |
| const XMLCh* const refName) |
| { |
| // check attributes |
| fAttributeCheck.checkAttributes( |
| elem, GeneralAttributeCheck::E_ElementRef, this, false, fNonXSAttList |
| ); |
| |
| // handle annotation |
| DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true); |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| |
| // do not generate synthetic annotation for element reference... |
| |
| if (content != 0) |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::NoContentForRef, SchemaSymbols::fgELT_ELEMENT); |
| |
| SchemaElementDecl* refElemDecl = getGlobalElemDecl(elem, refName); |
| |
| if (!refElemDecl) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::RefElementNotFound, refName); |
| } |
| else |
| { |
| if (fCurrentComplexType) |
| fCurrentComplexType->addElement(refElemDecl); |
| |
| if (fCurrentGroupInfo) |
| fCurrentGroupInfo->addElement(refElemDecl); |
| } |
| |
| return refElemDecl; |
| } |
| |
| int TraverseSchema::parseBlockSet(const DOMElement* const elem, |
| const int blockType, const bool isRoot) { |
| |
| const XMLCh* blockVal = (isRoot) ? getElementAttValue(elem, SchemaSymbols::fgATT_BLOCKDEFAULT) |
| : getElementAttValue(elem, SchemaSymbols::fgATT_BLOCK); |
| |
| // blockVal == 0 means 'block attribute is missing'; *blockVal == 0 means 'block="" found' |
| if (blockVal == 0) |
| return fSchemaInfo->getBlockDefault(); |
| |
| int blockSet = 0; |
| |
| if (XMLString::equals(blockVal, SchemaSymbols::fgATTVAL_POUNDALL)) { |
| |
| blockSet = SchemaSymbols::XSD_EXTENSION + SchemaSymbols::XSD_RESTRICTION + SchemaSymbols::XSD_SUBSTITUTION; |
| return blockSet; |
| } |
| |
| XMLStringTokenizer tokenizer(blockVal, fGrammarPoolMemoryManager); |
| |
| while (tokenizer.hasMoreTokens()) { |
| |
| XMLCh* token = tokenizer.nextToken(); |
| |
| if (XMLString::equals(token, SchemaSymbols::fgATTVAL_SUBSTITUTION) |
| && blockType == ES_Block) { |
| |
| if ((blockSet & SchemaSymbols::XSD_SUBSTITUTION) == 0 ) { |
| blockSet += SchemaSymbols::XSD_SUBSTITUTION; |
| } |
| } |
| else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_EXTENSION)) { |
| |
| if ((blockSet & SchemaSymbols::XSD_EXTENSION) == 0) { |
| blockSet += SchemaSymbols::XSD_EXTENSION; |
| } |
| } |
| else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_RESTRICTION)) { |
| |
| if ((blockSet & SchemaSymbols::XSD_RESTRICTION) == 0 ) { |
| blockSet += SchemaSymbols::XSD_RESTRICTION; |
| } |
| } |
| else { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidBlockValue, blockVal); |
| } |
| } //end while |
| |
| return blockSet; |
| } |
| |
| int TraverseSchema::parseFinalSet(const DOMElement* const elem, |
| const int finalType, const bool isRoot) { |
| |
| const XMLCh* finalVal = (isRoot) ? getElementAttValue(elem, SchemaSymbols::fgATT_FINALDEFAULT) |
| : getElementAttValue(elem, SchemaSymbols::fgATT_FINAL); |
| |
| // finalVal == 0 means 'final attribute is missing'; *finalVal == 0 means 'final="" found' |
| if (finalVal == 0) |
| return fSchemaInfo->getFinalDefault(); |
| |
| int finalSet = 0; |
| |
| if (XMLString::equals(finalVal, SchemaSymbols::fgATTVAL_POUNDALL)) { |
| |
| finalSet = SchemaSymbols::XSD_RESTRICTION + SchemaSymbols::XSD_LIST + |
| SchemaSymbols::XSD_UNION + SchemaSymbols::XSD_EXTENSION; |
| return finalSet; |
| } |
| |
| XMLStringTokenizer tokenizer(finalVal, fGrammarPoolMemoryManager); |
| |
| while (tokenizer.hasMoreTokens()) { |
| |
| XMLCh* token = tokenizer.nextToken(); |
| |
| if (XMLString::equals(token, SchemaSymbols::fgELT_UNION) |
| && (finalType == S_Final || finalType == ECS_Final)) { |
| |
| if ((finalSet & SchemaSymbols::XSD_UNION) == 0) { |
| finalSet += SchemaSymbols::XSD_UNION; |
| } |
| } |
| else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_EXTENSION) |
| && (finalType == EC_Final || finalType == ECS_Final)) { |
| |
| if ((finalSet & SchemaSymbols::XSD_EXTENSION) == 0) { |
| finalSet += SchemaSymbols::XSD_EXTENSION; |
| } |
| } |
| else if (XMLString::equals(token, SchemaSymbols::fgELT_LIST) |
| && (finalType == S_Final || finalType == ECS_Final)) { |
| |
| if ((finalSet & SchemaSymbols::XSD_LIST) == 0 ) { |
| finalSet += SchemaSymbols::XSD_LIST; |
| } |
| } |
| else if (XMLString::equals(token, SchemaSymbols::fgATTVAL_RESTRICTION)) { |
| |
| if ((finalSet & SchemaSymbols::XSD_RESTRICTION) == 0 ) { |
| finalSet += SchemaSymbols::XSD_RESTRICTION; |
| } |
| } |
| else { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidFinalValue, finalVal); |
| } |
| } //end while |
| |
| return finalSet; |
| } |
| |
| |
| const DOMElement* |
| TraverseSchema::checkIdentityConstraintContent(const DOMElement* const content) { |
| |
| const DOMElement* child = content; |
| |
| if (child != 0) { |
| |
| do { |
| |
| if (!isIdentityConstraintName(child->getLocalName())) { |
| break; |
| } |
| |
| child = XUtil::getNextSiblingElement(child); |
| |
| } while (child != 0); |
| } |
| |
| return child; |
| } |
| |
| bool TraverseSchema::isIdentityConstraintName(const XMLCh* const name) { |
| |
| return (XMLString::equals(name, SchemaSymbols::fgELT_KEY) |
| || XMLString::equals(name, SchemaSymbols::fgELT_KEYREF) |
| || XMLString::equals(name, SchemaSymbols::fgELT_UNIQUE)); |
| } |
| |
| const XMLCh* |
| TraverseSchema::checkTypeFromAnotherSchema(const DOMElement* const elem, |
| const XMLCh* const typeStr) { |
| |
| const XMLCh* prefix = getPrefix(typeStr); |
| const XMLCh* typeURI = resolvePrefixToURI(elem, prefix); |
| |
| if (!XMLString::equals(typeURI, fTargetNSURIString) |
| && !XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA) |
| ) { |
| return typeURI; |
| } |
| |
| return 0; |
| } |
| |
| DatatypeValidator* |
| TraverseSchema::getElementTypeValidator(const DOMElement* const elem, |
| const XMLCh* const typeStr, |
| bool& noErrorDetected, |
| const XMLCh* const otherSchemaURI) |
| { |
| const XMLCh* localPart = getLocalPart(typeStr); |
| const XMLCh* typeURI = otherSchemaURI; |
| DatatypeValidator* dv = 0; |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| SchemaInfo* saveInfo = fSchemaInfo; |
| unsigned int saveScope = fCurrentScope; |
| |
| if (otherSchemaURI && *otherSchemaURI) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(otherSchemaURI); |
| |
| if (!isImportingNS(uriId)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, otherSchemaURI); |
| return 0; |
| } |
| |
| dv = getDatatypeValidator(typeURI, localPart); |
| |
| if (dv) { |
| return dv; |
| } |
| |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId); |
| |
| if (!impInfo || impInfo->getProcessed()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, typeURI, localPart); |
| return 0; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| else { |
| const XMLCh* prefix = getPrefix(typeStr); |
| |
| typeURI = resolvePrefixToURI(elem, prefix); |
| dv = getDatatypeValidator(typeURI, localPart); |
| } |
| |
| if (!dv) { |
| |
| if (!XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA) |
| || XMLString::equals(fTargetNSURIString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { |
| |
| DOMElement* typeElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_SimpleType, |
| SchemaSymbols::fgELT_SIMPLETYPE, localPart, &fSchemaInfo); |
| |
| if (typeElem) { |
| traverseSimpleTypeDecl(typeElem); |
| dv = getDatatypeValidator(typeURI, localPart); |
| } |
| } |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| |
| if (!dv) { |
| |
| noErrorDetected = false; |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, typeURI, localPart); |
| } |
| } |
| |
| return dv; |
| } |
| |
| |
| DatatypeValidator* |
| TraverseSchema::getAttrDatatypeValidatorNS(const DOMElement* const elem, |
| const XMLCh* localPart, |
| const XMLCh* typeURI) |
| { |
| DatatypeValidator* dv = getDatatypeValidator(typeURI, localPart); |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| SchemaInfo* saveInfo = fSchemaInfo; |
| unsigned int saveScope = fCurrentScope; |
| |
| if (!XMLString::equals(typeURI, fTargetNSURIString) |
| && (typeURI && *typeURI)) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(typeURI); |
| |
| if (!isImportingNS(uriId)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, typeURI); |
| return 0; |
| } |
| |
| if (!dv) { |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId); |
| |
| if (!impInfo || impInfo->getProcessed()) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, typeURI, localPart); |
| return 0; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| } |
| |
| if (!dv) { |
| |
| DOMElement* typeElem = fSchemaInfo->getTopLevelComponent |
| ( |
| SchemaInfo::C_SimpleType |
| , SchemaSymbols::fgELT_SIMPLETYPE |
| , localPart |
| , &fSchemaInfo |
| ); |
| |
| if (typeElem) |
| dv = traverseSimpleTypeDecl(typeElem); |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| } |
| |
| return dv; |
| } |
| |
| ComplexTypeInfo* |
| TraverseSchema::getElementComplexTypeInfo(const DOMElement* const elem, |
| const XMLCh* const typeStr, |
| const XMLCh* const otherSchemaURI) |
| { |
| const XMLCh* localPart = getLocalPart(typeStr); |
| const XMLCh* prefix = getPrefix(typeStr); |
| const XMLCh* typeURI = (otherSchemaURI) ? otherSchemaURI : resolvePrefixToURI(elem, prefix); |
| ComplexTypeInfo* typeInfo = 0; |
| SchemaInfo* saveInfo = fSchemaInfo; |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| unsigned int saveScope = fCurrentScope; |
| |
| fBuffer.set(typeURI); |
| fBuffer.append(chComma); |
| fBuffer.append(localPart); |
| |
| if (otherSchemaURI != 0) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(typeURI); |
| |
| if (!isImportingNS(uriId)) |
| return 0; |
| |
| Grammar* aGrammar = fGrammarResolver->getGrammar(typeURI); |
| |
| if (!aGrammar || aGrammar->getGrammarType() != Grammar::SchemaGrammarType) { |
| return 0; |
| } |
| |
| typeInfo = ((SchemaGrammar*)aGrammar)->getComplexTypeRegistry()->get(fBuffer.getRawBuffer()); |
| |
| if (typeInfo) { |
| return typeInfo; |
| } |
| |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId); |
| |
| if (!impInfo || impInfo->getProcessed()) { |
| return 0; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| else { |
| typeInfo = fComplexTypeRegistry->get(fBuffer.getRawBuffer()); |
| } |
| |
| if (!typeInfo) { |
| if (!XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA) || |
| XMLString::equals(fTargetNSURIString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { |
| |
| DOMElement* typeNode = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_ComplexType, |
| SchemaSymbols::fgELT_COMPLEXTYPE, localPart, &fSchemaInfo); |
| |
| if (typeNode) { |
| // fBuffer is reused by traverseComplexTypeDecl, so we have to store its current value |
| XMLBuffer buffCopy(fBuffer.getLen()+1, fMemoryManager); |
| buffCopy.set(fBuffer.getRawBuffer()); |
| traverseComplexTypeDecl(typeNode); |
| typeInfo = fComplexTypeRegistry->get(buffCopy.getRawBuffer()); |
| } |
| } |
| } |
| |
| // restore schema information |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| return typeInfo; |
| } |
| |
| |
| SchemaElementDecl* |
| TraverseSchema::getGlobalElemDecl(const DOMElement* const elem, |
| const XMLCh* const qName) |
| { |
| const XMLCh* nameURI = resolvePrefixToURI(elem, getPrefix(qName)); |
| const XMLCh* localPart = getLocalPart(qName); |
| SchemaElementDecl* elemDecl = 0; |
| SchemaInfo* saveInfo = fSchemaInfo; |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| unsigned int saveScope = fCurrentScope; |
| unsigned int uriId = fURIStringPool->addOrFind(nameURI); |
| |
| if (fSchemaInfo->getTargetNSURI() != (int) uriId) |
| { |
| //if (!XMLString::equals(nameURI, fTargetNSURIString)) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| if (!isImportingNS(uriId)) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, nameURI); |
| return 0; |
| } |
| |
| Grammar* grammar = fGrammarResolver->getGrammar(nameURI); |
| |
| if (grammar && grammar->getGrammarType() == Grammar::SchemaGrammarType) |
| { |
| elemDecl = (SchemaElementDecl*) grammar->getElemDecl( |
| uriId, localPart, 0, Grammar::TOP_LEVEL_SCOPE); |
| } |
| else |
| { |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, nameURI); |
| return 0; |
| } |
| |
| if (!elemDecl) |
| { |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(uriId); |
| if (!impInfo || impInfo->getProcessed()) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, nameURI, localPart); |
| return 0; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| } |
| else |
| { |
| elemDecl = (SchemaElementDecl*) |
| fSchemaGrammar->getElemDecl(fTargetNSURI, localPart, 0, Grammar::TOP_LEVEL_SCOPE); |
| } |
| |
| if (!elemDecl) |
| { |
| DOMElement* subsGroupElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Element, |
| SchemaSymbols::fgELT_ELEMENT,localPart, &fSchemaInfo); |
| |
| if (subsGroupElem) |
| elemDecl = traverseElementDecl(subsGroupElem, true); |
| |
| if (!elemDecl) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, nameURI, localPart); |
| } |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| |
| return elemDecl; |
| } |
| |
| bool |
| TraverseSchema::isSubstitutionGroupValid(const DOMElement* const elem, |
| const SchemaElementDecl* const subsElemDecl, |
| const ComplexTypeInfo* const typeInfo, |
| const DatatypeValidator* const validator, |
| const XMLCh* const elemName, |
| const bool toEmit) { |
| |
| // here we must do two things: |
| // 1. Make sure there actually *is* a relation between the types of |
| // the element being nominated and the element doing the nominating; |
| // (see PR 3.3.6 point #3 in the first tableau, for instance; this |
| // and the corresponding tableaux from 3.4.6 and 3.14.6 rule out the nominated |
| // element having an anonymous type declaration. |
| // 2. Make sure the nominated element allows itself to be nominated by |
| // an element with the given type-relation. |
| // Note: we assume that (complex|simple)Type processing checks |
| // whether the type in question allows itself to |
| // be modified as this element desires. |
| |
| // if substitution element has any as content model type, return true |
| bool subsRestricted = false; |
| if (subsElemDecl->getModelType() == SchemaElementDecl::Any) { |
| |
| if ((subsElemDecl->getFinalSet() & SchemaSymbols::XSD_RESTRICTION) == 0 |
| || (typeInfo == 0 && validator == 0)) |
| return true; |
| else |
| subsRestricted = true; |
| } |
| // Check for type relationship; |
| // that is, make sure that the type we're deriving has some relatoinship |
| // to substitutionGroupElt's type. |
| else if (typeInfo) { // do complexType case ...need testing |
| |
| ComplexTypeInfo* subsTypeInfo = subsElemDecl->getComplexTypeInfo(); |
| |
| if (subsTypeInfo == typeInfo) |
| return true; |
| |
| int derivationMethod = typeInfo->getDerivedBy(); |
| |
| if (subsTypeInfo == 0) { // take care of complexType based on simpleType case... |
| |
| DatatypeValidator* elemDV = typeInfo->getDatatypeValidator(); |
| DatatypeValidator* subsValidator = subsElemDecl->getDatatypeValidator(); |
| |
| if (elemDV == subsValidator) { |
| return true; |
| } |
| else if (subsValidator && subsValidator->isSubstitutableBy(elemDV)) { |
| if ((subsElemDecl->getFinalSet() & derivationMethod) == 0) { |
| return true; |
| } |
| else { |
| subsRestricted = true; |
| } |
| } |
| } |
| else { // complex content |
| |
| const ComplexTypeInfo* elemTypeInfo = typeInfo; |
| |
| for (; elemTypeInfo && elemTypeInfo != subsTypeInfo; |
| elemTypeInfo = elemTypeInfo->getBaseComplexTypeInfo()) { |
| } |
| |
| if (elemTypeInfo) { |
| if ((subsElemDecl->getFinalSet() & derivationMethod) == 0) { |
| return true; |
| } |
| else { |
| subsRestricted = true; |
| } |
| } |
| } |
| } |
| else if (validator) { // do simpleType case... |
| |
| if (!subsElemDecl->getComplexTypeInfo()) { |
| // first, check for type relation. |
| DatatypeValidator* subsValidator = subsElemDecl->getDatatypeValidator(); |
| |
| if (subsValidator == validator) { |
| return true; |
| } |
| else if (subsValidator && subsValidator->isSubstitutableBy(validator) |
| && ((subsElemDecl->getFinalSet() & SchemaSymbols::XSD_RESTRICTION) == 0)) { |
| return true; |
| } |
| } |
| } |
| else // validator==0 && typeInfo==0 -- no checking |
| return true; |
| |
| if (toEmit) { |
| if (subsRestricted) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSubstitutionGroupElement, |
| elemName, subsElemDecl->getBaseName()); |
| } |
| else { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::SubstitutionGroupTypeMismatch, elemName); |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| SchemaElementDecl* |
| TraverseSchema::createSchemaElementDecl(const DOMElement* const elem, |
| const XMLCh* const name, |
| bool& isDuplicate, |
| const XMLCh*& valConstraint, |
| const bool topLevel) |
| { |
| unsigned int enclosingScope = fCurrentScope; |
| int uriIndex = fEmptyNamespaceURI; |
| |
| if (topLevel) { |
| |
| uriIndex = fTargetNSURI; |
| enclosingScope = Grammar::TOP_LEVEL_SCOPE; |
| } |
| else |
| { |
| const XMLCh* elemForm = getElementAttValue(elem, SchemaSymbols::fgATT_FORM); |
| |
| if (((!elemForm || !*elemForm) && |
| (fSchemaInfo->getElemAttrDefaultQualified() & Elem_Def_Qualified)) |
| || XMLString::equals(elemForm,SchemaSymbols::fgATTVAL_QUALIFIED)) |
| uriIndex = fTargetNSURI; |
| |
| // Check for duplicate elements |
| SchemaElementDecl* other = (SchemaElementDecl*) |
| fSchemaGrammar->getElemDecl(uriIndex, name, 0, enclosingScope); |
| |
| if (other != 0) |
| { |
| isDuplicate = true; |
| return other; |
| } |
| } |
| |
| // create element decl and add it to the grammar |
| Janitor<SchemaElementDecl> elemDecl(new (fGrammarPoolMemoryManager) SchemaElementDecl( |
| XMLUni::fgZeroLenString , name, uriIndex , SchemaElementDecl::Any |
| , enclosingScope , fGrammarPoolMemoryManager |
| )); |
| |
| elemDecl->setCreateReason(XMLElementDecl::Declared); |
| |
| if (topLevel) |
| elemDecl->setPSVIScope(PSVIDefs::SCP_GLOBAL); |
| |
| // process attributes |
| processElemDeclAttrs(elem, elemDecl.get(), valConstraint, topLevel); |
| |
| return elemDecl.release(); |
| } |
| |
| |
| void TraverseSchema::processAttributeDeclRef(const DOMElement* const elem, |
| ComplexTypeInfo* const typeInfo, |
| const XMLCh* const refName, |
| const XMLCh* const useAttr, |
| const XMLCh* const defaultVal, |
| const XMLCh* const fixedVal) { |
| |
| if (!typeInfo && !fCurrentAttGroupInfo) { |
| return; |
| } |
| |
| const XMLCh* prefix = getPrefix(refName); |
| const XMLCh* localPart = getLocalPart(refName); |
| const XMLCh* uriStr = resolvePrefixToURI(elem, prefix); |
| unsigned int attURI = fURIStringPool->addOrFind(uriStr); |
| |
| // Check for duplicate references |
| if (typeInfo && typeInfo->getAttDef(localPart, attURI)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateRefAttribute, uriStr, localPart); |
| return; |
| } |
| else if (fCurrentAttGroupInfo && fCurrentAttGroupInfo->containsAttribute(localPart, attURI)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateRefAttribute, uriStr, localPart); |
| return; |
| } |
| |
| // check for different namespace |
| SchemaInfo* saveInfo = fSchemaInfo; |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| SchemaAttDef* refAttDef = 0; |
| unsigned int saveScope = fCurrentScope; |
| |
| if (!XMLString::equals(uriStr, fTargetNSURIString)) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(uriStr); |
| |
| if (!isImportingNS(uriId)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr); |
| return; |
| } |
| |
| Grammar* grammar = fGrammarResolver->getGrammar(uriStr); |
| |
| if (grammar == 0 || grammar->getGrammarType() != Grammar::SchemaGrammarType) { |
| |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr); |
| return; |
| } |
| |
| refAttDef = (SchemaAttDef*) ((SchemaGrammar*) grammar)->getAttributeDeclRegistry()->get(localPart); |
| |
| if (!refAttDef) { |
| |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(attURI); |
| |
| if (!impInfo || impInfo->getProcessed()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelAttributeNotFound, refName); |
| return; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| } |
| |
| // if Global attribute registry does not contain the ref attribute, get |
| // the referred attribute declaration and traverse it. |
| if (!refAttDef) { |
| |
| if (fAttributeDeclRegistry->containsKey(localPart) == false) { |
| |
| DOMElement* referredAttribute = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Attribute, |
| SchemaSymbols::fgELT_ATTRIBUTE, localPart, &fSchemaInfo); |
| |
| if (referredAttribute != 0) { |
| traverseAttributeDecl(referredAttribute, 0, true); |
| } |
| } |
| |
| refAttDef = (SchemaAttDef*) fAttributeDeclRegistry->get(localPart); |
| } |
| |
| // restore schema information, if necessary |
| if (fSchemaInfo != saveInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| |
| if (!refAttDef) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelAttributeNotFound, refName); |
| return; |
| } |
| |
| XMLAttDef::DefAttTypes refAttDefType = refAttDef->getDefaultType(); |
| const XMLCh* refAttValue = refAttDef->getValue(); |
| bool invalidAttUse = false; |
| |
| if (refAttDefType == XMLAttDef::Fixed && |
| (defaultVal || (fixedVal && !XMLString::equals(fixedVal, refAttValue)))) { |
| |
| invalidAttUse = true; |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttUseCorrect, refName); |
| } |
| |
| DatatypeValidator* attDV = refAttDef->getDatatypeValidator(); |
| |
| //check for multiple attributes with type derived from ID |
| if (attDV && attDV->getType() == DatatypeValidator::ID) { |
| |
| if (fCurrentAttGroupInfo) { |
| |
| if (fCurrentAttGroupInfo->containsTypeWithId()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttGrpPropCorrect3, refName); |
| return; |
| } |
| |
| fCurrentAttGroupInfo->setTypeWithId(true); |
| } |
| else { |
| |
| if (typeInfo->containsAttWithTypeId()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect5, refName); |
| return; |
| } |
| |
| typeInfo->setAttWithTypeId(true); |
| } |
| } |
| |
| bool required = XMLString::equals(useAttr,SchemaSymbols::fgATTVAL_REQUIRED); |
| bool prohibited = XMLString::equals(useAttr,SchemaSymbols::fgATTVAL_PROHIBITED); |
| QName* attQName = refAttDef->getAttName(); |
| SchemaAttDef* attDef = new (fGrammarPoolMemoryManager) SchemaAttDef(attQName->getPrefix(), |
| attQName->getLocalPart(), |
| attQName->getURI(), |
| refAttValue, |
| refAttDef->getType(), |
| refAttDefType, |
| 0, fGrammarPoolMemoryManager); |
| |
| attDef->setBaseAttDecl(refAttDef); |
| attDef->setPSVIScope(PSVIDefs::SCP_GLOBAL); |
| |
| if (refAttDefType == XMLAttDef::Fixed) { |
| if (required && !invalidAttUse) { |
| attDef->setDefaultType(XMLAttDef::Required_And_Fixed); |
| } |
| } |
| else { |
| |
| if (prohibited) { |
| attDef->setDefaultType(XMLAttDef::Prohibited); |
| } |
| else { |
| |
| const XMLCh* valueConstraint = defaultVal; |
| |
| if (required){ |
| |
| if (fixedVal) { |
| |
| attDef->setDefaultType(XMLAttDef::Required_And_Fixed); |
| valueConstraint = fixedVal; |
| } |
| else { |
| attDef->setDefaultType(XMLAttDef::Required); |
| } |
| } |
| else |
| { |
| if (fixedVal) { |
| attDef->setDefaultType(XMLAttDef::Fixed); |
| valueConstraint = fixedVal; |
| } |
| else if (defaultVal) { |
| attDef->setDefaultType(XMLAttDef::Default); |
| } |
| } |
| |
| if (valueConstraint) { |
| |
| // validate content of value constraint |
| if (attDV) { |
| |
| if (attDV->getType() == DatatypeValidator::ID) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect3, refName); |
| } |
| else { |
| try { |
| attDV->validate(valueConstraint |
| , fSchemaInfo->getValidationContext() |
| , fMemoryManager); |
| } |
| catch(const XMLException& excep) { |
| reportSchemaError(elem, excep); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch (...) { |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::DatatypeValidationFailure, valueConstraint); |
| } |
| } |
| } |
| |
| attDef->setValue(valueConstraint); |
| } |
| } |
| } |
| |
| attDef->setDatatypeValidator(attDV); |
| |
| bool toClone = false; |
| |
| if (typeInfo) { |
| |
| toClone = true; |
| typeInfo->addAttDef(attDef); |
| } |
| |
| if (fCurrentAttGroupInfo) { |
| fCurrentAttGroupInfo->addAttDef(attDef, toClone); |
| } |
| } |
| |
| |
| int TraverseSchema::checkMinMax(ContentSpecNode* const specNode, |
| const DOMElement* const elem, |
| const int allContextFlag) { |
| |
| int minOccurs = 1; |
| int maxOccurs = 1; |
| const XMLCh* minOccursStr = getElementAttValue(elem, SchemaSymbols::fgATT_MINOCCURS, DatatypeValidator::Decimal); |
| const XMLCh* maxOccursStr = getElementAttValue(elem, SchemaSymbols::fgATT_MAXOCCURS, DatatypeValidator::Decimal); |
| |
| if (!minOccursStr || !*minOccursStr) { |
| if (specNode) |
| minOccurs = specNode->getMinOccurs(); |
| } |
| else { |
| try { |
| minOccurs = XMLString::parseInt(minOccursStr, fMemoryManager); |
| } |
| catch(const NumberFormatException& e) |
| { |
| // REVISIT: report a warning that we replaced a number too big? |
| if(e.getCode()==XMLExcepts::Str_ConvertOverflow) |
| minOccurs = 500; |
| else |
| minOccurs = 1; |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| |
| if (specNode) |
| specNode->setMinOccurs(minOccurs); |
| } |
| |
| bool isMaxUnbounded = XMLString::equals(maxOccursStr, fgUnbounded); |
| |
| if (isMaxUnbounded) { |
| maxOccurs = SchemaSymbols::XSD_UNBOUNDED; |
| if (specNode) |
| specNode->setMaxOccurs(maxOccurs); |
| } |
| else { |
| if (!maxOccursStr || !*maxOccursStr) { |
| if (specNode) |
| maxOccurs = specNode->getMaxOccurs(); |
| } |
| else { |
| try { |
| maxOccurs = XMLString::parseInt(maxOccursStr, fMemoryManager); |
| } |
| catch(const NumberFormatException& e) |
| { |
| // REVISIT: report a warning that we replaced a number too big? |
| if(e.getCode()==XMLExcepts::Str_ConvertOverflow && minOccurs < 500) |
| maxOccurs = 500; |
| else |
| maxOccurs = minOccurs; |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| |
| if (specNode) |
| specNode->setMaxOccurs(maxOccurs); |
| } |
| } |
| |
| if (minOccurs == 0 && maxOccurs == 0){ |
| return minOccurs; |
| } |
| |
| // Constraint checking for min/max value |
| if (!isMaxUnbounded) { |
| |
| XMLCh tmpMinStr[128]; |
| XMLCh tmpMaxStr[128]; |
| |
| XMLString::binToText(minOccurs, tmpMinStr, 127, 10, fMemoryManager); |
| XMLString::binToText(maxOccurs, tmpMaxStr, 127, 10, fMemoryManager); |
| |
| if (maxOccurs < 1) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAttValue, |
| tmpMaxStr, SchemaSymbols::fgATT_MAXOCCURS); |
| if (specNode) |
| specNode->setMaxOccurs(minOccurs); |
| } |
| else if (maxOccurs < minOccurs) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidMin2MaxOccurs, |
| tmpMinStr, tmpMaxStr); |
| if (specNode) |
| specNode->setMaxOccurs(minOccurs); |
| } |
| } |
| |
| // Constraint checking for 'all' content |
| bool isAllElement = (allContextFlag == All_Element); |
| bool isAllGroup = (allContextFlag == All_Group); |
| bool isGroupRefAll = (allContextFlag == Group_Ref_With_All); |
| |
| if (isAllElement || isAllGroup || isGroupRefAll) { |
| |
| if (maxOccurs != 1 || minOccurs > 1) { |
| |
| // set back correct value in order to carry on |
| if (specNode) { |
| |
| specNode->setMaxOccurs(1); |
| |
| if (minOccurs > 1) |
| specNode->setMinOccurs(1); |
| } |
| |
| if (isAllElement) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadMinMaxAllElem); |
| } |
| else { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadMinMaxAllCT); |
| } |
| } |
| } |
| return minOccurs; |
| } |
| |
| |
| void TraverseSchema::processComplexContent(const DOMElement* const ctElem, |
| const XMLCh* const typeName, |
| const DOMElement* const childElem, |
| ComplexTypeInfo* const typeInfo, |
| const XMLCh* const baseLocalPart, |
| const bool isMixed, |
| const bool isBaseAnyType) { |
| |
| NamespaceScopeManager nsMgr(childElem, fSchemaInfo, this); |
| |
| Janitor<ContentSpecNode> specNodeJan(0); |
| ContentSpecNode* specNode = specNodeJan.get(); |
| const DOMElement* attrNode = 0; |
| int typeDerivedBy = typeInfo->getDerivedBy(); |
| ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo(); |
| int baseContentType = (baseTypeInfo) ? baseTypeInfo->getContentType() : SchemaElementDecl::Empty; |
| |
| if (baseTypeInfo) { |
| |
| if (typeDerivedBy == SchemaSymbols::XSD_RESTRICTION) { |
| |
| // check to see if the baseType permits derivation by restriction |
| if((baseTypeInfo->getFinalSet() & typeDerivedBy) != 0) { |
| |
| reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivationByRestriction, |
| baseLocalPart); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| else { |
| |
| // check to see if the baseType permits derivation by extension |
| if((baseTypeInfo->getFinalSet() & typeDerivedBy) != 0) { |
| |
| reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivationByExtension, baseLocalPart); |
| throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue |
| } |
| |
| processElements(ctElem, baseTypeInfo, typeInfo); |
| } |
| } |
| |
| bool effectiveContent_hasChild = false; |
| |
| if (childElem != 0) { |
| |
| fCircularCheckIndex = fCurrentTypeNameStack->size(); |
| |
| // -------------------------------------------------------------------- |
| // GROUP, ALL, SEQUENCE or CHOICE, followed by attributes, if specified. |
| // Note that it's possible that only attributes are specified. |
| // -------------------------------------------------------------------- |
| const XMLCh* childName = childElem->getLocalName(); |
| |
| if (XMLString::equals(childName, SchemaSymbols::fgELT_GROUP)) { |
| |
| XercesGroupInfo* grpInfo = traverseGroupDecl(childElem, false); |
| |
| if (grpInfo) { |
| |
| ContentSpecNode* const groupSpecNode = grpInfo->getContentSpec(); |
| |
| if (groupSpecNode) { |
| |
| int contentContext = groupSpecNode->hasAllContent() ? Group_Ref_With_All : Not_All_Context; |
| specNodeJan.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*groupSpecNode)); |
| specNode = specNodeJan.get(); |
| checkMinMax(specNode, childElem, contentContext); |
| } |
| } |
| |
| attrNode = XUtil::getNextSiblingElement(childElem); |
| |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_SEQUENCE)) { |
| |
| specNodeJan.reset(traverseChoiceSequence(childElem, ContentSpecNode::Sequence, effectiveContent_hasChild)); |
| specNode = specNodeJan.get(); |
| checkMinMax(specNode, childElem); |
| attrNode = XUtil::getNextSiblingElement(childElem); |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_CHOICE)) { |
| |
| specNodeJan.reset(traverseChoiceSequence(childElem, ContentSpecNode::Choice, effectiveContent_hasChild)); |
| specNode = specNodeJan.get(); |
| int minOccurs = checkMinMax(specNode, childElem); |
| if (!effectiveContent_hasChild && minOccurs != 0) { |
| effectiveContent_hasChild = true; |
| } |
| |
| attrNode = XUtil::getNextSiblingElement(childElem); |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_ALL)) { |
| |
| specNodeJan.reset(traverseAll(childElem, effectiveContent_hasChild)); |
| specNode = specNodeJan.get(); |
| checkMinMax(specNode, childElem, All_Group); |
| attrNode = XUtil::getNextSiblingElement(childElem); |
| } |
| else if (isAttrOrAttrGroup(childElem)) { |
| // reset the contentType |
| typeInfo->setContentType(SchemaElementDecl::Any); |
| attrNode = childElem; |
| } |
| else { |
| reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType, childName); |
| } |
| } |
| |
| typeInfo->setContentSpec(specNode); |
| typeInfo->setAdoptContentSpec(true); |
| specNodeJan.release(); |
| bool specNodeWasNull = false; |
| |
| // ----------------------------------------------------------------------- |
| // Merge in information from base, if it exists |
| // ----------------------------------------------------------------------- |
| if (baseTypeInfo) { |
| |
| ContentSpecNode* baseSpecNode = baseTypeInfo->getContentSpec(); |
| |
| if (typeDerivedBy == SchemaSymbols::XSD_RESTRICTION) { |
| |
| //check derivation valid - content type is empty (5.2) |
| if (!typeInfo->getContentSpec()) { |
| |
| if (baseContentType != SchemaElementDecl::Empty |
| && !emptiableParticle(baseSpecNode)) { |
| reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::EmptyComplexRestrictionDerivation); |
| } |
| } |
| |
| // Delay particle constraint checking (5.3) until we have processed |
| // the whole schema. |
| } |
| else { |
| |
| // Compose the final content model by concatenating the base and |
| // the current in sequence |
| if (!specNode) { |
| specNodeWasNull = true; |
| if (isMixed) { |
| if (baseSpecNode && baseSpecNode->hasAllContent()) { |
| reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::NotAllContent); |
| throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue |
| } |
| } |
| if (baseSpecNode) { |
| specNodeJan.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*baseSpecNode)); |
| specNode = specNodeJan.get(); |
| typeInfo->setContentSpec(specNode); |
| typeInfo->setAdoptContentSpec(true); |
| specNodeJan.release(); |
| } |
| } |
| else if (baseSpecNode) { |
| |
| if (specNode->hasAllContent() || baseSpecNode->hasAllContent()) { |
| |
| reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::NotAllContent); |
| throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue |
| } |
| |
| // Check for derivation valid (extension) - 1.4.3.2.2.1 |
| if ((isMixed && baseContentType == SchemaElementDecl::Children) |
| || (!isMixed && baseContentType != SchemaElementDecl::Children)) { |
| |
| reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::MixedOrElementOnly, baseLocalPart, typeName); |
| throw TraverseSchema::InvalidComplexTypeInfo; //REVISIT - should we continue |
| } |
| |
| typeInfo->setAdoptContentSpec(false); |
| typeInfo->setContentSpec |
| ( |
| new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| ContentSpecNode::ModelGroupSequence |
| , new (fGrammarPoolMemoryManager) ContentSpecNode(*baseSpecNode) |
| , specNode |
| , true |
| , true |
| , fGrammarPoolMemoryManager |
| ) |
| ); |
| typeInfo->setAdoptContentSpec(true); |
| } |
| } |
| } |
| else { |
| typeInfo->setDerivedBy(0); |
| } |
| |
| // ------------------------------------------------------------- |
| // Set the content type |
| // ------------------------------------------------------------- |
| if (isBaseAnyType && typeDerivedBy == SchemaSymbols::XSD_EXTENSION) { |
| |
| ContentSpecNode* anySpecNode = new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| new (fGrammarPoolMemoryManager) QName |
| ( |
| XMLUni::fgZeroLenString |
| , XMLUni::fgZeroLenString |
| , fEmptyNamespaceURI, fGrammarPoolMemoryManager |
| ) |
| , false |
| , fGrammarPoolMemoryManager |
| ); |
| |
| anySpecNode->setType(ContentSpecNode::Any_Lax); |
| anySpecNode->setMinOccurs(0); |
| anySpecNode->setMaxOccurs(SchemaSymbols::XSD_UNBOUNDED); |
| |
| if (!specNode) { |
| typeInfo->setContentSpec(anySpecNode); |
| typeInfo->setDerivedBy(typeDerivedBy); |
| } |
| else { |
| |
| typeInfo->setAdoptContentSpec(false); |
| typeInfo->setContentSpec |
| ( |
| new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| ContentSpecNode::ModelGroupSequence |
| , anySpecNode |
| , specNode |
| , true |
| , true |
| , fGrammarPoolMemoryManager |
| ) |
| ); |
| typeInfo->setAdoptContentSpec(true); |
| |
| if (!isMixed) { |
| |
| reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::MixedOrElementOnly, baseLocalPart, typeName); |
| throw TraverseSchema::InvalidComplexTypeInfo; //REVISIT - should we continue |
| } |
| } |
| |
| typeInfo->setContentType(SchemaElementDecl::Mixed_Complex); |
| } |
| else if (isMixed) { |
| |
| if (specNode != 0) { |
| typeInfo->setContentType(SchemaElementDecl::Mixed_Complex); |
| } |
| else { |
| // add #PCDATA leaf and set its minOccurs to 0 |
| ContentSpecNode* pcdataNode = new (fGrammarPoolMemoryManager) ContentSpecNode |
| ( |
| new (fGrammarPoolMemoryManager) QName |
| ( |
| XMLUni::fgZeroLenString |
| , XMLUni::fgZeroLenString |
| , XMLElementDecl::fgPCDataElemId |
| , fGrammarPoolMemoryManager |
| ) |
| , false |
| , fGrammarPoolMemoryManager |
| ); |
| |
| pcdataNode->setMinOccurs(0); |
| typeInfo->setContentSpec(pcdataNode); |
| typeInfo->setAdoptContentSpec(true); |
| typeInfo->setContentType(SchemaElementDecl::Mixed_Simple); |
| } |
| } |
| else if (specNodeWasNull && |
| (typeDerivedBy == SchemaSymbols::XSD_EXTENSION) && |
| baseTypeInfo) { |
| typeInfo->setBaseDatatypeValidator(baseTypeInfo->getBaseDatatypeValidator()); |
| typeInfo->setDatatypeValidator(baseTypeInfo->getDatatypeValidator()); |
| typeInfo->setContentType(baseTypeInfo->getContentType()); |
| } |
| else if (typeInfo->getContentSpec() == 0) { |
| if (!effectiveContent_hasChild) { |
| typeInfo->setContentType(SchemaElementDecl::Empty); |
| } |
| else { |
| typeInfo->setContentType(SchemaElementDecl::ElementOnlyEmpty); |
| } |
| } |
| else { |
| typeInfo->setContentType(SchemaElementDecl::Children); |
| } |
| |
| // ------------------------------------------------------------- |
| // Now, check attributes and handle |
| // ------------------------------------------------------------- |
| if (attrNode != 0) { |
| |
| if (!isAttrOrAttrGroup(attrNode)) { |
| reportSchemaError(attrNode, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType, |
| attrNode->getLocalName()); |
| } |
| else { |
| processAttributes(ctElem, attrNode, typeInfo, isBaseAnyType); |
| } |
| } |
| else if (baseTypeInfo != 0 || isBaseAnyType) { |
| processAttributes(ctElem, 0, typeInfo, isBaseAnyType); |
| } |
| } |
| |
| |
| void TraverseSchema::processBaseTypeInfo(const DOMElement* const elem, |
| const XMLCh* const baseName, |
| const XMLCh* const localPart, |
| const XMLCh* const uriStr, |
| ComplexTypeInfo* const typeInfo) { |
| |
| SchemaInfo* saveInfo = fSchemaInfo; |
| ComplexTypeInfo* baseComplexTypeInfo = 0; |
| DatatypeValidator* baseDTValidator = 0; |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| unsigned int saveScope = fCurrentScope; |
| |
| // check if the base type is from another schema |
| if (!XMLString::equals(uriStr, fTargetNSURIString)) { |
| |
| // check for datatype validator if it's schema for schema URI |
| if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { |
| |
| baseDTValidator = getDatatypeValidator(uriStr, localPart); |
| |
| if (!baseDTValidator) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BaseTypeNotFound, baseName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| else { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(uriStr); |
| |
| if (!isImportingNS(uriId)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| baseComplexTypeInfo = getTypeInfoFromNS(elem, uriStr, localPart); |
| |
| if (!baseComplexTypeInfo) { |
| |
| baseDTValidator = getDatatypeValidator(uriStr, localPart); |
| |
| if (!baseDTValidator) |
| { |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(fURIStringPool->addOrFind(uriStr)); |
| |
| if (!impInfo || impInfo->getProcessed()) |
| { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BaseTypeNotFound, baseName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| } |
| } |
| } |
| else { |
| |
| fBuffer.set(uriStr); |
| fBuffer.append(chComma); |
| fBuffer.append(localPart); |
| |
| // assume the base is a complexType and try to locate the base type first |
| const XMLCh* fullBaseName = fBuffer.getRawBuffer(); |
| baseComplexTypeInfo = fComplexTypeRegistry->get(fullBaseName); |
| |
| // Circular check |
| if (baseComplexTypeInfo) { |
| |
| if (fCurrentTypeNameStack->containsElement(fStringPool->addOrFind(fullBaseName), fCircularCheckIndex)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, fullBaseName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| else if (fCurrentTypeNameStack->containsElement(fStringPool->addOrFind(fullBaseName))) { |
| |
| typeInfo->setBaseComplexTypeInfo(baseComplexTypeInfo); |
| throw TraverseSchema::RecursingElement; |
| } |
| else if (baseComplexTypeInfo->getPreprocessed()) { |
| baseComplexTypeInfo = 0; |
| } |
| } |
| } |
| |
| // if not found, 2 possibilities: |
| // 1: ComplexType in question has not been compiled yet; |
| // 2: base is SimpleType; |
| if (!baseComplexTypeInfo && !baseDTValidator) { |
| |
| baseDTValidator = getDatatypeValidator(uriStr, localPart); |
| |
| if (baseDTValidator == 0) { |
| |
| DOMElement* baseTypeNode = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_ComplexType, |
| SchemaSymbols::fgELT_COMPLEXTYPE, localPart, &fSchemaInfo); |
| |
| if (baseTypeNode != 0) { |
| |
| int baseTypeSymbol = traverseComplexTypeDecl(baseTypeNode); |
| baseComplexTypeInfo = fComplexTypeRegistry->get(fStringPool->getValueForId(baseTypeSymbol)); |
| } |
| else { |
| |
| baseTypeNode = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_SimpleType, |
| SchemaSymbols::fgELT_SIMPLETYPE, localPart, &fSchemaInfo); |
| |
| if (baseTypeNode != 0) { |
| |
| baseDTValidator = traverseSimpleTypeDecl(baseTypeNode); |
| |
| if (baseDTValidator == 0) { |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TypeNotFound, uriStr, localPart, uriStr); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| else { |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BaseTypeNotFound, baseName); |
| throw TraverseSchema::InvalidComplexTypeInfo; |
| } |
| } |
| } |
| } // end if |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| |
| typeInfo->setBaseComplexTypeInfo(baseComplexTypeInfo); |
| typeInfo->setBaseDatatypeValidator(baseDTValidator); |
| } |
| |
| |
| ComplexTypeInfo* TraverseSchema::getTypeInfoFromNS(const DOMElement* const elem, |
| const XMLCh* const uriStr, |
| const XMLCh* const localPart) |
| { |
| |
| Grammar* grammar = fGrammarResolver->getGrammar(uriStr); |
| |
| if (grammar != 0 && grammar->getGrammarType() == Grammar::SchemaGrammarType) { |
| |
| fBuffer.set(uriStr); |
| fBuffer.append(chComma); |
| fBuffer.append(localPart); |
| |
| ComplexTypeInfo* typeInfo = |
| ((SchemaGrammar*)grammar)->getComplexTypeRegistry()->get(fBuffer.getRawBuffer()); |
| |
| return typeInfo; |
| } |
| else { |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr); |
| } |
| |
| return 0; |
| } |
| |
| |
| void TraverseSchema::processAttributes(const DOMElement* const elem, |
| const DOMElement* const attElem, |
| ComplexTypeInfo* const typeInfo, |
| const bool isBaseAnyType) { |
| |
| // If we do not have a complexTypeInfo, then what is the point of |
| // processing. |
| if (typeInfo == 0) { |
| return; |
| } |
| |
| ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo(); |
| if (baseTypeInfo && baseTypeInfo->getPreprocessed()) |
| throw TraverseSchema::RecursingElement; |
| |
| const DOMElement* child = attElem; |
| SchemaAttDef* attWildCard = 0; |
| Janitor<SchemaAttDef> janAttWildCard(0); |
| XercesAttGroupInfo* attGroupInfo = 0; |
| ValueVectorOf<XercesAttGroupInfo*> attGroupList(4, fGrammarPoolMemoryManager); |
| |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| |
| const XMLCh* childName = child->getLocalName(); |
| |
| if (XMLString::equals(childName, SchemaSymbols::fgELT_ATTRIBUTE)) { |
| if(attWildCard) |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::AnyAttributeBeforeAttribute); |
| |
| traverseAttributeDecl(child, typeInfo); |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_ATTRIBUTEGROUP)) { |
| if(attWildCard) |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::AnyAttributeBeforeAttribute); |
| |
| attGroupInfo = traverseAttributeGroupDecl(child, typeInfo); |
| if (attGroupInfo && !attGroupList.containsElement(attGroupInfo)) { |
| attGroupList.addElement(attGroupInfo); |
| } |
| } |
| else if (XMLString::equals(childName, SchemaSymbols::fgELT_ANYATTRIBUTE) ) { |
| if(attWildCard) |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAnyAttribute); |
| |
| attWildCard = traverseAnyAttribute(child); |
| janAttWildCard.reset(attWildCard); |
| } |
| else { |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType, childName); |
| } |
| } |
| |
| // ------------------------------------------------------------- |
| // Handle wild card/any attribute |
| // ------------------------------------------------------------- |
| int derivedBy = typeInfo->getDerivedBy(); |
| XMLSize_t attGroupListSize = attGroupList.size(); |
| |
| if (attGroupListSize) { |
| |
| SchemaAttDef* completeWildCard = 0; |
| Janitor<SchemaAttDef> janCompleteWildCard(0); |
| XMLAttDef::DefAttTypes defAttType = XMLAttDef::Default; |
| bool defAttTypeSet = false; |
| |
| for (XMLSize_t i=0; i < attGroupListSize; i++) { |
| |
| attGroupInfo = attGroupList.elementAt(i); |
| XMLSize_t anyAttCount = attGroupInfo->anyAttributeCount(); |
| |
| if (anyAttCount) { |
| |
| if (!defAttTypeSet) { |
| |
| defAttType = (attWildCard) ? attWildCard->getDefaultType() |
| : attGroupInfo->anyAttributeAt(0)->getDefaultType(); |
| defAttTypeSet = true; |
| } |
| |
| SchemaAttDef* attGroupWildCard = attGroupInfo->getCompleteWildCard(); |
| if (completeWildCard) { |
| attWildCardIntersection(completeWildCard, attGroupWildCard); |
| } |
| else { |
| completeWildCard = new (fGrammarPoolMemoryManager) SchemaAttDef(attGroupWildCard); |
| janCompleteWildCard.reset(completeWildCard); |
| } |
| } |
| |
| } |
| |
| if (completeWildCard) { |
| |
| if (attWildCard) { |
| attWildCardIntersection(attWildCard, completeWildCard); |
| } |
| else { |
| |
| attWildCard = completeWildCard; |
| janCompleteWildCard.orphan(); |
| janAttWildCard.reset(attWildCard); |
| } |
| |
| attWildCard->setDefaultType(defAttType); |
| } |
| } |
| |
| SchemaAttDef* baseAttWildCard = (baseTypeInfo) ? baseTypeInfo->getAttWildCard() : 0; |
| Janitor<SchemaAttDef> janBaseAttWildCard(0); |
| |
| if (derivedBy == SchemaSymbols::XSD_EXTENSION) { |
| |
| if (isBaseAnyType) { |
| |
| baseAttWildCard = new (fGrammarPoolMemoryManager) SchemaAttDef(XMLUni::fgZeroLenString, |
| XMLUni::fgZeroLenString, |
| fEmptyNamespaceURI, XMLAttDef::Any_Any, |
| XMLAttDef::ProcessContents_Lax, |
| fGrammarPoolMemoryManager); |
| janBaseAttWildCard.reset(baseAttWildCard); |
| } |
| |
| if (baseAttWildCard && attWildCard) { |
| |
| XMLAttDef::DefAttTypes saveDefType = attWildCard->getDefaultType(); |
| attWildCardUnion(attWildCard, baseAttWildCard); |
| attWildCard->setDefaultType(saveDefType); |
| } |
| } |
| |
| // ------------------------------------------------------------- |
| // insert wildcard attribute |
| // ------------------------------------------------------------- |
| if (attWildCard) { |
| |
| typeInfo->setAttWildCard(attWildCard); |
| janAttWildCard.orphan(); |
| |
| if (attWildCard->getType() == XMLAttDef::AttTypes_Unknown) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NotExpressibleWildCardIntersection); |
| } |
| } |
| else if (baseAttWildCard && derivedBy == SchemaSymbols::XSD_EXTENSION) { |
| |
| if (isBaseAnyType) { |
| |
| typeInfo->setAttWildCard(baseAttWildCard); |
| janBaseAttWildCard.orphan(); |
| } |
| else { |
| |
| SchemaAttDef* newWildCard = new (fGrammarPoolMemoryManager) SchemaAttDef(baseAttWildCard); |
| typeInfo->setAttWildCard(newWildCard); |
| } |
| } |
| |
| // ------------------------------------------------------------- |
| // Check attributes derivation OK |
| // ------------------------------------------------------------- |
| bool baseWithAttributes = (baseTypeInfo && baseTypeInfo->hasAttDefs()); |
| bool childWithAttributes = (typeInfo->hasAttDefs() || typeInfo->getAttWildCard()); |
| |
| if (derivedBy == SchemaSymbols::XSD_RESTRICTION && childWithAttributes) { |
| |
| if (!baseWithAttributes && !baseAttWildCard) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_1); |
| } |
| else { |
| checkAttDerivationOK(elem, baseTypeInfo, typeInfo); |
| } |
| } |
| |
| // ------------------------------------------------------------- |
| // merge in base type's attribute decls |
| // ------------------------------------------------------------- |
| if (baseTypeInfo && baseTypeInfo->hasAttDefs()) { |
| |
| SchemaAttDefList& baseAttList = (SchemaAttDefList&) |
| baseTypeInfo->getAttDefList(); |
| |
| for (XMLSize_t i=0; i<baseAttList.getAttDefCount(); i++) { |
| |
| SchemaAttDef& attDef = (SchemaAttDef&) baseAttList.getAttDef(i); |
| QName* attName = attDef.getAttName(); |
| const XMLCh* localPart = attName->getLocalPart(); |
| |
| // if found a duplicate, then skip the one from the base type |
| if (typeInfo->getAttDef(localPart, attName->getURI()) != 0) { |
| |
| if (derivedBy == SchemaSymbols::XSD_EXTENSION) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttInDerivation, localPart); |
| } |
| |
| continue; |
| } |
| |
| if (attDef.getDefaultType() != XMLAttDef::Prohibited) { |
| |
| SchemaAttDef* newAttDef = new (fGrammarPoolMemoryManager) SchemaAttDef(attName->getPrefix(), |
| attName->getLocalPart(), |
| attName->getURI(), |
| attDef.getValue(), |
| attDef.getType(), |
| attDef.getDefaultType(), |
| attDef.getEnumeration(), |
| fGrammarPoolMemoryManager); |
| |
| newAttDef->setDatatypeValidator(attDef.getDatatypeValidator()); |
| typeInfo->addAttDef(newAttDef); |
| |
| if (attDef.getBaseAttDecl()) |
| newAttDef->setBaseAttDecl(attDef.getBaseAttDecl()); |
| else |
| newAttDef->setBaseAttDecl(&attDef); |
| } |
| } |
| } |
| } |
| |
| |
| void TraverseSchema::defaultComplexTypeInfo(ComplexTypeInfo* const typeInfo) { |
| |
| if (typeInfo) { |
| |
| typeInfo->setDerivedBy(0); |
| typeInfo->setContentType(SchemaElementDecl::Any); |
| typeInfo->setDatatypeValidator(0); |
| typeInfo->setContentSpec(0); |
| typeInfo->setBaseComplexTypeInfo(0); |
| typeInfo->setBaseDatatypeValidator(0); |
| } |
| } |
| |
| |
| InputSource* TraverseSchema::resolveSchemaLocation(const XMLCh* const loc, |
| const XMLResourceIdentifier::ResourceIdentifierType resourceIdentitiferType, |
| const XMLCh* const nameSpace) { |
| |
| // ------------------------------------------------------------------ |
| // Create an input source |
| // ------------------------------------------------------------------ |
| InputSource* srcToFill = 0; |
| XMLCh* normalizedURI = 0; |
| if (loc) { |
| XMLString::removeChar(loc, 0xFFFF, fBuffer); |
| normalizedURI = fBuffer.getRawBuffer(); |
| } |
| |
| if (fEntityHandler){ |
| XMLResourceIdentifier resourceIdentifier(resourceIdentitiferType, |
| normalizedURI, nameSpace, 0, fSchemaInfo->getCurrentSchemaURL(), fLocator); |
| srcToFill = fEntityHandler->resolveEntity(&resourceIdentifier); |
| } |
| |
| // If they didn't create a source via the entity resolver, then we |
| // have to create one on our own if we have the schemaLocation (with |
| // the update resolveEntity accepting nameSpace, a schemImport could |
| // pass a null schemaLocation) |
| if (!srcToFill && loc) { |
| if (fScanner->getDisableDefaultEntityResolution()) |
| return 0; |
| |
| XMLURL urlTmp(fMemoryManager); |
| if ((!urlTmp.setURL(fSchemaInfo->getCurrentSchemaURL(), normalizedURI, urlTmp)) || |
| (urlTmp.isRelative())) |
| { |
| if (!fScanner->getStandardUriConformant()) |
| { |
| XMLCh* tempURI = XMLString::replicate(normalizedURI, fMemoryManager); |
| ArrayJanitor<XMLCh> tempURIName(tempURI, fMemoryManager); |
| XMLUri::normalizeURI(tempURI, fBuffer); |
| |
| srcToFill = new (fMemoryManager) LocalFileInputSource |
| ( fSchemaInfo->getCurrentSchemaURL() |
| , fBuffer.getRawBuffer() |
| , fMemoryManager |
| ); |
| } |
| else |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager); |
| } |
| else |
| { |
| if (fScanner->getStandardUriConformant() && urlTmp.hasInvalidChar()) |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager); |
| srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager); |
| } |
| } |
| |
| return srcToFill; |
| } |
| |
| |
| void TraverseSchema::restoreSchemaInfo(SchemaInfo* const toRestore, |
| SchemaInfo::ListType const aListType, |
| const unsigned int saveScope) { |
| |
| |
| if (aListType == SchemaInfo::IMPORT) { // restore grammar info |
| |
| int targetNSURI = toRestore->getTargetNSURI(); |
| |
| fSchemaGrammar->setScopeCount (fScopeCount); |
| fSchemaGrammar->setAnonTypeCount (fAnonXSTypeCount); |
| |
| fSchemaGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(toRestore->getTargetNSURIString()); |
| fScopeCount = fSchemaGrammar->getScopeCount (); |
| fAnonXSTypeCount = fSchemaGrammar->getAnonTypeCount (); |
| |
| fTargetNSURI = targetNSURI; |
| fCurrentScope = saveScope; |
| fDatatypeRegistry = fSchemaGrammar->getDatatypeRegistry(); |
| fTargetNSURIString = fSchemaGrammar->getTargetNamespace(); |
| fGroupRegistry = fSchemaGrammar->getGroupInfoRegistry(); |
| fAttGroupRegistry = fSchemaGrammar->getAttGroupInfoRegistry(); |
| fAttributeDeclRegistry = fSchemaGrammar->getAttributeDeclRegistry(); |
| fComplexTypeRegistry = fSchemaGrammar->getComplexTypeRegistry(); |
| fValidSubstitutionGroups = fSchemaGrammar->getValidSubstitutionGroups(); |
| |
| } |
| |
| fSchemaInfo = toRestore; |
| } |
| |
| |
| bool |
| TraverseSchema::emptiableParticle(const ContentSpecNode* const specNode) { |
| |
| if (!fFullConstraintChecking || !specNode || (specNode->getMinTotalRange() == 0)) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void TraverseSchema::checkFixedFacet(const DOMElement* const elem, |
| const XMLCh* const facetName, |
| const DatatypeValidator* const baseDV, |
| unsigned int& flags) |
| { |
| const XMLCh* fixedFacet = getElementAttValue(elem, SchemaSymbols::fgATT_FIXED); |
| |
| if ((fixedFacet && *fixedFacet) && |
| (XMLString::equals(fixedFacet, SchemaSymbols::fgATTVAL_TRUE) |
| || XMLString::equals(fixedFacet, fgValueOne))) { |
| |
| if (XMLString::equals(SchemaSymbols::fgELT_LENGTH, facetName)) { |
| flags |= DatatypeValidator::FACET_LENGTH; |
| } |
| if (XMLString::equals(SchemaSymbols::fgELT_MINLENGTH, facetName)) { |
| flags |= DatatypeValidator::FACET_MINLENGTH; |
| } |
| else if (XMLString::equals(SchemaSymbols::fgELT_MAXLENGTH, facetName)) { |
| flags |= DatatypeValidator::FACET_MAXLENGTH; |
| } |
| else if (XMLString::equals(SchemaSymbols::fgELT_MAXEXCLUSIVE, facetName)) { |
| flags |= DatatypeValidator::FACET_MAXEXCLUSIVE; |
| } |
| else if (XMLString::equals(SchemaSymbols::fgELT_MAXINCLUSIVE, facetName)) { |
| flags |= DatatypeValidator::FACET_MAXINCLUSIVE; |
| } |
| else if (XMLString::equals(SchemaSymbols::fgELT_MINEXCLUSIVE, facetName)) { |
| flags |= DatatypeValidator::FACET_MINEXCLUSIVE; |
| } |
| else if (XMLString::equals(SchemaSymbols::fgELT_MININCLUSIVE, facetName)) { |
| flags |= DatatypeValidator::FACET_MININCLUSIVE; |
| } |
| else if (XMLString::equals(SchemaSymbols::fgELT_TOTALDIGITS, facetName)) { |
| flags |= DatatypeValidator::FACET_TOTALDIGITS; |
| } |
| else if (XMLString::equals(SchemaSymbols::fgELT_FRACTIONDIGITS, facetName)) { |
| flags |= DatatypeValidator::FACET_FRACTIONDIGITS; |
| } |
| else if ((XMLString::equals(SchemaSymbols::fgELT_WHITESPACE, facetName)) && |
| baseDV->getType() == DatatypeValidator::String) { |
| flags |= DatatypeValidator::FACET_WHITESPACE; |
| } |
| } |
| } |
| |
| void |
| TraverseSchema::buildValidSubstitutionListB(const DOMElement* const elem, |
| SchemaElementDecl* const elemDecl, |
| SchemaElementDecl* const subsElemDecl) { |
| |
| SchemaElementDecl* chainElemDecl = subsElemDecl->getSubstitutionGroupElem(); |
| |
| while (chainElemDecl) { |
| |
| int chainElemURI = chainElemDecl->getURI(); |
| XMLCh* chainElemName = chainElemDecl->getBaseName(); |
| ValueVectorOf<SchemaElementDecl*>* validSubsElements = |
| fValidSubstitutionGroups->get(chainElemName, chainElemURI); |
| |
| if (!validSubsElements) { |
| |
| if (fTargetNSURI == chainElemURI) { |
| break; // an error must have occured |
| } |
| |
| SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(fURIStringPool->getValueForId(chainElemURI)); |
| |
| if (!aGrammar) |
| break; |
| |
| validSubsElements = aGrammar->getValidSubstitutionGroups()->get(chainElemName, chainElemURI); |
| |
| if (!validSubsElements) { |
| break; |
| } |
| |
| validSubsElements = new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(*validSubsElements); |
| fValidSubstitutionGroups->put((void*) chainElemName, chainElemURI, validSubsElements); |
| } |
| |
| if (validSubsElements->containsElement(elemDecl) || |
| !isSubstitutionGroupValid(elem, chainElemDecl, elemDecl->getComplexTypeInfo(), |
| elemDecl->getDatatypeValidator(), 0, false)) { |
| break; |
| } |
| |
| validSubsElements->addElement(elemDecl); |
| |
| // update related subs. info in case of circular import |
| BaseRefVectorEnumerator<SchemaInfo> importingEnum = fSchemaInfo->getImportingListEnumerator(); |
| |
| while (importingEnum.hasMoreElements()) { |
| |
| const SchemaInfo& curRef = importingEnum.nextElement(); |
| SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(curRef.getTargetNSURIString()); |
| ValueVectorOf<SchemaElementDecl*>* subsElemList = |
| aGrammar->getValidSubstitutionGroups()->get(chainElemName, chainElemURI); |
| |
| if (subsElemList && !subsElemList->containsElement(elemDecl)) { |
| subsElemList->addElement(elemDecl); |
| } |
| } |
| |
| chainElemDecl = chainElemDecl->getSubstitutionGroupElem(); |
| } |
| } |
| |
| void |
| TraverseSchema::buildValidSubstitutionListF(const DOMElement* const elem, |
| SchemaElementDecl* const elemDecl, |
| SchemaElementDecl* const subsElemDecl) { |
| |
| int elemURI = elemDecl->getURI(); |
| XMLCh* elemName = elemDecl->getBaseName(); |
| ValueVectorOf<SchemaElementDecl*>* validSubsElements =fValidSubstitutionGroups->get(elemName, elemURI); |
| |
| if (validSubsElements) { |
| |
| int subsElemURI = subsElemDecl->getURI(); |
| XMLCh* subsElemName = subsElemDecl->getBaseName(); |
| ValueVectorOf<SchemaElementDecl*>* validSubs = fValidSubstitutionGroups->get(subsElemName, subsElemURI); |
| |
| if (!validSubs) { |
| |
| if (fTargetNSURI == subsElemURI) { |
| return; // an error must have occured |
| } |
| |
| SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(fURIStringPool->getValueForId(subsElemURI)); |
| |
| if (!aGrammar) |
| return; |
| |
| validSubs = aGrammar->getValidSubstitutionGroups()->get(subsElemName, subsElemURI); |
| |
| if (!validSubs) { |
| return; |
| } |
| |
| validSubs = new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(*validSubs); |
| fValidSubstitutionGroups->put((void*) subsElemName, subsElemURI, validSubs); |
| } |
| |
| XMLSize_t elemSize = validSubsElements->size(); |
| for (XMLSize_t i=0; i<elemSize; i++) { |
| |
| SchemaElementDecl* chainElem = validSubsElements->elementAt(i); |
| |
| if (validSubs->containsElement(chainElem)) { |
| continue; |
| } |
| |
| if (isSubstitutionGroupValid(elem, subsElemDecl, chainElem->getComplexTypeInfo(), |
| chainElem->getDatatypeValidator(), 0, false)) { |
| validSubs->addElement(chainElem); |
| buildValidSubstitutionListB(elem, chainElem, subsElemDecl); |
| } |
| } |
| } |
| } |
| |
| void TraverseSchema::checkEnumerationRequiredNotation(const DOMElement* const elem, |
| const XMLCh* const name, |
| const XMLCh* const type) { |
| |
| const XMLCh* localPart = getLocalPart(type); |
| |
| if (XMLString::equals(localPart, XMLUni::fgNotationString)) { |
| const XMLCh* prefix = getPrefix(type); |
| const XMLCh* typeURI = resolvePrefixToURI(elem, prefix); |
| |
| if (XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNotationType, name); |
| } |
| } |
| } |
| |
| XercesGroupInfo* TraverseSchema::processGroupRef(const DOMElement* const elem, |
| const XMLCh* const refName) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| DOMElement* content = checkContent(elem, XUtil::getFirstChildElement(elem), true); |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| if (content != 0) { |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::NoContentForRef, SchemaSymbols::fgELT_GROUP); |
| } |
| |
| const XMLCh* prefix = getPrefix(refName); |
| const XMLCh* localPart = getLocalPart(refName); |
| const XMLCh* uriStr = resolvePrefixToURI(elem, prefix); |
| |
| fBuffer.set(uriStr); |
| fBuffer.append(chComma); |
| fBuffer.append(localPart); |
| |
| unsigned int nameIndex = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| |
| if (fCurrentGroupStack->containsElement(nameIndex)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, localPart); |
| return 0; |
| } |
| |
| XercesGroupInfo* groupInfo = 0; |
| SchemaInfo* saveInfo = fSchemaInfo; |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| unsigned int saveScope = fCurrentScope; |
| |
| //if from another target namespace |
| if (!XMLString::equals(uriStr, fTargetNSURIString)) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(uriStr); |
| |
| if (!isImportingNS(uriId)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr); |
| return 0; |
| } |
| |
| Grammar* aGrammar = fGrammarResolver->getGrammar(uriStr); |
| |
| if (!aGrammar || aGrammar->getGrammarType() != Grammar::SchemaGrammarType) { |
| |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::GrammarNotFound, uriStr); |
| return 0; |
| } |
| |
| groupInfo = ((SchemaGrammar*)aGrammar)->getGroupInfoRegistry()->get(fStringPool->getValueForId(nameIndex)); |
| |
| if (!groupInfo) { |
| |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(fURIStringPool->addOrFind(uriStr)); |
| |
| if (!impInfo || impInfo->getProcessed()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound, |
| SchemaSymbols::fgELT_GROUP, uriStr, localPart); |
| return 0; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| } |
| else { |
| groupInfo = fGroupRegistry->get(fStringPool->getValueForId(nameIndex)); |
| } |
| |
| if (!groupInfo) { |
| |
| DOMElement* groupElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_Group, |
| SchemaSymbols::fgELT_GROUP, localPart, &fSchemaInfo); |
| |
| if (groupElem != 0) { |
| |
| groupInfo = traverseGroupDecl(groupElem); |
| |
| // restore schema information |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| |
| if (groupInfo && (fCurrentGroupInfo || infoType == SchemaInfo::IMPORT)) { |
| copyGroupElements(elem, groupInfo, fCurrentGroupInfo, |
| (infoType == SchemaInfo::IMPORT) ? fCurrentComplexType : 0); |
| } |
| |
| return groupInfo; |
| } |
| else { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound, |
| SchemaSymbols::fgELT_GROUP, uriStr, localPart); |
| } |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| } |
| else { |
| copyGroupElements(elem, groupInfo, fCurrentGroupInfo, fCurrentComplexType); |
| } |
| |
| return groupInfo; |
| } |
| |
| |
| XercesAttGroupInfo* |
| TraverseSchema::processAttributeGroupRef(const DOMElement* const elem, |
| const XMLCh* const refName, |
| ComplexTypeInfo* const typeInfo) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| if (checkContent(elem, XUtil::getFirstChildElement(elem), true) != 0) { |
| reportSchemaError(elem ,XMLUni::fgValidityDomain, XMLValid::NoContentForRef, SchemaSymbols::fgELT_ATTRIBUTEGROUP); |
| } |
| |
| Janitor<XSAnnotation> janAnnot(fAnnotation); |
| const XMLCh* prefix = getPrefix(refName); |
| const XMLCh* localPart = getLocalPart(refName); |
| const XMLCh* uriStr = resolvePrefixToURI(elem, prefix); |
| XercesAttGroupInfo* attGroupInfo = 0; |
| SchemaInfo* saveInfo = fSchemaInfo; |
| SchemaInfo::ListType infoType = SchemaInfo::INCLUDE; |
| unsigned int saveScope = fCurrentScope; |
| |
| if (!XMLString::equals(uriStr, fTargetNSURIString)) { |
| |
| // Make sure that we have an explicit import statement. |
| // Clause 4 of Schema Representation Constraint: |
| // http://www.w3.org/TR/xmlschema-1/#src-resolve |
| unsigned int uriId = fURIStringPool->addOrFind(uriStr); |
| |
| if (!isImportingNS(uriId)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidNSReference, uriStr); |
| return 0; |
| } |
| |
| attGroupInfo = traverseAttributeGroupDeclNS(elem, uriStr, localPart); |
| |
| if (!attGroupInfo) { |
| SchemaInfo* impInfo = fSchemaInfo->getImportInfo(fURIStringPool->addOrFind(uriStr)); |
| |
| if (!impInfo || impInfo->getProcessed()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound, |
| SchemaSymbols::fgELT_ATTRIBUTEGROUP, uriStr, localPart); |
| return 0; |
| } |
| |
| infoType = SchemaInfo::IMPORT; |
| restoreSchemaInfo(impInfo, infoType); |
| } |
| } |
| else { |
| |
| attGroupInfo = fAttGroupRegistry->get(localPart); |
| } |
| |
| if (!attGroupInfo) { |
| |
| // traverse top level attributeGroup - if found |
| DOMElement* attGroupElem = fSchemaInfo->getTopLevelComponent(SchemaInfo::C_AttributeGroup, |
| SchemaSymbols::fgELT_ATTRIBUTEGROUP, localPart, &fSchemaInfo); |
| |
| if (attGroupElem != 0) { |
| |
| // circular attribute check |
| if (fDeclStack->containsElement(attGroupElem)) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoCircularDefinition, refName); |
| return 0; |
| } |
| |
| attGroupInfo = traverseAttributeGroupDecl(attGroupElem, typeInfo, true); |
| |
| if (attGroupInfo && fCurrentAttGroupInfo) { |
| copyAttGroupAttributes(elem, attGroupInfo, fCurrentAttGroupInfo, 0); |
| } |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType, saveScope); |
| } |
| |
| return attGroupInfo; |
| } |
| else { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNotFound, |
| SchemaSymbols::fgELT_ATTRIBUTEGROUP, uriStr, localPart); |
| } |
| } |
| |
| if (attGroupInfo) { |
| copyAttGroupAttributes(elem, attGroupInfo, fCurrentAttGroupInfo, typeInfo); |
| } |
| |
| // restore schema information, if necessary |
| if (saveInfo != fSchemaInfo) { |
| restoreSchemaInfo(saveInfo, infoType); |
| } |
| |
| return attGroupInfo; |
| } |
| |
| void TraverseSchema::processElements(const DOMElement* const elem, |
| ComplexTypeInfo* const baseTypeInfo, |
| ComplexTypeInfo* const newTypeInfo) { |
| |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| XMLSize_t elemCount = baseTypeInfo->elementCount(); |
| |
| if (elemCount) { |
| |
| int newTypeScope = newTypeInfo->getScopeDefined(); |
| int schemaURI = fURIStringPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA); |
| |
| for (XMLSize_t i=0; i < elemCount; i++) { |
| |
| SchemaGrammar* aGrammar = fSchemaGrammar; |
| SchemaElementDecl* elemDecl = baseTypeInfo->elementAt(i); |
| int elemURI = elemDecl->getURI(); |
| unsigned int elemScope = elemDecl->getEnclosingScope(); |
| |
| if (elemScope != Grammar::TOP_LEVEL_SCOPE) { |
| |
| if (elemURI != fTargetNSURI && elemURI != schemaURI && elemURI != fEmptyNamespaceURI) { |
| Grammar* aGrammar = fGrammarResolver->getGrammar(fURIStringPool->getValueForId(elemURI)); |
| |
| if (!aGrammar || aGrammar->getGrammarType() != Grammar::SchemaGrammarType) { |
| continue; // REVISIT - error message |
| } |
| } |
| |
| const XMLCh* localPart = elemDecl->getBaseName(); |
| const SchemaElementDecl* other = (SchemaElementDecl*) |
| aGrammar->getElemDecl(elemURI, localPart, 0, newTypeScope); |
| |
| if (other) { |
| |
| if (elemDecl->getComplexTypeInfo() != other->getComplexTypeInfo() |
| || elemDecl->getDatatypeValidator() != other->getDatatypeValidator()) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateElementDeclaration, localPart); |
| } |
| |
| continue; |
| } |
| elemDecl->setEnclosingScope(newTypeScope); |
| ((SchemaGrammar*) aGrammar)->putGroupElemDecl(elemDecl); |
| elemDecl->setEnclosingScope(elemScope); |
| } |
| |
| newTypeInfo->addElement(elemDecl); |
| } |
| } |
| } |
| |
| void TraverseSchema::processElements(const DOMElement* const elem, |
| XercesGroupInfo* const fromGroup, |
| ComplexTypeInfo* const typeInfo) |
| { |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| XMLSize_t elemCount = fromGroup->elementCount(); |
| int newScope = typeInfo->getScopeDefined(); |
| |
| for (XMLSize_t i = 0; i < elemCount; i++) { |
| |
| SchemaElementDecl* elemDecl = fromGroup->elementAt(i); |
| unsigned int elemScope = elemDecl->getEnclosingScope(); |
| |
| if (elemScope != Grammar::TOP_LEVEL_SCOPE) |
| { |
| int elemURI = elemDecl->getURI(); |
| const XMLCh* localPart = elemDecl->getBaseName(); |
| const SchemaElementDecl* other = (SchemaElementDecl*) |
| fSchemaGrammar->getElemDecl(elemURI, localPart, 0, newScope); |
| |
| if (other) |
| { |
| if (elemDecl->getComplexTypeInfo() != other->getComplexTypeInfo() |
| || elemDecl->getDatatypeValidator() != other->getDatatypeValidator()) |
| { |
| reportSchemaError( |
| elem, XMLUni::fgXMLErrDomain |
| , XMLErrs::DuplicateElementDeclaration, localPart); |
| } |
| |
| continue; |
| } |
| |
| elemDecl->setEnclosingScope(newScope); |
| fSchemaGrammar->putGroupElemDecl(elemDecl); |
| elemDecl->setEnclosingScope(elemScope); |
| typeInfo->addElement(elemDecl); |
| } |
| } |
| } |
| |
| |
| void TraverseSchema::copyGroupElements(const DOMElement* const elem, |
| XercesGroupInfo* const fromGroup, |
| XercesGroupInfo* const toGroup, |
| ComplexTypeInfo* const typeInfo) { |
| |
| XMLSize_t elemCount = fromGroup->elementCount(); |
| int newScope = (typeInfo) ? typeInfo->getScopeDefined() : 0; |
| |
| if (typeInfo) |
| fromGroup->setCheckElementConsistency(false); |
| |
| for (XMLSize_t i = 0; i < elemCount; i++) { |
| |
| SchemaElementDecl* elemDecl = fromGroup->elementAt(i); |
| |
| if (typeInfo) { |
| |
| unsigned int elemScope = elemDecl->getEnclosingScope(); |
| |
| if (elemScope != Grammar::TOP_LEVEL_SCOPE) { |
| |
| int elemURI = elemDecl->getURI(); |
| const XMLCh* localPart = elemDecl->getBaseName(); |
| const SchemaElementDecl* other = (SchemaElementDecl*) |
| fSchemaGrammar->getElemDecl(elemURI, localPart, 0, newScope); |
| |
| if (other) { |
| |
| if (elemDecl->getComplexTypeInfo() != other->getComplexTypeInfo() |
| || elemDecl->getDatatypeValidator() != other->getDatatypeValidator()) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateElementDeclaration, localPart); |
| } |
| |
| continue; |
| } |
| |
| elemDecl->setEnclosingScope(newScope); |
| fSchemaGrammar->putGroupElemDecl(elemDecl); |
| elemDecl->setEnclosingScope(elemScope); |
| } |
| |
| typeInfo->addElement(elemDecl); |
| } |
| |
| if (toGroup) { |
| toGroup->addElement(elemDecl); |
| } |
| } |
| } |
| |
| void TraverseSchema::copyAttGroupAttributes(const DOMElement* const elem, |
| XercesAttGroupInfo* const fromAttGroup, |
| XercesAttGroupInfo* const toAttGroup, |
| ComplexTypeInfo* const typeInfo) { |
| |
| XMLSize_t attCount = fromAttGroup->attributeCount(); |
| |
| for (XMLSize_t i=0; i < attCount; i++) { |
| |
| SchemaAttDef* attDef = fromAttGroup->attributeAt(i); |
| QName* attName = attDef->getAttName(); |
| const XMLCh* localPart = attName->getLocalPart(); |
| DatatypeValidator* attDV = attDef->getDatatypeValidator(); |
| |
| if (typeInfo) { |
| |
| if (typeInfo->getAttDef(localPart, attName->getURI())) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, localPart); |
| continue; |
| } |
| |
| if (attDV && attDV->getType() == DatatypeValidator::ID) { |
| |
| if (typeInfo->containsAttWithTypeId()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect5, localPart); |
| continue; |
| } |
| |
| typeInfo->setAttWithTypeId(true); |
| } |
| |
| SchemaAttDef* clonedAttDef = new (fGrammarPoolMemoryManager) SchemaAttDef(attDef); |
| typeInfo->addAttDef(clonedAttDef); |
| |
| if (!clonedAttDef->getBaseAttDecl()) |
| clonedAttDef->setBaseAttDecl(attDef); |
| |
| if (toAttGroup) { |
| toAttGroup->addAttDef(attDef, true); |
| } |
| } |
| else { |
| |
| if (toAttGroup->containsAttribute(localPart, attName->getURI())) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, localPart); |
| continue; |
| } |
| |
| if (attDV && attDV->getType() == DatatypeValidator::ID) { |
| |
| if (toAttGroup->containsTypeWithId()) { |
| |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttGrpPropCorrect3, localPart); |
| continue; |
| } |
| |
| toAttGroup->setTypeWithId(true); |
| } |
| |
| toAttGroup->addAttDef(attDef, true); |
| } |
| } |
| |
| if (toAttGroup) { |
| XMLSize_t anyAttCount = fromAttGroup->anyAttributeCount(); |
| |
| for (XMLSize_t j=0; j < anyAttCount; j++) { |
| toAttGroup->addAnyAttDef(fromAttGroup->anyAttributeAt(j), true); |
| } |
| } |
| } |
| |
| void |
| TraverseSchema::attWildCardIntersection(SchemaAttDef* const resultWildCard, |
| const SchemaAttDef* const compareWildCard) { |
| |
| XMLAttDef::AttTypes typeR = resultWildCard->getType(); |
| XMLAttDef::AttTypes typeC = compareWildCard->getType(); |
| |
| //If either O1 or O2 is any, then the other must be the value. |
| if (typeC == XMLAttDef::Any_Any || |
| typeR == XMLAttDef::AttTypes_Unknown) { |
| return; |
| } |
| |
| if (typeR == XMLAttDef::Any_Any || |
| typeC == XMLAttDef::AttTypes_Unknown) { |
| |
| resultWildCard->resetNamespaceList(); |
| copyWildCardData(compareWildCard, resultWildCard); |
| return; |
| } |
| |
| // If either O1 or O2 is a pair of not and a namespace name and the other |
| // is a set, then that set, minus the negated namespace name if it was in |
| // is the value |
| if ((typeC == XMLAttDef::Any_Other && typeR == XMLAttDef::Any_List) || |
| (typeR == XMLAttDef::Any_Other && typeC == XMLAttDef::Any_List)) { |
| |
| unsigned int compareURI = 0; |
| ValueVectorOf<unsigned int>* nameURIList = 0; |
| |
| if (typeC == XMLAttDef::Any_List) { |
| nameURIList = compareWildCard->getNamespaceList(); |
| compareURI = resultWildCard->getAttName()->getURI(); |
| } |
| else { |
| nameURIList = resultWildCard->getNamespaceList(); |
| compareURI = compareWildCard->getAttName()->getURI(); |
| } |
| |
| XMLSize_t listSize = (nameURIList) ? nameURIList->size() : 0; |
| |
| if (listSize) { |
| |
| bool found = false; |
| ValueVectorOf<unsigned int> tmpURIList(listSize, fGrammarPoolMemoryManager); |
| |
| for (XMLSize_t i=0; i < listSize; i++) { |
| |
| unsigned int nameURI = nameURIList->elementAt(i); |
| |
| if (nameURI != compareURI && |
| nameURI != (unsigned int) fEmptyNamespaceURI) { |
| tmpURIList.addElement(nameURI); |
| } |
| else { |
| found = true; |
| } |
| } |
| |
| if (found || typeC == XMLAttDef::Any_List) { |
| resultWildCard->setNamespaceList(&tmpURIList); |
| } |
| } |
| |
| if (typeC == XMLAttDef::Any_List) { |
| copyWildCardData(compareWildCard, resultWildCard); |
| } |
| |
| return; |
| } |
| |
| // If both O1 and O2 are sets, then the intersection of those sets must be |
| // the value. |
| if (typeR == XMLAttDef::Any_List && typeC == XMLAttDef::Any_List) { |
| |
| ValueVectorOf<unsigned int>* uriListR = resultWildCard->getNamespaceList(); |
| ValueVectorOf<unsigned int>* uriListC = compareWildCard->getNamespaceList(); |
| XMLSize_t listSize = (uriListC) ? uriListC->size() : 0; |
| |
| if (listSize) { |
| |
| ValueVectorOf<unsigned int> tmpURIList(listSize, fGrammarPoolMemoryManager); |
| |
| for (XMLSize_t i=0; i < listSize; i++) { |
| |
| unsigned int uriName = uriListC->elementAt(i); |
| |
| if (uriListR && uriListR->containsElement(uriName)) { |
| tmpURIList.addElement(uriName); |
| } |
| } |
| |
| resultWildCard->setNamespaceList(&tmpURIList); |
| } |
| else { |
| resultWildCard->resetNamespaceList(); |
| } |
| |
| return; |
| } |
| |
| // If the two are negations of different namespace names, then: |
| // if one is a negation of absent, then result is negation of namespace |
| // else intersection is not expressible. |
| if (typeR == XMLAttDef::Any_Other && typeC == XMLAttDef::Any_Other) { |
| |
| QName* qnameR = resultWildCard->getAttName(); |
| |
| if (qnameR->getURI() != compareWildCard->getAttName()->getURI()) { |
| |
| if (qnameR->getURI() == (unsigned int)fEmptyNamespaceURI) { |
| qnameR->setURI(compareWildCard->getAttName()->getURI()); |
| } |
| else if (compareWildCard->getAttName()->getURI() != (unsigned int)fEmptyNamespaceURI) { |
| |
| qnameR->setURI(fEmptyNamespaceURI); |
| resultWildCard->setType(XMLAttDef::AttTypes_Unknown); |
| } |
| } |
| } |
| } |
| |
| |
| void |
| TraverseSchema::attWildCardUnion(SchemaAttDef* const resultWildCard, |
| const SchemaAttDef* const compareWildCard) { |
| |
| XMLAttDef::AttTypes typeR = resultWildCard->getType(); |
| XMLAttDef::AttTypes typeC = compareWildCard->getType(); |
| |
| //If either O1 or O2 is any, then the other must be the value. |
| if (typeR == XMLAttDef::Any_Any || |
| typeR == XMLAttDef::AttTypes_Unknown) { |
| return; |
| } |
| |
| if (typeC == XMLAttDef::Any_Any || |
| typeC == XMLAttDef::AttTypes_Unknown) { |
| |
| resultWildCard->resetNamespaceList(); |
| copyWildCardData(compareWildCard, resultWildCard); |
| return; |
| } |
| |
| // If both O1 and O2 are sets, then the union of those sets must be |
| // the value. |
| if (typeR == XMLAttDef::Any_List && typeC == XMLAttDef::Any_List) { |
| |
| ValueVectorOf<unsigned int>* uriListR = resultWildCard->getNamespaceList(); |
| ValueVectorOf<unsigned int>* uriListC = compareWildCard->getNamespaceList(); |
| XMLSize_t listSizeC = (uriListC) ? uriListC->size() : 0; |
| |
| if (listSizeC) { |
| |
| if (!uriListR || !uriListR->size()) { |
| |
| resultWildCard->setNamespaceList(uriListC); |
| return; |
| } |
| |
| ValueVectorOf<unsigned int> tmpURIList(*uriListR); |
| |
| for (XMLSize_t i = 0; i < listSizeC; i++) { |
| |
| unsigned int uriName = uriListC->elementAt(i); |
| |
| if (!uriListR->containsElement(uriName)) { |
| tmpURIList.addElement(uriName); |
| } |
| } |
| |
| resultWildCard->setNamespaceList(&tmpURIList); |
| } |
| |
| return; |
| } |
| |
| // If the two are negations of different namespace names, then not and |
| // absent must be the value |
| if (typeR == XMLAttDef::Any_Other && typeC == XMLAttDef::Any_Other) { |
| |
| QName* qnameR = resultWildCard->getAttName(); |
| |
| if (qnameR->getURI() != compareWildCard->getAttName()->getURI()) { |
| |
| qnameR->setURI(fEmptyNamespaceURI); |
| resultWildCard->setType(XMLAttDef::Any_Other); |
| } |
| } |
| |
| // 5. If either O1 or O2 is a pair of not and a namespace name and the |
| // other is a set, then: |
| // 1. If the set includes both the negated namespace name and absent |
| // then any must be the value. |
| // 2. If the set includes the negated namespace name but not absent, |
| // then a pair of not and absent must be the value. |
| // 3. If the set includes absent but not the negated namespace name, |
| // then the union is not expressible. |
| // 4. If the set does not include either the negated namespace or |
| // absent, then whichever of O1 or O2 is a pair of not and a |
| // namespace name. |
| // |
| // 6. If either O1 or O2 is a pair of not and absent and the other is a |
| // set, then: |
| // 1. If the set includes absent then any must be the value. |
| // 2. If the set does not include absent, then a pair of not and |
| // absent. |
| if ((typeC == XMLAttDef::Any_Other && typeR == XMLAttDef::Any_List) || |
| (typeR == XMLAttDef::Any_Other && typeC == XMLAttDef::Any_List)) { |
| |
| ValueVectorOf<unsigned int>* nameURIList = 0; |
| QName* attNameR = resultWildCard->getAttName(); |
| unsigned int compareURI = 0; |
| |
| if (typeC == XMLAttDef::Any_List) { |
| nameURIList = compareWildCard->getNamespaceList(); |
| compareURI = attNameR->getURI(); |
| } |
| else { |
| nameURIList = resultWildCard->getNamespaceList(); |
| compareURI = compareWildCard->getAttName()->getURI(); |
| } |
| |
| // 6. not and absent |
| if (compareURI == (unsigned int) fEmptyNamespaceURI) { |
| |
| if (nameURIList) { |
| |
| // 6.1 result is any |
| if (nameURIList->containsElement(compareURI)) { |
| |
| resultWildCard->setType(XMLAttDef::Any_Any); |
| attNameR->setURI(fEmptyNamespaceURI); |
| } |
| // 6.2 result is not and absent |
| else if (typeR == XMLAttDef::Any_List){ |
| |
| resultWildCard->setType(XMLAttDef::Any_Other); |
| attNameR->setURI(fEmptyNamespaceURI); |
| } |
| } |
| // 6.2 result is not and absent |
| else if (typeR == XMLAttDef::Any_List) { |
| |
| resultWildCard->setType(XMLAttDef::Any_Other); |
| attNameR->setURI(fEmptyNamespaceURI); |
| } |
| } |
| // 5. not and namespace |
| else { |
| |
| // 5.3 result is not expressible |
| if (!nameURIList) { |
| resultWildCard->setType(XMLAttDef::AttTypes_Unknown); |
| attNameR->setURI(fEmptyNamespaceURI); |
| } |
| else { |
| bool containsAbsent = |
| nameURIList->containsElement(fEmptyNamespaceURI); |
| bool containsNamespace = |
| nameURIList->containsElement(compareURI); |
| |
| // 5.1 result is any |
| if (containsAbsent && containsNamespace) { |
| |
| resultWildCard->setType(XMLAttDef::Any_Any); |
| attNameR->setURI(fEmptyNamespaceURI); |
| } |
| // 5.2 result is not and absent |
| else if (containsNamespace) { |
| |
| resultWildCard->setType(XMLAttDef::Any_Other); |
| attNameR->setURI(fEmptyNamespaceURI); |
| } |
| // 5.3 result is not expressible |
| else if (containsAbsent) { |
| |
| resultWildCard->setType(XMLAttDef::AttTypes_Unknown); |
| attNameR->setURI(fEmptyNamespaceURI); |
| } |
| // 5.4. whichever is not and namespace |
| else if (typeR == XMLAttDef::Any_List) { |
| |
| resultWildCard->setType(XMLAttDef::Any_Other); |
| attNameR->setURI(compareURI); |
| } |
| } |
| } |
| |
| resultWildCard->resetNamespaceList(); |
| } |
| } |
| |
| |
| void TraverseSchema::checkAttDerivationOK(const DOMElement* const elem, |
| const ComplexTypeInfo* const baseTypeInfo, |
| const ComplexTypeInfo* const childTypeInfo) { |
| |
| SchemaAttDefList& childAttList = (SchemaAttDefList&) childTypeInfo->getAttDefList(); |
| const SchemaAttDef* baseAttWildCard = baseTypeInfo->getAttWildCard(); |
| |
| for (XMLSize_t i=0; i<childAttList.getAttDefCount(); i++) { |
| |
| SchemaAttDef& childAttDef = (SchemaAttDef&) childAttList.getAttDef(i); |
| QName* childAttName = childAttDef.getAttName(); |
| const XMLCh* childLocalPart = childAttName->getLocalPart(); |
| const SchemaAttDef* baseAttDef = baseTypeInfo->getAttDef(childLocalPart, childAttName->getURI()); |
| |
| if (baseAttDef) { |
| |
| XMLAttDef::DefAttTypes baseAttDefType = baseAttDef->getDefaultType(); |
| XMLAttDef::DefAttTypes childAttDefType = childAttDef.getDefaultType(); |
| |
| // Constraint 2.1.1 & 3 + check for prohibited base attribute |
| if (baseAttDefType == XMLAttDef::Prohibited |
| && childAttDefType != XMLAttDef::Prohibited) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_8, childLocalPart); |
| } |
| |
| if ((baseAttDefType & XMLAttDef::Required) |
| && !(childAttDefType & XMLAttDef::Required)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_2, childLocalPart); |
| } |
| |
| // if the attribute in the derived type is prohibited, and it didn't try to override a required attribute, |
| // it's ok and shouldn't be tested for data type or fixed value |
| if (childAttDefType == XMLAttDef::Prohibited) |
| continue; |
| |
| // Constraint 2.1.2 |
| DatatypeValidator* baseDV = baseAttDef->getDatatypeValidator(); |
| DatatypeValidator* childDV = childAttDef.getDatatypeValidator(); |
| if (!baseDV || !baseDV->isSubstitutableBy(childDV)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_3, childLocalPart); |
| } |
| |
| // Constraint 2.1.3 |
| if ((baseAttDefType & XMLAttDef::Fixed) && |
| (!(childAttDefType & XMLAttDef::Fixed) || |
| !XMLString::equals(baseAttDef->getValue(), childAttDef.getValue()))) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_4, childLocalPart); |
| } |
| } |
| // Constraint 2.2 |
| else if (!baseAttWildCard || |
| !wildcardAllowsNamespace(baseAttWildCard, childAttName->getURI())) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_5, childLocalPart); |
| } |
| } |
| |
| // Constraint 4 |
| const SchemaAttDef* childAttWildCard = childTypeInfo->getAttWildCard(); |
| |
| if (childAttWildCard) { |
| |
| if (!baseAttWildCard) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_6); |
| } |
| else if (!isWildCardSubset(baseAttWildCard, childAttWildCard)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_7); |
| } |
| else if (childAttWildCard->getDefaultType() < baseAttWildCard->getDefaultType()) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_9); |
| } |
| } |
| } |
| |
| void TraverseSchema::checkAttDerivationOK(const DOMElement* const elem, |
| const XercesAttGroupInfo* const baseAttGrpInfo, |
| const XercesAttGroupInfo* const childAttGrpInfo) { |
| |
| XMLSize_t baseAttCount = baseAttGrpInfo->attributeCount(); |
| XMLSize_t baseAnyAttCount = baseAttGrpInfo->anyAttributeCount(); |
| XMLSize_t childAttCount = childAttGrpInfo->attributeCount(); |
| XMLSize_t childAnyAttCount = childAttGrpInfo->anyAttributeCount(); |
| |
| if ((childAttCount || childAnyAttCount) && (!baseAttCount && !baseAnyAttCount)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_1); |
| } |
| |
| const SchemaAttDef* baseAttWildCard = (baseAnyAttCount) ? baseAttGrpInfo->anyAttributeAt(0) : 0; |
| |
| for (XMLSize_t i=0; i<childAttCount; i++) { |
| |
| const SchemaAttDef* childAttDef = childAttGrpInfo->attributeAt(i); |
| QName* childAttName = childAttDef->getAttName(); |
| const XMLCh* childLocalPart = childAttName->getLocalPart(); |
| const SchemaAttDef* baseAttDef = baseAttGrpInfo->getAttDef(childLocalPart, childAttName->getURI()); |
| |
| if (baseAttDef) { |
| |
| XMLAttDef::DefAttTypes baseAttDefType = baseAttDef->getDefaultType(); |
| XMLAttDef::DefAttTypes childAttDefType = childAttDef->getDefaultType(); |
| |
| // Constraint 2.1.1 & 3 + check for prohibited base attribute |
| if (baseAttDefType == XMLAttDef::Prohibited |
| && childAttDefType != XMLAttDef::Prohibited) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_8, childLocalPart); |
| } |
| |
| if ((baseAttDefType & XMLAttDef::Required) |
| && !(childAttDefType & XMLAttDef::Required)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_2, childLocalPart); |
| } |
| |
| // if the attribute in the derived type is prohibited, and it didn't try to override a required attribute, |
| // it's ok and shouldn't be tested for data type or fixed value |
| if (childAttDefType == XMLAttDef::Prohibited) |
| continue; |
| |
| // Constraint 2.1.2 |
| DatatypeValidator* baseDV = baseAttDef->getDatatypeValidator(); |
| DatatypeValidator* childDV = childAttDef->getDatatypeValidator(); |
| if (!baseDV || !baseDV->isSubstitutableBy(childDV)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_3, childLocalPart); |
| } |
| |
| // Constraint 2.1.3 |
| if ((baseAttDefType & XMLAttDef::Fixed) && |
| (!(childAttDefType & XMLAttDef::Fixed) || |
| !XMLString::equals(baseAttDef->getValue(), childAttDef->getValue()))) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_4, childLocalPart); |
| } |
| } |
| // Constraint 2.2 |
| else if (!baseAttWildCard || |
| !wildcardAllowsNamespace(baseAttWildCard, childAttName->getURI())) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_5, childLocalPart); |
| } |
| } |
| |
| // Constraint 4 |
| const SchemaAttDef* childAttWildCard = (childAnyAttCount) ? childAttGrpInfo->anyAttributeAt(0) : 0; |
| |
| if (childAttWildCard) { |
| |
| if (!baseAttWildCard) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_6); |
| } |
| else if (!isWildCardSubset(baseAttWildCard, childAttWildCard)) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_7); |
| } |
| else if (childAttWildCard->getDefaultType() < baseAttWildCard->getDefaultType()) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::BadAttDerivation_9); |
| } |
| } |
| } |
| |
| bool TraverseSchema::wildcardAllowsNamespace(const SchemaAttDef* const wildCard, |
| const unsigned int nameURI) { |
| |
| XMLAttDef::AttTypes wildCardType = wildCard->getType(); |
| |
| // The constraint must be any |
| if (wildCardType == XMLAttDef::Any_Any) { |
| return true; |
| } |
| |
| // All of the following must be true: |
| // 2.1 The constraint is a pair of not and a namespace name or absent |
| // 2.2 The value must not be identical to the namespace test. |
| // 2.3 The value must not be absent. |
| if (wildCardType == XMLAttDef::Any_Other && |
| ((int) nameURI) != fEmptyNamespaceURI && |
| wildCard->getAttName()->getURI() != nameURI) { |
| return true; |
| } |
| |
| // The constraint is a set, and the value is identical to one of the |
| // members of the set |
| if (wildCardType == XMLAttDef::Any_List) { |
| |
| ValueVectorOf<unsigned int>* nameURIList = wildCard->getNamespaceList(); |
| |
| if (nameURIList->containsElement(nameURI)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool TraverseSchema::isWildCardSubset(const SchemaAttDef* const baseAttWildCard, |
| const SchemaAttDef* const childAttWildCard) { |
| |
| XMLAttDef::AttTypes baseWildCardType = baseAttWildCard->getType(); |
| XMLAttDef::AttTypes childWildCardType = childAttWildCard->getType(); |
| |
| if (baseWildCardType == XMLAttDef::AttTypes_Unknown || |
| childWildCardType == XMLAttDef::AttTypes_Unknown) { |
| return false; |
| } |
| |
| // 1 super must be any. |
| if (baseWildCardType == XMLAttDef::Any_Any) { |
| return true; |
| } |
| |
| // 2 All of the following must be true: |
| // 2.1 sub must be a pair of not and a namespace name or absent. |
| // 2.2 super must be a pair of not and the same value. |
| if (childWildCardType == XMLAttDef::Any_Other && baseWildCardType == XMLAttDef::Any_Other && |
| childAttWildCard->getAttName()->getURI() == baseAttWildCard->getAttName()->getURI()) { |
| return true; |
| } |
| |
| // 3 All of the following must be true: |
| // 3.1 sub must be a set whose members are either namespace names or absent. |
| // 3.2 One of the following must be true: |
| // 3.2.1 super must be the same set or a superset thereof. |
| // 3.2.2 super must be a pair of not and a namespace name or absent and |
| // that value must not be in sub's set. |
| if (childWildCardType == XMLAttDef::Any_List) { |
| |
| ValueVectorOf<unsigned int>* childURIList = childAttWildCard->getNamespaceList(); |
| |
| if (baseWildCardType == XMLAttDef::Any_List) { |
| |
| ValueVectorOf<unsigned int>* baseURIList = baseAttWildCard->getNamespaceList(); |
| XMLSize_t childListSize = (childURIList) ? childURIList->size() : 0; |
| |
| for (XMLSize_t i=0; i<childListSize; i++) { |
| if (!baseURIList->containsElement(childURIList->elementAt(i))) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| else if (baseWildCardType == XMLAttDef::Any_Other) { |
| if (!childURIList->containsElement(baseAttWildCard->getAttName()->getURI())) { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| bool TraverseSchema::openRedefinedSchema(const DOMElement* const redefineElem) { |
| |
| if (fPreprocessedNodes->containsKey(redefineElem)) { |
| |
| restoreSchemaInfo(fPreprocessedNodes->get(redefineElem)); |
| return true; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Get 'schemaLocation' attribute |
| // ------------------------------------------------------------------ |
| const XMLCh* schemaLocation = getElementAttValue(redefineElem, SchemaSymbols::fgATT_SCHEMALOCATION, DatatypeValidator::AnyURI); |
| |
| if (!schemaLocation || !*schemaLocation) { |
| reportSchemaError(redefineElem, XMLUni::fgXMLErrDomain, XMLErrs::DeclarationNoSchemaLocation, SchemaSymbols::fgELT_REDEFINE); |
| return false; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Resolve schema location |
| // ------------------------------------------------------------------ |
| fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0, |
| ((XSDElementNSImpl*) redefineElem)->getLineNo(), |
| ((XSDElementNSImpl*) redefineElem)->getColumnNo()); |
| InputSource* srcToFill = resolveSchemaLocation(schemaLocation, |
| XMLResourceIdentifier::SchemaRedefine); |
| Janitor<InputSource> janSrc(srcToFill); |
| |
| // Nothing to do |
| if (!srcToFill) { |
| return false; |
| } |
| |
| const XMLCh* includeURL = srcToFill->getSystemId(); |
| |
| if (XMLString::equals(includeURL, fSchemaInfo->getCurrentSchemaURL())) { |
| return false; |
| } |
| |
| SchemaInfo* redefSchemaInfo = fCachedSchemaInfoList->get(includeURL, fTargetNSURI); |
| |
| if (!redefSchemaInfo && fSchemaInfoList != fCachedSchemaInfoList) |
| redefSchemaInfo = fSchemaInfoList->get(includeURL, fTargetNSURI); |
| |
| if (redefSchemaInfo) { |
| |
| reportSchemaError(redefineElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidRedefine, includeURL); |
| return false; |
| } |
| |
| // ------------------------------------------------------------------ |
| // Parse input source |
| // ------------------------------------------------------------------ |
| if (!fParser) |
| fParser = new (fGrammarPoolMemoryManager) XSDDOMParser(0,fGrammarPoolMemoryManager, 0); |
| |
| fParser->setValidationScheme(XercesDOMParser::Val_Never); |
| fParser->setDoNamespaces(true); |
| fParser->setUserEntityHandler(fEntityHandler); |
| fParser->setUserErrorReporter(fErrorReporter); |
| |
| // Should just issue warning if the schema is not found |
| bool flag = srcToFill->getIssueFatalErrorIfNotFound(); |
| srcToFill->setIssueFatalErrorIfNotFound(false); |
| |
| fParser->parse(*srcToFill) ; |
| |
| // Reset the InputSource |
| srcToFill->setIssueFatalErrorIfNotFound(flag); |
| |
| if (fParser->getSawFatal() && fScanner->getExitOnFirstFatal()) |
| reportSchemaError(redefineElem, XMLUni::fgXMLErrDomain, XMLErrs::SchemaScanFatalError); |
| |
| // ------------------------------------------------------------------ |
| // Get root element |
| // ------------------------------------------------------------------ |
| DOMDocument* document = fParser->getDocument(); |
| |
| if (!document) { |
| return false; |
| } |
| else { |
| |
| DOMElement* root = document->getDocumentElement(); |
| |
| if (root == 0) { |
| return false; |
| } |
| |
| const XMLCh* targetNSURIString = root->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE); |
| |
| // check to see if targetNameSpace is right |
| if (*targetNSURIString |
| && !XMLString::equals(targetNSURIString,fTargetNSURIString)){ |
| reportSchemaError(root, XMLUni::fgXMLErrDomain, XMLErrs::RedefineNamespaceDifference, |
| schemaLocation, targetNSURIString); |
| return false; |
| } |
| |
| // if targetNamespace is empty, change it to redefin'g schema |
| // targetNamespace |
| if (!*targetNSURIString && root->getAttributeNode(XMLUni::fgXMLNSString) == 0 |
| && fTargetNSURI != fEmptyNamespaceURI) { |
| root->setAttribute(XMLUni::fgXMLNSString, fTargetNSURIString); |
| } |
| |
| // -------------------------------------------------------- |
| // Update schema information with redefined schema |
| // -------------------------------------------------------- |
| redefSchemaInfo = fSchemaInfo; |
| Janitor<SchemaInfo> newSchemaInfo(new (fMemoryManager) SchemaInfo(0, 0, 0, fTargetNSURI, |
| 0, |
| includeURL, |
| fTargetNSURIString, root, |
| fScanner, |
| fGrammarPoolMemoryManager)); |
| fSchemaInfo = newSchemaInfo.get(); |
| |
| fSchemaInfo->getNamespaceScope()->reset(fEmptyNamespaceURI); |
| // Add mapping for the xml prefix |
| fSchemaInfo->getNamespaceScope()->addPrefix(XMLUni::fgXMLString, fURIStringPool->addOrFind(XMLUni::fgXMLURIName)); |
| |
| traverseSchemaHeader(root); |
| fSchemaInfoList->put((void*) fSchemaInfo->getCurrentSchemaURL(), fSchemaInfo->getTargetNSURI(), fSchemaInfo); |
| newSchemaInfo.release(); |
| redefSchemaInfo->addSchemaInfo(fSchemaInfo, SchemaInfo::INCLUDE); |
| fPreprocessedNodes->put((void*) redefineElem, fSchemaInfo); |
| } |
| |
| return true; |
| } |
| |
| void TraverseSchema::renameRedefinedComponents(const DOMElement* const redefineElem, |
| SchemaInfo* const redefiningSchemaInfo, |
| SchemaInfo* const redefinedSchemaInfo) { |
| |
| DOMElement* child = XUtil::getFirstChildElement(redefineElem); |
| |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| |
| const XMLCh* childName = child->getLocalName(); |
| |
| if (XMLString::equals(childName, SchemaSymbols::fgELT_ANNOTATION)) { |
| continue; |
| } |
| |
| // if component already redefined skip |
| const XMLCh* typeName = getElementAttValue(child, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(typeName); |
| |
| if (fRedefineComponents->containsKey(childName, fStringPool->addOrFind(fBuffer.getRawBuffer()))) { |
| continue; |
| } |
| |
| // Rename |
| const XMLCh* tmpChildName = fStringPool->getValueForId(fStringPool->addOrFind(childName)); |
| |
| if (validateRedefineNameChange(child, tmpChildName, typeName, 1, redefiningSchemaInfo)) { |
| fixRedefinedSchema(child, redefinedSchemaInfo, tmpChildName, typeName, 1); |
| } |
| else { |
| redefiningSchemaInfo->addFailedRedefine(child); |
| } |
| } |
| } |
| |
| bool TraverseSchema::validateRedefineNameChange(const DOMElement* const redefineChildElem, |
| const XMLCh* const redefineChildComponentName, |
| const XMLCh* const redefineChildTypeName, |
| const int redefineNameCounter, |
| SchemaInfo* const redefiningSchemaInfo) { |
| |
| const XMLCh* baseTypeName = 0; |
| unsigned int typeNameId = fStringPool->addOrFind(redefineChildTypeName); |
| |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(redefineChildTypeName); |
| |
| int fullTypeNameId = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| const XMLCh* typeNameStr = fStringPool->getValueForId(fullTypeNameId); |
| |
| restoreSchemaInfo(redefiningSchemaInfo); |
| |
| if (XMLString::equals(redefineChildComponentName,SchemaSymbols::fgELT_SIMPLETYPE)) { |
| |
| if (fDatatypeRegistry->getDatatypeValidator(typeNameStr)) { |
| return false; |
| } |
| |
| DOMElement* grandKid = XUtil::getFirstChildElement(redefineChildElem); |
| |
| if (grandKid && XMLString::equals(grandKid->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) { |
| grandKid = XUtil::getNextSiblingElement(grandKid); |
| } |
| |
| if (grandKid == 0) { |
| |
| reportSchemaError(redefineChildElem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidSimpleType); |
| return false; |
| } |
| else if(!XMLString::equals(grandKid->getLocalName(), SchemaSymbols::fgELT_RESTRICTION)) { |
| |
| reportSchemaError(grandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidSimpleType); |
| return false; |
| } |
| |
| baseTypeName = getElementAttValue(grandKid, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName); |
| const XMLCh* prefix = getPrefix(baseTypeName); |
| const XMLCh* localPart = getLocalPart(baseTypeName); |
| const XMLCh* uriStr = resolvePrefixToURI(grandKid, prefix); |
| |
| if (fTargetNSURI != (int) fURIStringPool->addOrFind(uriStr) |
| || fStringPool->addOrFind(localPart) != typeNameId) { |
| reportSchemaError(grandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidSimpleTypeBase); |
| return false; |
| } |
| |
| // now we have to do the renaming... |
| getRedefineNewTypeName(baseTypeName, redefineNameCounter, fBuffer); |
| grandKid->setAttribute(SchemaSymbols::fgATT_BASE, fBuffer.getRawBuffer()); |
| fRedefineComponents->put((void*) SchemaSymbols::fgELT_SIMPLETYPE, |
| fullTypeNameId, 0); |
| } |
| else if (XMLString::equals(redefineChildComponentName,SchemaSymbols::fgELT_COMPLEXTYPE)) { |
| |
| if (fComplexTypeRegistry->containsKey(typeNameStr)) { |
| return false; |
| } |
| |
| DOMElement* grandKid = XUtil::getFirstChildElement(redefineChildElem); |
| |
| if (grandKid && XMLString::equals(grandKid->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) { |
| grandKid = XUtil::getNextSiblingElement(grandKid); |
| } |
| |
| if (grandKid == 0) { |
| reportSchemaError(redefineChildElem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidComplexType); |
| return false; |
| } else { |
| |
| // have to go one more level down; let another pass worry whether complexType is valid. |
| DOMElement* greatGrandKid = XUtil::getFirstChildElement(grandKid); |
| |
| if (greatGrandKid != 0 && |
| XMLString::equals(greatGrandKid->getLocalName(), SchemaSymbols::fgELT_ANNOTATION)) { |
| greatGrandKid = XUtil::getNextSiblingElement(greatGrandKid); |
| } |
| |
| if (greatGrandKid == 0) { |
| |
| reportSchemaError(grandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidComplexType); |
| return false; |
| } else { |
| |
| const XMLCh* greatGrandKidName = greatGrandKid->getLocalName(); |
| |
| if (!XMLString::equals(greatGrandKidName, SchemaSymbols::fgELT_RESTRICTION) |
| && !XMLString::equals(greatGrandKidName, SchemaSymbols::fgELT_EXTENSION)) { |
| |
| reportSchemaError(greatGrandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidComplexType); |
| return false; |
| } |
| |
| baseTypeName = getElementAttValue(greatGrandKid, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName); |
| const XMLCh* prefix = getPrefix(baseTypeName); |
| const XMLCh* localPart = getLocalPart(baseTypeName); |
| const XMLCh* uriStr = resolvePrefixToURI(greatGrandKid, prefix); |
| |
| if (fTargetNSURI != (int) fURIStringPool->addOrFind(uriStr) |
| || fStringPool->addOrFind(localPart) != typeNameId) { |
| reportSchemaError(greatGrandKid, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidComplexTypeBase); |
| return false; |
| } |
| |
| // now we have to do the renaming... |
| getRedefineNewTypeName(baseTypeName, redefineNameCounter, fBuffer); |
| greatGrandKid->setAttribute(SchemaSymbols::fgATT_BASE, fBuffer.getRawBuffer()); |
| fRedefineComponents->put((void*) SchemaSymbols::fgELT_COMPLEXTYPE, |
| fullTypeNameId, 0); |
| } |
| } |
| } |
| else if (XMLString::equals(redefineChildComponentName, SchemaSymbols::fgELT_GROUP)) { |
| |
| if (fGroupRegistry->containsKey(typeNameStr)) { |
| return false; |
| } |
| |
| int groupRefCount = changeRedefineGroup(redefineChildElem, redefineChildComponentName, |
| redefineChildTypeName, redefineNameCounter); |
| |
| if (groupRefCount > 1) { |
| |
| reportSchemaError(redefineChildElem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_GroupRefCount); |
| return false; |
| } |
| else if (groupRefCount == 0) { |
| // put a dummy value, default is null. |
| // when processing groups, we will check that table, if a value |
| // is found, we need to do a particle derivation check. |
| fRedefineComponents->put((void*) SchemaSymbols::fgELT_GROUP, |
| fullTypeNameId, fSchemaInfo->getCurrentSchemaURL()); |
| } |
| else { |
| fRedefineComponents->put((void*) SchemaSymbols::fgELT_GROUP, fullTypeNameId, 0); |
| } |
| } |
| else if (XMLString::equals(redefineChildComponentName, SchemaSymbols::fgELT_ATTRIBUTEGROUP)) { |
| |
| if (fAttGroupRegistry->containsKey(redefineChildTypeName)) { |
| return false; |
| } |
| |
| int attGroupRefCount = changeRedefineGroup(redefineChildElem, redefineChildComponentName, |
| redefineChildTypeName, redefineNameCounter); |
| |
| if (attGroupRefCount > 1) { |
| |
| reportSchemaError(redefineChildElem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_AttGroupRefCount); |
| return false; |
| } |
| else if (attGroupRefCount == 0) { |
| // put a dummy value, default is null. |
| // when processing attributeGroups, we will check that table, if |
| // a value is found, we need to check for attribute derivation ok |
| // (by restriction) |
| fRedefineComponents->put((void*) SchemaSymbols::fgELT_ATTRIBUTEGROUP, |
| fullTypeNameId, fSchemaInfo->getCurrentSchemaURL()); |
| } |
| else { |
| fRedefineComponents->put((void*) SchemaSymbols::fgELT_ATTRIBUTEGROUP, fullTypeNameId, 0); |
| } |
| } |
| else { |
| reportSchemaError |
| ( |
| redefineChildElem |
| , XMLUni::fgXMLErrDomain |
| , XMLErrs::Redefine_InvalidChild |
| , redefineChildComponentName |
| ); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| int TraverseSchema::changeRedefineGroup(const DOMElement* const redefineChildElem, |
| const XMLCh* const redefineChildComponentName, |
| const XMLCh* const redefineChildTypeName, |
| const int redefineNameCounter) { |
| int result = 0; |
| DOMElement* child = XUtil::getFirstChildElement(redefineChildElem); |
| |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| |
| const XMLCh* name = child->getLocalName(); |
| |
| if (XMLString::equals(name, SchemaSymbols::fgELT_ANNOTATION)) { |
| continue; |
| } |
| |
| if (!XMLString::equals(name, redefineChildComponentName)) { |
| result += changeRedefineGroup(child, redefineChildComponentName, redefineChildTypeName, redefineNameCounter); |
| } else { |
| const XMLCh* refName = getElementAttValue(child, SchemaSymbols::fgATT_REF, DatatypeValidator::QName); |
| |
| if (refName && *refName) { |
| |
| const XMLCh* prefix = getPrefix(refName); |
| const XMLCh* localPart = getLocalPart(refName); |
| const XMLCh* uriStr = resolvePrefixToURI(child, prefix); |
| |
| if (fTargetNSURI == (int) fURIStringPool->addOrFind(uriStr) |
| && fStringPool->addOrFind(localPart) == fStringPool->addOrFind(redefineChildTypeName)) { |
| |
| // now we have to do the renaming... |
| getRedefineNewTypeName(refName, redefineNameCounter, fBuffer); |
| child->setAttribute(SchemaSymbols::fgATT_REF, fBuffer.getRawBuffer()); |
| result++; |
| |
| if(XMLString::equals(redefineChildComponentName, SchemaSymbols::fgELT_GROUP)) { |
| |
| const XMLCh* minOccurs = getElementAttValue(child, SchemaSymbols::fgATT_MINOCCURS, DatatypeValidator::Decimal); |
| const XMLCh* maxOccurs = getElementAttValue(child, SchemaSymbols::fgATT_MAXOCCURS, DatatypeValidator::Decimal); |
| |
| if (((maxOccurs && *maxOccurs) && !XMLString::equals(maxOccurs, fgValueOne)) |
| || ((minOccurs && *minOccurs) && !XMLString::equals(minOccurs, fgValueOne))) { |
| reportSchemaError(child, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_InvalidGroupMinMax, redefineChildTypeName); |
| } |
| } |
| } |
| } // if ref was null some other stage of processing will flag the error |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| void TraverseSchema::fixRedefinedSchema(const DOMElement* const elem, |
| SchemaInfo* const redefinedSchemaInfo, |
| const XMLCh* const redefineChildComponentName, |
| const XMLCh* const redefineChildTypeName, |
| const int redefineNameCounter) { |
| |
| bool foundIt = false; |
| DOMElement* child = XUtil::getFirstChildElement(redefinedSchemaInfo->getRoot()); |
| |
| restoreSchemaInfo(redefinedSchemaInfo); |
| |
| for (; child != 0; child = XUtil::getNextSiblingElement(child)) { |
| |
| const XMLCh* name = child->getLocalName(); |
| |
| if (XMLString::equals(name, redefineChildComponentName)) { |
| |
| const XMLCh* infoItemName = getElementAttValue(child, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| |
| if(!XMLString::equals(infoItemName, redefineChildTypeName)) { |
| continue; |
| } |
| else { // found it! |
| |
| // now we have to do the renaming... |
| foundIt = true; |
| getRedefineNewTypeName(infoItemName, redefineNameCounter, fBuffer); |
| child->setAttribute(SchemaSymbols::fgATT_NAME, fBuffer.getRawBuffer()); |
| break; |
| } |
| } |
| else if (XMLString::equals(name, SchemaSymbols::fgELT_REDEFINE)) { // need to search the redefine decl... |
| |
| for (DOMElement* redefChild = XUtil::getFirstChildElement(child); |
| redefChild != 0; |
| redefChild = XUtil::getNextSiblingElement(redefChild)) { |
| |
| const XMLCh* redefName = redefChild->getLocalName(); |
| |
| if (XMLString::equals(redefName, redefineChildComponentName)) { |
| |
| const XMLCh* infoItemName = getElementAttValue(redefChild, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName); |
| |
| if(!XMLString::equals(infoItemName, redefineChildTypeName)) { |
| continue; |
| } |
| else { // found it! |
| |
| if (!openRedefinedSchema(child)) { |
| |
| redefinedSchemaInfo->addFailedRedefine(child); |
| return; |
| } |
| |
| foundIt = true; |
| |
| SchemaInfo* reRedefinedSchemaInfo = fSchemaInfo; |
| |
| if (validateRedefineNameChange(redefChild, redefineChildComponentName, redefineChildTypeName, redefineNameCounter + 1, redefinedSchemaInfo)) { |
| |
| fixRedefinedSchema(redefChild, reRedefinedSchemaInfo, redefineChildComponentName, redefineChildTypeName, redefineNameCounter + 1); |
| |
| // now we have to do the renaming... |
| getRedefineNewTypeName(infoItemName, redefineNameCounter, fBuffer); |
| const XMLCh* newInfoItemName = fStringPool->getValueForId(fStringPool->addOrFind(fBuffer.getRawBuffer())); |
| redefChild->setAttribute(SchemaSymbols::fgATT_NAME, newInfoItemName); |
| |
| // and we now know we will traverse this, so set fRedefineComponents appropriately... |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(newInfoItemName); |
| } |
| else { |
| |
| fixRedefinedSchema(redefChild, reRedefinedSchemaInfo, redefineChildComponentName, redefineChildTypeName, redefineNameCounter); |
| redefinedSchemaInfo->addFailedRedefine(redefChild); |
| |
| // and we now know we will traverse this, so set fRedefineComponents appropriately... |
| fBuffer.set(fTargetNSURIString); |
| fBuffer.append(chComma); |
| fBuffer.append(infoItemName); |
| } |
| |
| unsigned int infoItemNameId = fStringPool->addOrFind(fBuffer.getRawBuffer()); |
| |
| if (!fRedefineComponents->containsKey(redefineChildComponentName, infoItemNameId)) { |
| fRedefineComponents->put((void*) redefineChildComponentName, infoItemNameId, 0); |
| } |
| |
| break; |
| } |
| } |
| } //for |
| |
| if (foundIt) { |
| break; |
| } |
| } |
| } //for |
| |
| if(!foundIt) { |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::Redefine_DeclarationNotFound, redefineChildTypeName); |
| } |
| } |
| |
| bool TraverseSchema::isSubstitutionGroupCircular(SchemaElementDecl* const elemDecl, |
| SchemaElementDecl* const subsElemDecl) |
| { |
| |
| if (elemDecl == subsElemDecl) |
| return true; |
| |
| SchemaElementDecl* tmpElemDecl = subsElemDecl->getSubstitutionGroupElem(); |
| |
| while (tmpElemDecl) |
| { |
| if (tmpElemDecl == elemDecl) |
| return true; |
| |
| tmpElemDecl = tmpElemDecl->getSubstitutionGroupElem(); |
| } |
| |
| return false; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // TraverseSchema: Error reporting methods |
| // --------------------------------------------------------------------------- |
| void TraverseSchema::reportSchemaError(const XSDLocator* const aLocator, |
| const XMLCh* const msgDomain, |
| const int errorCode) { |
| |
| fXSDErrorReporter.emitError(errorCode, msgDomain, aLocator); |
| } |
| |
| void TraverseSchema::reportSchemaError(const XSDLocator* const aLocator, |
| const XMLCh* const msgDomain, |
| const int errorCode, |
| const XMLCh* const text1, |
| const XMLCh* const text2, |
| const XMLCh* const text3, |
| const XMLCh* const text4) { |
| |
| fXSDErrorReporter.emitError(errorCode, msgDomain, aLocator, text1, text2, text3, text4, fMemoryManager); |
| } |
| |
| void TraverseSchema::reportSchemaError(const DOMElement* const elem, |
| const XMLCh* const msgDomain, |
| const int errorCode) { |
| |
| fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0, |
| ((XSDElementNSImpl*) elem)->getLineNo(), |
| ((XSDElementNSImpl*) elem)->getColumnNo()); |
| |
| fXSDErrorReporter.emitError(errorCode, msgDomain, fLocator); |
| } |
| |
| void TraverseSchema::reportSchemaError(const DOMElement* const elem, |
| const XMLCh* const msgDomain, |
| const int errorCode, |
| const XMLCh* const text1, |
| const XMLCh* const text2, |
| const XMLCh* const text3, |
| const XMLCh* const text4) { |
| |
| fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0, |
| ((XSDElementNSImpl*) elem)->getLineNo(), |
| ((XSDElementNSImpl*) elem)->getColumnNo()); |
| |
| fXSDErrorReporter.emitError(errorCode, msgDomain, fLocator, text1, text2, text3, text4, fMemoryManager); |
| } |
| |
| void TraverseSchema::reportSchemaError(const DOMElement* const elem, |
| const XMLException& except) |
| { |
| fLocator->setValues(fSchemaInfo->getCurrentSchemaURL(), 0, |
| ((XSDElementNSImpl*) elem)->getLineNo(), |
| ((XSDElementNSImpl*) elem)->getColumnNo()); |
| |
| fXSDErrorReporter.emitError(except, fLocator); |
| } |
| // --------------------------------------------------------------------------- |
| // TraverseSchema: Init/CleanUp methods |
| // --------------------------------------------------------------------------- |
| void TraverseSchema::init() { |
| |
| fXSDErrorReporter.setErrorReporter(fErrorReporter); |
| fXSDErrorReporter.setExitOnFirstFatal(fScanner->getExitOnFirstFatal()); |
| |
| fFullConstraintChecking = fScanner->getValidationSchemaFullChecking(); |
| |
| fDatatypeRegistry = fSchemaGrammar->getDatatypeRegistry(); |
| fStringPool = fGrammarResolver->getStringPool(); |
| fEmptyNamespaceURI = fScanner->getEmptyNamespaceId(); |
| fCurrentTypeNameStack = new (fMemoryManager) ValueVectorOf<unsigned int>(8, fMemoryManager); |
| fCurrentGroupStack = new (fMemoryManager) ValueVectorOf<unsigned int>(8, fMemoryManager); |
| |
| fGlobalDeclarations = (ValueVectorOf<unsigned int>**) fMemoryManager->allocate |
| ( |
| ENUM_ELT_SIZE * sizeof(ValueVectorOf<unsigned int>*) |
| );//new ValueVectorOf<unsigned int>*[ENUM_ELT_SIZE]; |
| memset(fGlobalDeclarations, 0, ENUM_ELT_SIZE * sizeof(ValueVectorOf<unsigned int>*)); |
| for(unsigned int i=0; i < ENUM_ELT_SIZE; i++) |
| fGlobalDeclarations[i] = new (fMemoryManager) ValueVectorOf<unsigned int>(8, fMemoryManager); |
| |
| fNonXSAttList = new (fMemoryManager) ValueVectorOf<DOMNode*>(4, fMemoryManager); |
| fNotationRegistry = new (fMemoryManager) RefHash2KeysTableOf<XMLCh>(13, (bool) false, fMemoryManager); |
| fPreprocessedNodes = new (fMemoryManager) RefHashTableOf<SchemaInfo, PtrHasher> |
| ( |
| 29 |
| , false |
| , fMemoryManager |
| ); |
| fLocator = new (fMemoryManager) XSDLocator(); |
| fDeclStack = new (fMemoryManager) ValueVectorOf<const DOMElement*>(16, fMemoryManager); |
| } |
| |
| void TraverseSchema::cleanUp() { |
| |
| delete fCurrentTypeNameStack; |
| delete fCurrentGroupStack; |
| |
| if (fGlobalDeclarations) |
| { |
| for(unsigned int i=0; i < ENUM_ELT_SIZE; i++) |
| delete fGlobalDeclarations[i]; |
| fMemoryManager->deallocate(fGlobalDeclarations);//delete [] fGlobalDeclarations; |
| } |
| |
| delete fNonXSAttList; |
| delete fImportedNSList; |
| delete fNotationRegistry; |
| delete fRedefineComponents; |
| delete fIdentityConstraintNames; |
| delete fDeclStack; |
| delete fIC_ElementsNS; |
| delete fIC_NodeListNS; |
| delete fPreprocessedNodes; |
| delete fLocator; |
| delete fParser; |
| } |
| |
| void TraverseSchema::processElemDeclAttrs(const DOMElement* const elem, |
| SchemaElementDecl* const elemDecl, |
| const XMLCh*& valueConstraint, |
| bool isTopLevel) |
| { |
| int elementMiscFlags = 0; |
| const XMLCh* fixedVal = getElementAttValue(elem, SchemaSymbols::fgATT_FIXED); |
| const XMLCh* nillable = getElementAttValue(elem, SchemaSymbols::fgATT_NILLABLE, DatatypeValidator::Boolean); |
| |
| // check constraint value |
| valueConstraint = getElementAttValue(elem, SchemaSymbols::fgATT_DEFAULT); |
| if (fixedVal) |
| { |
| elementMiscFlags |= SchemaSymbols::XSD_FIXED; |
| |
| // if both default and fixed, emit an error |
| if (valueConstraint) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::ElementWithFixedAndDefault, getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName)); |
| |
| // set constraint value to the fixed one |
| valueConstraint = fixedVal; |
| } |
| |
| // check nillable |
| if (nillable && *nillable) { |
| |
| if (XMLString::equals(nillable, SchemaSymbols::fgATTVAL_TRUE) |
| || XMLString::equals(nillable, fgValueOne)) { |
| elementMiscFlags |= SchemaSymbols::XSD_NILLABLE; |
| } |
| } |
| |
| if (isTopLevel) |
| { |
| const XMLCh* bAbstract = getElementAttValue(elem, SchemaSymbols::fgATT_ABSTRACT, DatatypeValidator::Boolean); |
| if (bAbstract && *bAbstract) { |
| |
| if (XMLString::equals(bAbstract, SchemaSymbols::fgATTVAL_TRUE) |
| || XMLString::equals(bAbstract, fgValueOne)) { |
| elementMiscFlags |= SchemaSymbols::XSD_ABSTRACT; |
| } |
| } |
| |
| elemDecl->setFinalSet(parseFinalSet(elem, EC_Final)); |
| } |
| |
| elemDecl->setBlockSet(parseBlockSet(elem, ES_Block)); |
| elemDecl->setMiscFlags(elementMiscFlags); |
| } |
| |
| void TraverseSchema::processElemDeclIC(DOMElement* const icElem, |
| SchemaElementDecl* const elemDecl) |
| { |
| // key/keyref/unique processing |
| ValueVectorOf<DOMElement*>* icNodes = 0; |
| DOMElement* ic = icElem; |
| while (ic != 0) { |
| |
| if (XMLString::equals(ic->getLocalName(), SchemaSymbols::fgELT_KEY)) { |
| traverseKey(ic, elemDecl); |
| } |
| else if (XMLString::equals(ic->getLocalName(), SchemaSymbols::fgELT_UNIQUE)) { |
| traverseUnique(ic, elemDecl); |
| } |
| else { |
| |
| if (!icNodes) { |
| icNodes = new (fGrammarPoolMemoryManager) ValueVectorOf<DOMElement*>(8, fGrammarPoolMemoryManager); |
| } |
| |
| icNodes->addElement(ic); |
| } |
| |
| ic = XUtil::getNextSiblingElementNS( |
| ic, fgIdentityConstraints, SchemaSymbols::fgURI_SCHEMAFORSCHEMA, 3); |
| } |
| |
| if (icNodes) { |
| |
| if (!fIC_ElementsNS) { |
| |
| fIC_ElementsNS = new (fMemoryManager) RefHashTableOf<ElemVector>(13, fMemoryManager); |
| fIC_NodeListNS = new (fMemoryManager) RefHashTableOf<ValueVectorOf<DOMElement*>, PtrHasher>(29, true, fMemoryManager); |
| } |
| |
| fIC_Elements = fIC_ElementsNS->get(fTargetNSURIString); |
| if (!fIC_Elements) { |
| fIC_Elements = new (fMemoryManager) ValueVectorOf<SchemaElementDecl*>(8, fMemoryManager); |
| fIC_ElementsNS->put((void*) fTargetNSURIString, fIC_Elements); |
| } |
| |
| fIC_NodeListNS->put(elemDecl, icNodes); |
| fIC_Elements->addElement(elemDecl); |
| } |
| } |
| |
| bool |
| TraverseSchema::checkElemDeclValueConstraint(const DOMElement* const elem, |
| SchemaElementDecl* const elemDecl, |
| const XMLCh* const valConstraint, |
| ComplexTypeInfo* const typeInfo, |
| DatatypeValidator* const validator) |
| { |
| bool isValid = false; |
| if (validator) |
| { |
| if (validator->getType() == DatatypeValidator::ID) |
| reportSchemaError( |
| elem, XMLUni::fgXMLErrDomain, XMLErrs::ElemIDValueConstraint |
| , elemDecl->getBaseName(), valConstraint |
| ); |
| |
| try |
| { |
| const XMLCh* valueToCheck = valConstraint; |
| short wsFacet = validator->getWSFacet(); |
| if((wsFacet == DatatypeValidator::REPLACE && !XMLString::isWSReplaced(valueToCheck)) || |
| (wsFacet == DatatypeValidator::COLLAPSE && !XMLString::isWSCollapsed(valueToCheck))) |
| { |
| XMLCh* normalizedValue=XMLString::replicate(valueToCheck, fMemoryManager); |
| ArrayJanitor<XMLCh> tempURIName(normalizedValue, fMemoryManager); |
| if(wsFacet == DatatypeValidator::REPLACE) |
| XMLString::replaceWS(normalizedValue, fMemoryManager); |
| else if(wsFacet == DatatypeValidator::COLLAPSE) |
| XMLString::collapseWS(normalizedValue, fMemoryManager); |
| valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue)); |
| } |
| |
| validator->validate(valueToCheck,0,fMemoryManager); |
| |
| XMLCh* canonical = (XMLCh*) validator->getCanonicalRepresentation(valueToCheck, fMemoryManager); |
| ArrayJanitor<XMLCh> tempCanonical(canonical, fMemoryManager); |
| |
| if(!XMLString::equals(canonical, valueToCheck)) |
| { |
| validator->validate(canonical, 0, fMemoryManager); |
| valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(canonical)); |
| } |
| |
| elemDecl->setDefaultValue(valueToCheck); |
| |
| isValid = true; |
| } |
| catch(const XMLException& excep) |
| { |
| reportSchemaError(elem, excep); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch(...) |
| { |
| reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::DatatypeValidationFailure, valConstraint); |
| } |
| } |
| |
| if (typeInfo) |
| { |
| int contentSpecType = typeInfo->getContentType(); |
| |
| if (contentSpecType != SchemaElementDecl::Simple && |
| contentSpecType != SchemaElementDecl::Mixed_Simple && |
| contentSpecType != SchemaElementDecl::Mixed_Complex) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NotSimpleOrMixedElement, elemDecl->getBaseName()); |
| |
| if (((contentSpecType == SchemaElementDecl::Mixed_Complex |
| || contentSpecType == SchemaElementDecl::Mixed_Simple) |
| && !emptiableParticle(typeInfo->getContentSpec()))) |
| reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::EmptiableMixedContent, elemDecl->getBaseName()); |
| } |
| |
| return isValid; |
| } |
| |
| void TraverseSchema::processSubstitutionGroup(const DOMElement* const elem, |
| SchemaElementDecl* const elemDecl, |
| ComplexTypeInfo*& typeInfo, |
| DatatypeValidator*& validator, |
| const XMLCh* const subsElemQName) |
| { |
| NamespaceScopeManager nsMgr(elem, fSchemaInfo, this); |
| |
| SchemaElementDecl* subsElemDecl = getGlobalElemDecl(elem, subsElemQName); |
| if (subsElemDecl) |
| { |
| if (isSubstitutionGroupCircular(elemDecl, subsElemDecl)) |
| { |
| reportSchemaError( |
| elem , XMLUni::fgXMLErrDomain , XMLErrs::CircularSubsGroup, elemDecl->getBaseName()); |
| } |
| else |
| { |
| // Check for substitution validity constraint |
| // Substitution allowed (block and blockDefault) && same type |
| if (isSubstitutionGroupValid(elem, subsElemDecl, typeInfo, validator, elemDecl->getBaseName())) |
| { |
| elemDecl->setSubstitutionGroupElem(subsElemDecl); |
| |
| // if type information is missing, use subsGroup one |
| if (!typeInfo && !validator) |
| { |
| typeInfo = subsElemDecl->getComplexTypeInfo(); |
| validator = subsElemDecl->getDatatypeValidator(); |
| |
| if (validator) |
| { |
| elemDecl->setDatatypeValidator(validator); |
| elemDecl->setModelType(SchemaElementDecl::Simple); |
| } |
| else if (typeInfo) |
| { |
| elemDecl->setComplexTypeInfo(typeInfo); |
| elemDecl->setModelType((SchemaElementDecl::ModelTypes)typeInfo->getContentType()); |
| } |
| } |
| |
| XMLCh* subsElemBaseName = subsElemDecl->getBaseName(); |
| int subsElemURI = subsElemDecl->getURI(); |
| ValueVectorOf<SchemaElementDecl*>* subsElements = |
| fValidSubstitutionGroups->get(subsElemBaseName, subsElemURI); |
| |
| if (!subsElements && fTargetNSURI != subsElemURI) |
| { |
| SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(fURIStringPool->getValueForId(subsElemURI)); |
| |
| if (aGrammar) |
| { |
| subsElements = aGrammar->getValidSubstitutionGroups()->get(subsElemBaseName, subsElemURI); |
| |
| if (subsElements) |
| { |
| subsElements = new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(*subsElements); |
| fValidSubstitutionGroups->put(subsElemBaseName, subsElemURI, subsElements); |
| } |
| else if (fSchemaInfo->circularImportExist(subsElemURI)) |
| { |
| aGrammar->getValidSubstitutionGroups()->put( |
| subsElemBaseName, subsElemURI, new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(8, fGrammarPoolMemoryManager)); |
| } |
| } |
| } |
| |
| if (!subsElements) |
| { |
| subsElements = new (fGrammarPoolMemoryManager) ValueVectorOf<SchemaElementDecl*>(8, fGrammarPoolMemoryManager); |
| fValidSubstitutionGroups->put(subsElemBaseName, subsElemURI, subsElements); |
| } |
| |
| subsElements->addElement(elemDecl); |
| |
| // update related subs. info in case of circular import |
| BaseRefVectorEnumerator<SchemaInfo> importingEnum = fSchemaInfo->getImportingListEnumerator(); |
| |
| while (importingEnum.hasMoreElements()) |
| { |
| const SchemaInfo& curRef = importingEnum.nextElement(); |
| SchemaGrammar* aGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(curRef.getTargetNSURIString()); |
| ValueVectorOf<SchemaElementDecl*>* subsElemList = |
| aGrammar->getValidSubstitutionGroups()->get(subsElemBaseName, subsElemURI); |
| |
| if (subsElemList && !subsElemList->containsElement(elemDecl)) |
| subsElemList->addElement(elemDecl); |
| } |
| |
| buildValidSubstitutionListB(elem, elemDecl, subsElemDecl); |
| buildValidSubstitutionListF(elem, elemDecl, subsElemDecl); |
| } |
| } |
| } |
| } |
| |
| void TraverseSchema::processAttValue(const XMLCh* const attVal, |
| XMLBuffer& aBuf) |
| { |
| // REVISIT-KN: assuming that attVal is not NULL |
| // |
| // normally, nothing will happen |
| const XMLCh* srcVal = attVal; |
| XMLCh nextCh = *srcVal; |
| while (nextCh) |
| { |
| if (nextCh <= chCloseAngle) { |
| switch (nextCh) { |
| case chDoubleQuote: |
| aBuf.append(chAmpersand); |
| aBuf.append(XMLUni::fgQuot); |
| aBuf.append(chSemiColon); |
| break; |
| case chSingleQuote: |
| aBuf.append(chAmpersand); |
| aBuf.append(XMLUni::fgApos); |
| aBuf.append(chSemiColon); |
| break; |
| case chCloseAngle: |
| aBuf.append(chAmpersand); |
| aBuf.append(XMLUni::fgGT); |
| aBuf.append(chSemiColon); |
| break; |
| case chOpenAngle: |
| aBuf.append(chAmpersand); |
| aBuf.append(XMLUni::fgLT); |
| aBuf.append(chSemiColon); |
| break; |
| case chAmpersand: |
| aBuf.append(chAmpersand); |
| aBuf.append(XMLUni::fgAmp); |
| aBuf.append(chSemiColon); |
| break; |
| default: |
| aBuf.append(nextCh); |
| break; |
| } // end switch |
| } |
| else |
| aBuf.append(nextCh); |
| |
| nextCh = *++srcVal; |
| } |
| } |
| |
| XSAnnotation* TraverseSchema::generateSyntheticAnnotation(const DOMElement* const elem |
| , ValueVectorOf<DOMNode*>* nonXSAttList) |
| { |
| const XMLCh* prefix = elem->getPrefix(); |
| ValueHashTableOf<unsigned int>* listOfURIs = new (fMemoryManager) ValueHashTableOf<unsigned int>(29, fMemoryManager); |
| bool sawXMLNS = false; |
| |
| fBuffer.reset(); |
| fBuffer.append(chOpenAngle); |
| if (prefix) |
| { |
| fBuffer.append(prefix); |
| fBuffer.append(chColon); |
| } |
| fBuffer.append(SchemaSymbols::fgELT_ANNOTATION); |
| |
| // next is the nonXSAttList names & values |
| XMLSize_t nonXSAttSize = nonXSAttList->size(); |
| |
| for (XMLSize_t i=0; i<nonXSAttSize; i++) |
| { |
| DOMNode* attNode = nonXSAttList->elementAt(i); |
| |
| fBuffer.append(chSpace); |
| fBuffer.append(attNode->getNodeName()); |
| fBuffer.append(chEqual); |
| fBuffer.append(chDoubleQuote); |
| processAttValue(attNode->getNodeValue(), fBuffer); |
| fBuffer.append(chDoubleQuote); |
| } |
| |
| // next is the namespaces on the elem |
| DOMElement* currentElem = (DOMElement*) elem; |
| DOMNamedNodeMap* eltAttrs; |
| XMLSize_t attrCount; |
| do { |
| eltAttrs = currentElem->getAttributes(); |
| attrCount = eltAttrs->getLength(); |
| for (XMLSize_t j = 0; j < attrCount; j++) |
| { |
| DOMNode* attribute = eltAttrs->item(j); |
| const XMLCh* attName = attribute->getNodeName(); |
| |
| if (XMLString::startsWith(attName, XMLUni::fgXMLNSColonString)) |
| { |
| if (!listOfURIs->containsKey((void*) attName)) { |
| listOfURIs->put((void*) attName, 0); |
| fBuffer.append(chSpace); |
| fBuffer.append(attName); |
| fBuffer.append(chEqual); |
| fBuffer.append(chDoubleQuote); |
| processAttValue(attribute->getNodeValue(), fBuffer); |
| fBuffer.append(chDoubleQuote); |
| } |
| } |
| else if (!sawXMLNS && XMLString::equals(attName, XMLUni::fgXMLNSString)) |
| { |
| fBuffer.append(chSpace); |
| fBuffer.append(attName); |
| fBuffer.append(chEqual); |
| fBuffer.append(chDoubleQuote); |
| processAttValue(attribute->getNodeValue(), fBuffer); |
| fBuffer.append(chDoubleQuote); |
| sawXMLNS = true; |
| } |
| } |
| currentElem = (DOMElement*) currentElem->getParentNode(); |
| } |
| while (currentElem != fSchemaInfo->getRoot()->getParentNode()); |
| delete listOfURIs; |
| |
| fBuffer.append(chCloseAngle); |
| fBuffer.append(chLF); |
| fBuffer.append(chOpenAngle); |
| if (prefix) |
| { |
| fBuffer.append(prefix); |
| fBuffer.append(chColon); |
| } |
| fBuffer.append(SchemaSymbols::fgELT_DOCUMENTATION); |
| fBuffer.append(chCloseAngle); |
| fBuffer.append(fgSynthetic_Annotation); |
| fBuffer.append(chOpenAngle); |
| fBuffer.append(chForwardSlash); |
| if (prefix) |
| { |
| fBuffer.append(prefix); |
| fBuffer.append(chColon); |
| } |
| fBuffer.append(SchemaSymbols::fgELT_DOCUMENTATION); |
| fBuffer.append(chCloseAngle); |
| fBuffer.append(chLF); |
| fBuffer.append(chOpenAngle); |
| fBuffer.append(chForwardSlash); |
| if (prefix) |
| { |
| fBuffer.append(prefix); |
| fBuffer.append(chColon); |
| } |
| fBuffer.append(SchemaSymbols::fgELT_ANNOTATION); |
| fBuffer.append(chCloseAngle); |
| |
| XSAnnotation* annot = new (fGrammarPoolMemoryManager) XSAnnotation(fBuffer.getRawBuffer(), fGrammarPoolMemoryManager); |
| annot->setLineCol( ((XSDElementNSImpl*)elem)->getLineNo() |
| , ((XSDElementNSImpl*)elem)->getColumnNo() ); |
| annot->setSystemId(fSchemaInfo->getCurrentSchemaURL()); |
| return annot; |
| } |
| |
| class AnnotationErrorReporter : public XMLErrorReporter |
| { |
| public: |
| AnnotationErrorReporter(XMLErrorReporter* chainedErrorReporter) |
| { |
| fErrorReporter = chainedErrorReporter; |
| setSystemIdAndPosition(NULL, 0, 0); |
| } |
| |
| void setSystemIdAndPosition(const XMLCh* systemId, XMLFileLoc line, XMLFileLoc column) |
| { |
| fSystemId=systemId; |
| fLine=line; |
| fColumn=column; |
| } |
| |
| virtual void error |
| ( |
| const unsigned int errCode |
| , const XMLCh* const errDomain |
| , const ErrTypes type |
| , const XMLCh* const errorText |
| , const XMLCh* const /*systemId*/ |
| , const XMLCh* const publicId |
| , const XMLFileLoc lineNum |
| , const XMLFileLoc colNum |
| ) |
| { |
| if(fErrorReporter) |
| fErrorReporter->error(errCode, errDomain, type, errorText, fSystemId, publicId, fLine+lineNum-1, lineNum==1?fColumn+colNum:colNum); |
| } |
| |
| virtual void resetErrors() {} |
| |
| protected: |
| XMLErrorReporter* fErrorReporter; |
| const XMLCh* fSystemId; |
| XMLFileLoc fLine, fColumn; |
| }; |
| |
| void TraverseSchema::validateAnnotations() { |
| |
| MemoryManager *memMgr = fMemoryManager; |
| RefHashTableOfEnumerator<XSAnnotation, PtrHasher> xsAnnotationEnum = RefHashTableOfEnumerator<XSAnnotation, PtrHasher> (fSchemaGrammar->getAnnotations(), false, memMgr); |
| XSAnnotation& xsAnnot = xsAnnotationEnum.nextElement(); |
| XSAnnotation* nextAnnot; |
| |
| // create schema grammar |
| SchemaGrammar *grammar = new (memMgr) SchemaGrammar(memMgr); |
| grammar->setComplexTypeRegistry(new (memMgr) RefHashTableOf<ComplexTypeInfo>(29, memMgr)); |
| grammar->setGroupInfoRegistry(new (memMgr) RefHashTableOf<XercesGroupInfo>(13, memMgr)); |
| grammar->setAttGroupInfoRegistry(new (memMgr) RefHashTableOf<XercesAttGroupInfo>(13, memMgr)); |
| grammar->setAttributeDeclRegistry(new (memMgr) RefHashTableOf<XMLAttDef>(29, memMgr)); |
| grammar->setValidSubstitutionGroups(new (memMgr) RefHash2KeysTableOf<ElemVector>(29, memMgr)); |
| grammar->setTargetNamespace(SchemaSymbols::fgURI_SCHEMAFORSCHEMA); |
| XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) grammar->getGrammarDescription(); |
| gramDesc->setTargetNamespace(SchemaSymbols::fgURI_SCHEMAFORSCHEMA); |
| |
| // setup components of annotation grammar |
| SchemaElementDecl* annotElemDecl = new (memMgr) SchemaElementDecl |
| ( |
| XMLUni::fgZeroLenString , SchemaSymbols::fgELT_ANNOTATION |
| , fURIStringPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA) |
| , SchemaElementDecl::Mixed_Complex, Grammar::TOP_LEVEL_SCOPE , memMgr |
| ); |
| annotElemDecl->setCreateReason(XMLElementDecl::Declared); |
| grammar->putElemDecl(annotElemDecl); |
| |
| ComplexTypeInfo* complexType = new (memMgr) ComplexTypeInfo(memMgr); |
| complexType->setAnonymous(); |
| complexType->setContentType(SchemaElementDecl::Mixed_Complex); |
| annotElemDecl->setComplexTypeInfo(complexType); |
| |
| fBuffer.set(SchemaSymbols::fgURI_SCHEMAFORSCHEMA); |
| fBuffer.append(chComma); |
| fBuffer.append(chLatin_C); |
| fBuffer.append(chDigit_0); |
| const XMLCh* fullName = fStringPool->getValueForId(fStringPool->addOrFind(fBuffer.getRawBuffer())); |
| grammar->getComplexTypeRegistry()->put((void*) fullName, complexType); |
| complexType->setTypeName(fullName); |
| complexType->setAttWildCard |
| ( |
| new (memMgr) SchemaAttDef |
| ( |
| XMLUni::fgZeroLenString, XMLUni::fgZeroLenString, |
| fEmptyNamespaceURI, XMLAttDef::Any_Any, |
| XMLAttDef::ProcessContents_Lax, memMgr |
| ) |
| ); |
| |
| SchemaElementDecl* appInfoElemDecl = new (memMgr) SchemaElementDecl |
| ( |
| XMLUni::fgZeroLenString , SchemaSymbols::fgELT_APPINFO |
| , fURIStringPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA) |
| , SchemaElementDecl::Any, Grammar::TOP_LEVEL_SCOPE , memMgr |
| ); |
| |
| appInfoElemDecl->setCreateReason(XMLElementDecl::Declared); |
| appInfoElemDecl->setAttWildCard |
| ( |
| new (memMgr) SchemaAttDef |
| ( |
| XMLUni::fgZeroLenString, XMLUni::fgZeroLenString, |
| fEmptyNamespaceURI, XMLAttDef::Any_Any, |
| XMLAttDef::ProcessContents_Lax, memMgr |
| ) |
| ); |
| grammar->putElemDecl(appInfoElemDecl); |
| complexType->addElement(appInfoElemDecl); |
| |
| SchemaElementDecl* docElemDecl = new (memMgr) SchemaElementDecl |
| ( |
| XMLUni::fgZeroLenString , SchemaSymbols::fgELT_DOCUMENTATION |
| , fURIStringPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA) |
| , SchemaElementDecl::Any, Grammar::TOP_LEVEL_SCOPE , memMgr |
| ); |
| |
| docElemDecl->setCreateReason(XMLElementDecl::Declared); |
| docElemDecl->setAttWildCard |
| ( |
| new (memMgr) SchemaAttDef |
| ( |
| XMLUni::fgZeroLenString, XMLUni::fgZeroLenString, |
| fEmptyNamespaceURI, XMLAttDef::Any_Any, |
| XMLAttDef::ProcessContents_Lax, memMgr |
| ) |
| ); |
| grammar->putElemDecl(docElemDecl); |
| complexType->addElement(docElemDecl); |
| |
| ContentSpecNode* left = new (memMgr) ContentSpecNode(appInfoElemDecl, memMgr); |
| ContentSpecNode* right = new (memMgr) ContentSpecNode(docElemDecl, memMgr); |
| ContentSpecNode* root = new (memMgr) ContentSpecNode(ContentSpecNode::ModelGroupChoice |
| , left |
| , right |
| , true |
| , true |
| , memMgr); |
| root->setMinOccurs(0); |
| root->setMaxOccurs(SchemaSymbols::XSD_UNBOUNDED); |
| complexType->setContentSpec(root); |
| |
| // create input source to scan |
| MemBufInputSource* memBufIS = new (memMgr) MemBufInputSource |
| ( |
| (const XMLByte*)xsAnnot.getAnnotationString() |
| , XMLString::stringLen(xsAnnot.getAnnotationString())*sizeof(XMLCh) |
| , SchemaSymbols::fgELT_ANNOTATION |
| , false |
| , memMgr |
| ); |
| Janitor<MemBufInputSource> janMemBuf(memBufIS); |
| memBufIS->setEncoding(XMLUni::fgXMLChEncodingString); |
| memBufIS->setCopyBufToStream(false); |
| |
| XSAXMLScanner *scanner = new (memMgr) XSAXMLScanner |
| ( |
| fGrammarResolver, fURIStringPool, grammar, memMgr |
| ); |
| Janitor<XSAXMLScanner> janScanner(scanner); |
| |
| AnnotationErrorReporter annErrReporter(fErrorReporter); |
| scanner->setErrorReporter(&annErrReporter); |
| |
| XMLFileLoc line, col; |
| xsAnnot.getLineCol(line, col); |
| annErrReporter.setSystemIdAndPosition(xsAnnot.getSystemId(), line, col); |
| scanner->scanDocument(*memBufIS); |
| |
| nextAnnot = xsAnnot.getNext(); |
| |
| while (nextAnnot || xsAnnotationEnum.hasMoreElements()) |
| { |
| if (nextAnnot) { |
| memBufIS->resetMemBufInputSource((const XMLByte*)nextAnnot->getAnnotationString() |
| , XMLString::stringLen(nextAnnot->getAnnotationString())*sizeof(XMLCh)); |
| nextAnnot->getLineCol(line, col); |
| annErrReporter.setSystemIdAndPosition(nextAnnot->getSystemId(), line, col); |
| nextAnnot = nextAnnot->getNext(); |
| } |
| else { |
| XSAnnotation& xsAnnot = xsAnnotationEnum.nextElement(); |
| memBufIS->resetMemBufInputSource((const XMLByte*)xsAnnot.getAnnotationString() |
| , XMLString::stringLen(xsAnnot.getAnnotationString())*sizeof(XMLCh)); |
| xsAnnot.getLineCol(line, col); |
| annErrReporter.setSystemIdAndPosition(xsAnnot.getSystemId(), line, col); |
| nextAnnot = xsAnnot.getNext(); |
| } |
| scanner->scanDocument(*memBufIS); |
| } |
| |
| } |
| |
| const XMLCh* TraverseSchema::getElementAttValue(const DOMElement* const elem, |
| const XMLCh* const attName, |
| const DatatypeValidator::ValidatorType attType /* = UnKnown */) { |
| |
| DOMAttr* attNode = elem->getAttributeNode(attName); |
| |
| if (attNode == 0) { |
| return 0; |
| } |
| |
| const XMLCh* attValue = attNode->getValue(); |
| |
| if (attType < DatatypeValidator::ID) { |
| static bool bInitialized = false; |
| static short wsFacets[DatatypeValidator::ID] = {0}; |
| if(!bInitialized) |
| { |
| bInitialized=true; |
| DVHashTable* registry = DatatypeValidatorFactory::getBuiltInRegistry(); |
| wsFacets[DatatypeValidator::String] = registry->get(SchemaSymbols::fgDT_STRING)->getWSFacet(); |
| wsFacets[DatatypeValidator::AnyURI] = registry->get(SchemaSymbols::fgDT_ANYURI)->getWSFacet(); |
| wsFacets[DatatypeValidator::QName] = registry->get(SchemaSymbols::fgDT_QNAME)->getWSFacet(); |
| wsFacets[DatatypeValidator::Name] = registry->get(SchemaSymbols::fgDT_NAME)->getWSFacet(); |
| wsFacets[DatatypeValidator::NCName] = registry->get(SchemaSymbols::fgDT_NCNAME)->getWSFacet(); |
| wsFacets[DatatypeValidator::Boolean] = registry->get(SchemaSymbols::fgDT_BOOLEAN)->getWSFacet(); |
| wsFacets[DatatypeValidator::Float] = registry->get(SchemaSymbols::fgDT_FLOAT)->getWSFacet(); |
| wsFacets[DatatypeValidator::Double] = registry->get(SchemaSymbols::fgDT_DOUBLE)->getWSFacet(); |
| wsFacets[DatatypeValidator::Decimal] = registry->get(SchemaSymbols::fgDT_DECIMAL)->getWSFacet(); |
| wsFacets[DatatypeValidator::HexBinary] = registry->get(SchemaSymbols::fgDT_HEXBINARY)->getWSFacet(); |
| wsFacets[DatatypeValidator::Base64Binary]= registry->get(SchemaSymbols::fgDT_BASE64BINARY)->getWSFacet(); |
| wsFacets[DatatypeValidator::Duration] = registry->get(SchemaSymbols::fgDT_DURATION)->getWSFacet(); |
| wsFacets[DatatypeValidator::DateTime] = registry->get(SchemaSymbols::fgDT_DATETIME)->getWSFacet(); |
| wsFacets[DatatypeValidator::Date] = registry->get(SchemaSymbols::fgDT_DATE)->getWSFacet(); |
| wsFacets[DatatypeValidator::Time] = registry->get(SchemaSymbols::fgDT_TIME)->getWSFacet(); |
| wsFacets[DatatypeValidator::MonthDay] = registry->get(SchemaSymbols::fgDT_MONTHDAY)->getWSFacet(); |
| wsFacets[DatatypeValidator::YearMonth] = registry->get(SchemaSymbols::fgDT_YEARMONTH)->getWSFacet(); |
| wsFacets[DatatypeValidator::Year] = registry->get(SchemaSymbols::fgDT_YEAR)->getWSFacet(); |
| wsFacets[DatatypeValidator::Month] = registry->get(SchemaSymbols::fgDT_MONTH)->getWSFacet(); |
| wsFacets[DatatypeValidator::Day] = registry->get(SchemaSymbols::fgDT_DAY)->getWSFacet(); |
| } |
| short wsFacet = wsFacets[attType]; |
| if((wsFacet == DatatypeValidator::REPLACE && !XMLString::isWSReplaced(attValue)) || |
| (wsFacet == DatatypeValidator::COLLAPSE && !XMLString::isWSCollapsed(attValue))) |
| { |
| XMLCh* normalizedValue=XMLString::replicate(attValue, fMemoryManager); |
| ArrayJanitor<XMLCh> tempName(normalizedValue, fMemoryManager); |
| if(wsFacet == DatatypeValidator::REPLACE) |
| XMLString::replaceWS(normalizedValue, fMemoryManager); |
| else if(wsFacet == DatatypeValidator::COLLAPSE) |
| XMLString::collapseWS(normalizedValue, fMemoryManager); |
| if (!*normalizedValue) |
| return XMLUni::fgZeroLenString; |
| return fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue)); |
| } |
| } |
| |
| return attValue; |
| } |
| |
| } |
| |
| /** |
| * End of file TraverseSchema.cpp |
| */ |