#include "../config/pathan_config.h" /* * Copyright (c) 2002, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void DocumentCacheErrorCatcher::warning(const XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException& toCatch) { // ignore them } void DocumentCacheErrorCatcher::error(const XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException& toCatch) { throw toCatch; } void DocumentCacheErrorCatcher::fatalError(const XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException& toCatch) { throw toCatch; } void DocumentCacheErrorCatcher::resetErrors() { } ///////////////////////////////////////////////////////////////// // // /* urn:Pathan2:validation */ static const XMLCh g_szPathanURI[] = { XERCES_CPP_NAMESPACE_QUALIFIER chLatin_u, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_r, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, XERCES_CPP_NAMESPACE_QUALIFIER chColon, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_h, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, XERCES_CPP_NAMESPACE_QUALIFIER chDigit_2, XERCES_CPP_NAMESPACE_QUALIFIER chColon, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_v, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_l, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_i, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_d, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_i, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, XERCES_CPP_NAMESPACE_QUALIFIER chNull }; /* root */ static const XMLCh g_szRoot[] = { XERCES_CPP_NAMESPACE_QUALIFIER chLatin_r, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, XERCES_CPP_NAMESPACE_QUALIFIER chNull }; /* pathan */ static const XMLCh g_szPathan[] = { XERCES_CPP_NAMESPACE_QUALIFIER chLatin_p, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_h, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, XERCES_CPP_NAMESPACE_QUALIFIER chNull }; /* urn:Pathan2:validation,C0 */ static const XMLCh g_szTypeName[] = { XERCES_CPP_NAMESPACE_QUALIFIER chLatin_u, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_r, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, XERCES_CPP_NAMESPACE_QUALIFIER chColon, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_P, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_h, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, XERCES_CPP_NAMESPACE_QUALIFIER chDigit_2, XERCES_CPP_NAMESPACE_QUALIFIER chColon, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_v, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_l, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_i, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_d, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_i, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, XERCES_CPP_NAMESPACE_QUALIFIER chComma, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_C, XERCES_CPP_NAMESPACE_QUALIFIER chDigit_0, XERCES_CPP_NAMESPACE_QUALIFIER chNull }; XERCES_CPP_NAMESPACE_QUALIFIER Grammar* DocumentCacheParser::createPathanGrammar(XERCES_CPP_NAMESPACE_QUALIFIER MemoryManager *mm, XERCES_CPP_NAMESPACE_QUALIFIER GrammarResolver *gr, XERCES_CPP_NAMESPACE_QUALIFIER XMLScanner *xmlScan) { XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar *sg = new (mm) XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar(mm); sg->setTargetNamespace(g_szPathanURI); sg->setGrammarDescription(gr->getGrammarPool()->createSchemaDescription(g_szPathanURI)); sg->setComplexTypeRegistry(new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(29,mm)); // TODO: These lines are not needed when Xerces fixes a bug in the XSModel::addGrammarToXSModel() - jpcs sg->setAttributeDeclRegistry(new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm)); sg->setAttGroupInfoRegistry(new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm)); sg->setGroupInfoRegistry(new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm)); unsigned int pathanUriId = xmlScan->getURIStringPool()->addOrFind(g_szPathanURI); XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl* pRootElt=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl*)sg->putElemDecl(pathanUriId,g_szRoot, g_szPathan, NULL, XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE); pRootElt->setCreateReason(XERCES_CPP_NAMESPACE_QUALIFIER XMLElementDecl::Declared); return sg; } XERCES_CPP_NAMESPACE_QUALIFIER Grammar* DocumentCacheParser::createXQueryTypes(XERCES_CPP_NAMESPACE_QUALIFIER MemoryManager *mm, XERCES_CPP_NAMESPACE_QUALIFIER GrammarResolver *gr) { XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar *sg = new (mm) XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar(mm); // TODO: These lines are not needed when Xerces fixes a bug in the XSModel::addGrammarToXSModel() - jpcs sg->setComplexTypeRegistry(new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm)); sg->setAttributeDeclRegistry(new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm)); sg->setAttGroupInfoRegistry(new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm)); sg->setGroupInfoRegistry(new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm)); sg->setTargetNamespace(FunctionConstructor::XMLChXPath2DatatypesURI); sg->setGrammarDescription(gr->getGrammarPool()->createSchemaDescription(FunctionConstructor::XMLChXPath2DatatypesURI)); XERCES_CPP_NAMESPACE_QUALIFIER DatatypeValidatorFactory *dtvf = sg->getDatatypeRegistry(); // xdt:dayTimeDuration XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf* facets = new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm); facets->put((void*) XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgELT_PATTERN, new (mm) XERCES_CPP_NAMESPACE_QUALIFIER KVStringPair(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgELT_PATTERN, ATDurationOrDerived::pattern_DT_YEARMONTHDURATION,mm)); dtvf->createDatatypeValidator(ATDurationOrDerived::fgDT_YEARMONTHDURATION_XERCESHASH, dtvf->getDatatypeValidator(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DURATION), facets, 0, false, 0, true, mm); // xdt:yearMonthDuration facets = new (mm) XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf(1,mm); facets->put((void*) XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgELT_PATTERN, new (mm) XERCES_CPP_NAMESPACE_QUALIFIER KVStringPair(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgELT_PATTERN, ATDurationOrDerived::pattern_DT_DAYTIMEDURATION,mm)); dtvf->createDatatypeValidator(ATDurationOrDerived::fgDT_DAYTIMEDURATION_XERCESHASH, dtvf->getDatatypeValidator(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DURATION), facets, 0, false, 0, true, mm); // xdt:anyAtomicType -- no facets. We need to put this validator in the xerces memory manager, and put it in the registry ourselves XERCES_CPP_NAMESPACE_QUALIFIER DVHashTable *defRegistry = dtvf->getBuiltInRegistry(); if(!defRegistry->containsKey((void*) AnyAtomicType::fgDT_ANYATOMICTYPE_XERCESHASH)) { XERCES_CPP_NAMESPACE_QUALIFIER DatatypeValidator* dv = new (XERCES_CPP_NAMESPACE_QUALIFIER XMLPlatformUtils::fgMemoryManager) AnyAtomicTypeDatatypeValidator(); dv->setTypeName(AnyAtomicType::fgDT_ANYATOMICTYPE_XERCESHASH); defRegistry->put((void*) AnyAtomicType::fgDT_ANYATOMICTYPE_XERCESHASH, dv); } // xdt:untypedAtomic -- no facets dtvf->createDatatypeValidator(ATUntypedAtomic::fgDT_UNTYPEDATOMIC_XERCESHASH, dtvf->getDatatypeValidator(AnyAtomicType::fgDT_ANYATOMICTYPE_XERCESHASH), 0, 0, false, 0, true, mm); return sg; } DocumentCacheParser::DocumentCacheParser(const DocumentCacheParser &parent, XPath2MemoryManager* memMgr) : XercesDOMParser(0, memMgr, parent.getGrammarResolver()->getGrammarPool()), _documentMap(3,false,memMgr), _context(0), _memMgr(memMgr) { init(); _xqueryDatatypes = parent._xqueryDatatypes; } DocumentCacheParser::DocumentCacheParser(XPath2MemoryManager* memMgr, XERCES_CPP_NAMESPACE_QUALIFIER XMLGrammarPool* xmlgr) : XercesDOMParser(0,memMgr, xmlgr), _documentMap(3,false,memMgr), _context(0), _memMgr(memMgr) { init(); // add XPath2 types _xqueryDatatypes = (XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar*) createXQueryTypes(_memMgr, getGrammarResolver()); getGrammarResolver()->putGrammar(_xqueryDatatypes); getGrammarResolver()->cacheGrammars(); getGrammarResolver()->useCachedGrammarInParse(true); // also set these things to true. Not sure if this is correct, but without // them, all built-in types cannot be found (untypedAtomic, dayTimeDuration and yearMonthDuration) -- crioux getGrammarResolver()->cacheGrammarFromParse(true); if(!isCachingGrammarFromParse()) cacheGrammarFromParse(true); // hold the loaded schemas in the cache, so that can be reused } void DocumentCacheParser::init() { //todo this does not need to happen now if these types are already in the cache!!! //also sort out what state to be in for the query - ie no cacheing to polute the grammar // set up the parser setDoSchema(true);// enable schema processing setDoNamespaces(true);// enable namespaces (needed for schema processing) setValidationScheme(XERCES_CPP_NAMESPACE_QUALIFIER AbstractDOMParser::Val_Auto);// try to validate setCreateEntityReferenceNodes(false);// don't create entity reference nodes, but represent its value in the DOM tree setValidationConstraintFatal(false);// if a schema validation error is encountered, don't abort parsing setErrorHandler(&_errorHandler); // add the grammar used when validating DOM nodes _pathanGrammar = (XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar*)createPathanGrammar(_memMgr, getGrammarResolver(), getScanner()); _pathanUriId = getScanner()->getURIStringPool()->addOrFind(g_szPathanURI); getGrammarResolver()->putGrammar(_pathanGrammar); } void DocumentCacheParser::startDocument() { // Mostly copied from AbstractDOMParser::startDocument() if(_context) { fDocument = (XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl *) _context->createNewDocument(); // This uses the context's memory manager } else { fDocument = (XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl *) XERCES_CPP_NAMESPACE_QUALIFIER DOMImplementation::getImplementation()->createDocument(fMemoryManager); } // Just set the document as the current parent and current node fCurrentParent = fDocument; fCurrentNode = fDocument; // set DOM error checking off fDocument->setErrorChecking(false); fDocument->setDocumentURI(fScanner->getLocator()->getSystemId()); fDocument->setActualEncoding(fScanner->getReaderMgr()->getCurrentEncodingStr()); } XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *DocumentCacheParser::parseWithContext(const XERCES_CPP_NAMESPACE_QUALIFIER InputSource &source, StaticContext *context) { _context = context; try { parse(source); } catch(...) { _context = 0; throw; } _context = 0; return adoptDocument(); } XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *DocumentCacheParser::parseWithContext(const XMLCh* const uri, StaticContext *context) { // Resolve the uri against the base uri const XMLCh *systemId = uri; XERCES_CPP_NAMESPACE_QUALIFIER XMLURL urlTmp(context->getMemoryManager()); if(urlTmp.setURL(context->getBaseURI(), uri, urlTmp)) { systemId = urlTmp.getURLText(); } XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *cachedDoc = retrieveDocument(systemId); if(cachedDoc) { return cachedDoc; } _context = context; try { parse(systemId); storeDocument(systemId, getDocument()); } catch(...) { _context = 0; throw; } _context = 0; return adoptDocument(); } XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* DocumentCacheParser::retrieveDocument(const XMLCh* uri) { return _documentMap.get((void*)uri); } void DocumentCacheParser::storeDocument(const XMLCh* uri, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* document) { _documentMap.put((void*)_memMgr->getPooledString(uri),document); } void DocumentCacheParser::clearStoredDocuments() { _documentMap.removeAll(); } void DocumentCacheParser::loadSchema(const XMLCh* const uri, StaticContext *context) { // Resolve the uri against the base uri const XMLCh *systemId = uri; XERCES_CPP_NAMESPACE_QUALIFIER XMLURL urlTmp(context->getMemoryManager()); if(urlTmp.setURL(context->getBaseURI(), uri, urlTmp)) { systemId = urlTmp.getURLText(); } // always validate, so that the preloaded schema can be matched even if the XML doesn't reference it setValidationScheme(XERCES_CPP_NAMESPACE_QUALIFIER AbstractDOMParser::Val_Always); // prepopulate the cache with the requested grammar, so that static typing can use it // if needed, set the "use cached grammars" flag if(!isCachingGrammarFromParse()) cacheGrammarFromParse(true);// hold the loaded schemas in the cache, so that can be reused getScanner()->loadGrammar(systemId, XERCES_CPP_NAMESPACE_QUALIFIER Grammar::SchemaGrammarType, true); } unsigned int DocumentCacheParser::getSchemaUriId(const XMLCh* uri) const { // This is a kind of hack... I should directly use fURIStringPool, but it's private. // So I ask the scanner to give me back the string pool I gave him before.... return getScanner()->getURIStringPool()->getId(uri); } const XMLCh* DocumentCacheParser::getSchemaUri(unsigned int id) const { // This is a kind of hack... I should directly use fURIStringPool, but it's private. // So I ask the scanner to give me back the string pool I gave him before.... return getScanner()->getURIStringPool()->getValueForId(id); } bool DocumentCacheParser::isChildElement( XERCES_CPP_NAMESPACE_QUALIFIER ContentSpecNode *topContentSpec, unsigned int uriId, const XMLCh* localPart ) const { if(topContentSpec){ if(topContentSpec->getType()==XERCES_CPP_NAMESPACE_QUALIFIER ContentSpecNode::Leaf) { XERCES_CPP_NAMESPACE_QUALIFIER QName* qName=topContentSpec->getElement(); if(qName->getURI()==uriId && XPath2Utils::equals(qName->getLocalPart(),localPart)) return true; } else { if(isChildElement(topContentSpec->getFirst(), uriId, localPart) || isChildElement(topContentSpec->getSecond(), uriId, localPart)) return true; } } return false; } ValidationContext DocumentCacheParser::updateValidationContext(ValidationContext current,QualifiedName* step,bool bIsElement,StaticContext* context) const { ValidationContext newContext; const XMLCh* uri=context->getUriBoundToPrefix(step->getPrefix()); unsigned int uriId=getSchemaUriId(uri); XERCES_CPP_NAMESPACE_QUALIFIER XMLSchemaDescription* gramDesc = getGrammarResolver()->getGrammarPool()->createSchemaDescription(uri); XERCES_CPP_NAMESPACE_QUALIFIER Janitor janName(gramDesc); XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar* schGrammar=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar*)getGrammarResolver()->getGrammar(gramDesc); switch(current.getContextType()) { case ValidationContext::GLOBAL_CONTEXT: { if(bIsElement) { XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl* elemDecl=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl*) schGrammar->getElemDecl(uriId, step->getName(), NULL, XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE); if(elemDecl==NULL) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Definition for element {")); msg.append(uri); msg.append(X("}")); msg.append(step->getName()); msg.append(X(" cannot be found")); DSLthrow(ContextException,X("DocumentCacheParser::updateValidationContext"), msg.getRawBuffer()); } newContext.setCurrentElement(elemDecl); } else { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer typeKey(1023, context->getMemoryManager()); typeKey.set(uri); typeKey.append(XERCES_CPP_NAMESPACE_QUALIFIER chComma); typeKey.append(step->getName()); XERCES_CPP_NAMESPACE_QUALIFIER ComplexTypeInfo* typeDecl=schGrammar->getComplexTypeRegistry()->get(typeKey.getRawBuffer()); if(typeDecl==NULL) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Definition for type {")); msg.append(uri); msg.append(X("}")); msg.append(step->getName()); msg.append(X(" cannot be found")); DSLthrow(ContextException,X("DocumentCacheParser::updateValidationContext"), msg.getRawBuffer()); } newContext.setCurrentType(typeDecl); } break; } case ValidationContext::TYPE_CONTEXT: case ValidationContext::ELEMENT_CONTEXT: { if(bIsElement) { XERCES_CPP_NAMESPACE_QUALIFIER ComplexTypeInfo* curType=NULL; const XMLCh* parentURI=NULL; const XMLCh* parentName=NULL; if(current.getContextType()==ValidationContext::TYPE_CONTEXT) { curType=current.getCurrentType(); parentURI=curType->getTypeUri(); parentName=curType->getTypeLocalName(); } else { XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl* curElement=current.getCurrentElement(); curType=curElement->getComplexTypeInfo(); parentURI=getSchemaUri(curElement->getURI()); parentName=curElement->getElementName()->getLocalPart(); if(curType==NULL) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Element {")); msg.append(parentURI); msg.append(X("}")); msg.append(parentName); msg.append(X(" is not a complex type")); DSLthrow(ContextException,X("DocumentCacheParser::updateValidationContext"), msg.getRawBuffer()); } } if(!isChildElement(curType->getContentSpec(), uriId, step->getName())) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Element {")); msg.append(uri); msg.append(X("}")); msg.append(step->getName()); msg.append(X(" is not a child of the type {")); msg.append(parentURI); msg.append(X("}")); msg.append(parentName); DSLthrow(ContextException,X("DocumentCacheParser::updateValidationContext"), msg.getRawBuffer()); } // ok, if the content spec told us this is a valid child, it could be a locally defined element... XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl* elemDecl=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl*) schGrammar->getElemDecl(uriId, step->getName(), NULL, curType->getScopeDefined()); if(elemDecl==NULL) { // ... or a reference to a global element elemDecl=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl*)schGrammar->getElemDecl(uriId, step->getName(), NULL, XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE); } if(elemDecl==NULL) { // I should never be here.... XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Definition for element {")); msg.append(uri); msg.append(X("}")); msg.append(step->getName()); msg.append(X(" cannot be found")); DSLthrow(ContextException,X("DocumentCacheParser::updateValidationContext"), msg.getRawBuffer()); } newContext.setCurrentElement(elemDecl); } else { // it's an attribute XERCES_CPP_NAMESPACE_QUALIFIER SchemaAttDef* pAttr=NULL; bool bDummy; if(current.getContextType()==ValidationContext::TYPE_CONTEXT) { pAttr=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaAttDef*)current.getCurrentType()->findAttr(NULL, uriId, step->getName(), step->getPrefix(), XERCES_CPP_NAMESPACE_QUALIFIER XMLElementDecl::FailIfNotFound, bDummy); } else { pAttr=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaAttDef*)current.getCurrentElement()->findAttr(NULL, uriId, step->getName(), step->getPrefix(), XERCES_CPP_NAMESPACE_QUALIFIER XMLElementDecl::FailIfNotFound, bDummy); } if(pAttr==NULL) { // I should never be here.... XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Definition for attribute {")); msg.append(uri); msg.append(X("}")); msg.append(step->getName()); msg.append(X(" cannot be found")); DSLthrow(ContextException,X("DocumentCacheParser::updateValidationContext"), msg.getRawBuffer()); } newContext.setCurrentAttribute(pAttr); } break; } case ValidationContext::ATTRIBUTE_CONTEXT: { // I should never be here.... XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Cannot navigate a schema starting from an attribute")); DSLthrow(ContextException,X("DocumentCacheParser::updateValidationContext"), msg.getRawBuffer()); break; } } return newContext; } XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *DocumentCacheParser::validate(const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node, DocumentCache::ValidationMode valMode, ValidationContext valCtx, StaticContext *context) { XERCES_CPP_NAMESPACE_QUALIFIER AbstractDOMParser::ValSchemes oldValScheme=getValidationScheme(); try { int curEltScope=XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE; XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer toBeParsed(1023, context->getMemoryManager()); if(valMode==DocumentCache::VALIDATION_SKIP) { // no need to specify a schema; just serialize and parse with validation off XERCES_CPP_NAMESPACE_QUALIFIER DOMWriter* writer = XERCES_CPP_NAMESPACE_QUALIFIER DOMImplementation::getImplementation()->createDOMWriter(context->getMemoryManager()); XMLCh* serializedForm=writer->writeToString(*node); writer->release(); toBeParsed.set(serializedForm); delete serializedForm; } else { XERCES_CPP_NAMESPACE_QUALIFIER ComplexTypeInfo* curType=NULL; switch(valCtx.getContextType()) { case ValidationContext::GLOBAL_CONTEXT: curType=NULL; curEltScope=XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE; break; case ValidationContext::TYPE_CONTEXT: curType=valCtx.getCurrentType(); curEltScope=curType->getScopeDefined(); break; case ValidationContext::ELEMENT_CONTEXT: curType=valCtx.getCurrentElement()->getComplexTypeInfo(); curEltScope=curType->getScopeDefined(); break; case ValidationContext::ATTRIBUTE_CONTEXT: // Shut the compiler warnings up break; } const XMLCh* uri=node->getNamespaceURI(); XERCES_CPP_NAMESPACE_QUALIFIER XMLSchemaDescription* gramDesc = getGrammarResolver()->getGrammarPool()->createSchemaDescription(uri); XERCES_CPP_NAMESPACE_QUALIFIER Janitor janName(gramDesc); XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar* schGrammar=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar*)getGrammarResolver()->getGrammar(gramDesc); if(schGrammar==NULL && valMode==DocumentCache::VALIDATION_STRICT) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer exc_msg(1023, context->getMemoryManager()); exc_msg.set(X("Validation failed: namespace {")); exc_msg.append(uri); exc_msg.set(X("} has no associated schema")); DSLthrow(ContextException,X("DocumentCacheParser::validate"), exc_msg.getRawBuffer()); } unsigned int uriId=getSchemaUriId(uri); XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl* elemDecl=NULL; if(curType!=NULL && !isChildElement(curType->getContentSpec(), uriId, node->getLocalName()) && valMode==DocumentCache::VALIDATION_STRICT) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Element {")); msg.append(uri); msg.append(X("}")); msg.append(node->getLocalName()); msg.append(X(" is not defined in the current context")); DSLthrow(ContextException,X("DocumentCacheParser::validate"), msg.getRawBuffer()); } if(schGrammar!=NULL) { // find the definition for this node, as a local definition... elemDecl=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl*)schGrammar->getElemDecl(uriId, node->getLocalName(), NULL, curEltScope); // ... or as a reference to a global element if(elemDecl==NULL) elemDecl=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl*)schGrammar->getElemDecl(uriId, node->getLocalName(), NULL, XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE); } if(elemDecl==NULL && valMode==DocumentCache::VALIDATION_STRICT) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer msg(1023, context->getMemoryManager()); msg.set(X("Element {")); msg.append(uri); msg.append(X("}")); msg.append(node->getLocalName()); msg.append(X(" is not defined in the current context")); DSLthrow(ContextException,X("DocumentCacheParser::validate"), msg.getRawBuffer()); } // if the schema definition is a global one, we don't need any trick; otherwise, we need to add a root element carefully // crafted so that the definition can be found if(curEltScope!=XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE) { // now, change the definition for the pathan:root element to be // ... // // // // // // // // XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl* pRootElt= (XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl*)_pathanGrammar->getElemDecl(_pathanUriId, g_szRoot, NULL, XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE); _pathanGrammar->getComplexTypeRegistry()->reinitialize(NULL); XERCES_CPP_NAMESPACE_QUALIFIER ComplexTypeInfo* pRootType=new (context->getMemoryManager()) XERCES_CPP_NAMESPACE_QUALIFIER ComplexTypeInfo; pRootType->setAnonymous(); _pathanGrammar->getComplexTypeRegistry()->put((void*) g_szTypeName, pRootType); pRootType->setTypeName(g_szTypeName); // assign to this complex type the same scope the DOM element is defined into if(elemDecl!=NULL) pRootType->setScopeDefined(elemDecl->getEnclosingScope()); XERCES_CPP_NAMESPACE_QUALIFIER ContentSpecNode* pSpecNode = new (context->getMemoryManager()) XERCES_CPP_NAMESPACE_QUALIFIER ContentSpecNode(new (context->getMemoryManager()) XERCES_CPP_NAMESPACE_QUALIFIER QName(node->getPrefix(), node->getLocalName(), getSchemaUriId(uri)), false); pRootType->setContentSpec(pSpecNode); pRootType->setAdoptContentSpec(true); pRootType->setContentType(XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl::Children); pRootElt->setComplexTypeInfo(pRootType); pRootElt->setModelType((XERCES_CPP_NAMESPACE_QUALIFIER SchemaElementDecl::ModelTypes) pRootType->getContentType()); pRootElt->setContentSpec(pRootType->getContentSpec()); toBeParsed.set(X("")); XERCES_CPP_NAMESPACE_QUALIFIER DOMWriter* writer = XERCES_CPP_NAMESPACE_QUALIFIER DOMImplementation::getImplementation()->createDOMWriter(context->getMemoryManager()); XMLCh* serializedForm=writer->writeToString(*node); writer->release(); toBeParsed.append(serializedForm); toBeParsed.append(X("")); delete serializedForm; } else { XERCES_CPP_NAMESPACE_QUALIFIER DOMWriter* writer = XERCES_CPP_NAMESPACE_QUALIFIER DOMImplementation::getImplementation()->createDOMWriter(context->getMemoryManager()); XMLCh* serializedForm=writer->writeToString(*node); writer->release(); toBeParsed.set(serializedForm); delete serializedForm; } } // To build a copy of the input tree with validation informations, we need to: // - build a textual representation of the element const XMLCh* stringToBeParsed=toBeParsed.getRawBuffer(); // - enable the flag bValidationConstraintFatal switch(valMode) { case DocumentCache::VALIDATION_STRICT: setValidationConstraintFatal(true); // fallback to "lax" case DocumentCache::VALIDATION_LAX: setValidationScheme(XERCES_CPP_NAMESPACE_QUALIFIER AbstractDOMParser::Val_Always); break; case DocumentCache::VALIDATION_SKIP: setValidationScheme(XERCES_CPP_NAMESPACE_QUALIFIER AbstractDOMParser::Val_Never); break; case DocumentCache::VALIDATION_DEFAULT: // Shut the compiler warnings up break; } XERCES_CPP_NAMESPACE_QUALIFIER MemBufInputSource inputSrc( (const XMLByte*)stringToBeParsed, XERCES_CPP_NAMESPACE_QUALIFIER XMLString::stringLen(stringToBeParsed)*sizeof(XMLCh), XERCES_CPP_NAMESPACE_QUALIFIER XMLUni::fgZeroLenString, false, context->getMemoryManager()); inputSrc.setCopyBufToStream(false); inputSrc.setEncoding(XERCES_CPP_NAMESPACE_QUALIFIER XMLUni::fgUTF16EncodingString); // - parse the text (with validation on) XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* pDoc=parseWithContext(inputSrc, context); setValidationConstraintFatal(false); setValidationScheme(oldValScheme); // - return the document element if(pDoc==NULL) return NULL; XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* root=pDoc->getDocumentElement(); if(curEltScope!=XERCES_CPP_NAMESPACE_QUALIFIER Grammar::TOP_LEVEL_SCOPE) return root->removeChild(root->getFirstChild()); else if(node->getNodeType()==XERCES_CPP_NAMESPACE_QUALIFIER DOMNode::DOCUMENT_NODE) return pDoc; else return root; } catch (const XERCES_CPP_NAMESPACE_QUALIFIER SAXException& toCatch) { setValidationConstraintFatal(false); setValidationScheme(oldValScheme); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer exc_msg(1023, context->getMemoryManager()); exc_msg.set(X("Validation failed: ")); exc_msg.append(toCatch.getMessage()); DSLthrow(ContextException,X("DocumentCacheParser::validate"), exc_msg.getRawBuffer()); } catch (const XERCES_CPP_NAMESPACE_QUALIFIER DOMException& toCatch) { setValidationConstraintFatal(false); setValidationScheme(oldValScheme); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer exc_msg(1023, context->getMemoryManager()); exc_msg.set(X("Validation failed: ")); exc_msg.append(toCatch.msg); DSLthrow(ContextException,X("DocumentCacheParser::validate"), exc_msg.getRawBuffer()); } catch (const XERCES_CPP_NAMESPACE_QUALIFIER XMLException& toCatch) { setValidationConstraintFatal(false); setValidationScheme(oldValScheme); XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer exc_msg(1023, context->getMemoryManager()); exc_msg.set(X("Validation failed: ")); exc_msg.append(toCatch.getMessage()); DSLthrow(ContextException,X("DocumentCacheParser::validate"), exc_msg.getRawBuffer()); } return NULL; } void DocumentCacheParser::error(const unsigned int errCode , const XMLCh* const msgDomain , const XERCES_CPP_NAMESPACE_QUALIFIER XMLErrorReporter::ErrTypes errType , const XMLCh* const errorText , const XMLCh* const systemId , const XMLCh* const publicId , const XMLSSize_t lineNum , const XMLSSize_t colNum ) { XERCES_CPP_NAMESPACE_QUALIFIER XMLErrorReporter::ErrTypes newErrType=errType; // if we have disabled validation errors, convert them into warnings if (!getValidationConstraintFatal() && XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(msgDomain, XERCES_CPP_NAMESPACE_QUALIFIER XMLUni::fgValidityDomain)) newErrType=XERCES_CPP_NAMESPACE_QUALIFIER XMLErrorReporter::ErrType_Warning; XercesDOMParser::error(errCode,msgDomain,newErrType,errorText,systemId,publicId,lineNum,colNum); } ///////////////////////////////////////////////////// // DocumentCacheImpl::DocumentCacheImpl(XPath2MemoryManager* memMgr, XERCES_CPP_NAMESPACE_QUALIFIER XMLGrammarPool* xmlgr) : _parser(memMgr, xmlgr), _memMgr(memMgr) { } DocumentCacheImpl::DocumentCacheImpl(const DocumentCacheImpl *parent, XPath2MemoryManager* memMgr) : _parser(parent->_parser, memMgr), _memMgr(memMgr) { } void DocumentCacheImpl::setXMLEntityResolver(XERCES_CPP_NAMESPACE_QUALIFIER XMLEntityResolver* const handler) { _parser.setXMLEntityResolver(handler); } void DocumentCacheImpl::storeDocument(const XMLCh* uri,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* document) { _parser.storeDocument(uri, document); } void DocumentCacheImpl::clearStoredDocuments() { _parser.clearStoredDocuments(); } XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *DocumentCacheImpl::loadXMLDocument(const XMLCh* uri, StaticContext *context) { XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* doc=NULL; try { doc = _parser.parseWithContext(uri, context); } catch(const XERCES_CPP_NAMESPACE_QUALIFIER SAXException& toCatch) { //TODO: Find a way to decipher whether the exception is actually because of a parsing problem or because the document can't be found DSLthrow(XMLParseException, X("DocumentCacheImpl::loadXMLDocument"), toCatch.getMessage()); } catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException& toCatch) { DSLthrow(XMLParseException,X("DocumentCacheImpl::loadXMLDocument"), toCatch.msg); } catch(const XERCES_CPP_NAMESPACE_QUALIFIER XMLException& toCatch) { DSLthrow(XMLParseException,X("DocumentCacheImpl::loadXMLDocument"), toCatch.getMessage()); } return doc; } /* * returns true if the type represented by uri:typename is an instance of uriToCheck:typeNameToCheck * * ie: to check * xs:integer instance of xs:decimal, * call * isTypeOrDerivedFromType("xs", "integer", "xs", "decimal") * (except of course, call with URIs, not prefixes!) */ bool DocumentCacheImpl::isTypeOrDerivedFromType(const XMLCh* const uri, const XMLCh* const typeName, const XMLCh* const uriToCheck, const XMLCh* const typeNameToCheck) const { //cerr<<"is "<getDatatypeValidator(uri,typeName); if(dtvDerived==NULL) { ////cerr << "looking at complex" << endl; //now lets take a look at complex stuff XERCES_CPP_NAMESPACE_QUALIFIER ComplexTypeInfo *cti = getComplexTypeInfo(uri, typeName); //in the case of non-schema grammar if (cti) { // if we are here, the type is a complex type if(XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(uriToCheck, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA) && XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(typeNameToCheck, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgATTVAL_ANYTYPE)) return true; while(cti != 0) { if(XPath2Utils::equals(uriToCheck, cti->getTypeUri()) && XPath2Utils::equals(typeNameToCheck, cti->getTypeLocalName())) return true; XERCES_CPP_NAMESPACE_QUALIFIER ComplexTypeInfo *ctiOld = cti; cti = cti->getBaseComplexTypeInfo(); //might be derived from a simple type if(cti == 0) { XERCES_CPP_NAMESPACE_QUALIFIER DatatypeValidator* dtv = ctiOld->getDatatypeValidator(); while(dtv != 0) { //cerr << "dtv type nameUDCom is '" << XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode(dtv->getTypeName()) << "'" << endl; if(XPath2Utils::equals(uriToCheck, dtv->getTypeUri()) && XPath2Utils::equals(typeNameToCheck, dtv->getTypeLocalName())) return true; dtv = dtv->getBaseValidator(); } } } } return false; } // if we are here, the type is a simple type if( (XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(typeNameToCheck, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_ANYSIMPLETYPE) && XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(uriToCheck, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA) ) || (XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(typeNameToCheck, AnyAtomicType::fgDT_ANYATOMICTYPE) && XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(uriToCheck, FunctionConstructor::XMLChXPath2DatatypesURI) ) ) return true; XERCES_CPP_NAMESPACE_QUALIFIER DatatypeValidator* dtvBase=_parser.getGrammarResolver()->getDatatypeValidator(uriToCheck,typeNameToCheck); if(dtvBase==NULL) return false; while(dtvDerived != 0) { if(XPath2Utils::equals(dtvBase->getTypeUri(), dtvDerived->getTypeUri()) && XPath2Utils::equals(dtvBase->getTypeLocalName(), dtvDerived->getTypeLocalName())) return true; dtvDerived = dtvDerived->getBaseValidator(); } // if we are here, the type is a type if(XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(uriToCheck, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA) && XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(typeNameToCheck, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgATTVAL_ANYTYPE)) return true; return false; } void DocumentCacheImpl::addSchemaLocation(const XMLCh* uri, const XMLCh* location, StaticContext *context) { // TODO: add a catalog thing if(location==NULL) return; try { _parser.loadSchema(location, context); } catch(const XERCES_CPP_NAMESPACE_QUALIFIER SAXException& toCatch) { DSLthrow(ContextException,X("DocumentCacheImpl::addSchemaLocation"), toCatch.getMessage()); } catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException& toCatch) { DSLthrow(ContextException,X("DocumentCacheImpl::addSchemaLocation"), toCatch.msg); } catch(const XERCES_CPP_NAMESPACE_QUALIFIER XMLException& toCatch) { DSLthrow(ContextException,X("DocumentCacheImpl::addSchemaLocation"), toCatch.getMessage()); } } unsigned int DocumentCacheImpl::getSchemaUriId(const XMLCh* uri) const { return _parser.getSchemaUriId(uri); } const XMLCh* DocumentCacheImpl::getSchemaUri(unsigned int id) const { return _parser.getSchemaUri(id); } XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *DocumentCacheImpl::validate(const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node, DocumentCache::ValidationMode valMode, ValidationContext valContext, StaticContext *context) { return _parser.validate(node, valMode, valContext, context); } ValidationContext DocumentCacheImpl::updateValidationContext(ValidationContext current,QualifiedName* step,bool bIsElement,StaticContext* context) const { return _parser.updateValidationContext(current,step,bIsElement,context); } XERCES_CPP_NAMESPACE_QUALIFIER DatatypeValidator* DocumentCacheImpl::getDatatypeValidator(const XMLCh* uri, const XMLCh* typeName) const { return _parser.getGrammarResolver()->getDatatypeValidator(uri,typeName); } XERCES_CPP_NAMESPACE_QUALIFIER ComplexTypeInfo* DocumentCacheImpl::getComplexTypeInfo(const XMLCh* uri, const XMLCh* typeName) const { XERCES_CPP_NAMESPACE_QUALIFIER Grammar* grammar=_parser.getGrammarResolver()->getGrammar(uri); if(grammar==NULL) return NULL; if(grammar->getGrammarType()!=XERCES_CPP_NAMESPACE_QUALIFIER Grammar::SchemaGrammarType) return NULL; XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar* schGrammar=(XERCES_CPP_NAMESPACE_QUALIFIER SchemaGrammar*)grammar; XERCES_CPP_NAMESPACE_QUALIFIER RefHashTableOf *ctr = schGrammar->getComplexTypeRegistry(); if(ctr==NULL) return NULL; XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer typeKey(1023, _memMgr); typeKey.set(uri); typeKey.append(XERCES_CPP_NAMESPACE_QUALIFIER chComma); typeKey.append(typeName); return ctr->get(typeKey.getRawBuffer()); } DocumentCache *DocumentCacheImpl::createDerivedCache(XPath2MemoryManager *memMgr) const { // lock the grammar pool, so we can share it accross threads _parser.getGrammarResolver()->getGrammarPool()->lockPool(); // Construct a new DocumentCacheImpl, based on this one return new (memMgr) DocumentCacheImpl(this, memMgr); }