/* * 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 #include #include #include #include #include #include #include #include XERCES_CPP_NAMESPACE_BEGIN // --------------------------------------------------------------------------- // XSDDOMParser: Constructors and Destructor // --------------------------------------------------------------------------- XSDDOMParser::XSDDOMParser( XMLValidator* const valToAdopt , MemoryManager* const manager , XMLGrammarPool* const gramPool): XercesDOMParser(valToAdopt, manager, gramPool) , fSawFatal(false) , fAnnotationDepth(-1) , fInnerAnnotationDepth(-1) , fDepth(-1) , fUserErrorReporter(0) , fUserEntityHandler(0) , fURIs(0) , fAnnotationBuf(1023, manager) { fURIs = new (manager) ValueVectorOf(16, manager); fXSDErrorReporter.setErrorReporter(this); setValidationScheme(XercesDOMParser::Val_Never); setDoNamespaces(true); } XSDDOMParser::~XSDDOMParser() { delete fURIs; } // --------------------------------------------------------------------------- // XSDDOMParser: Helper methods // --------------------------------------------------------------------------- DOMElement* XSDDOMParser::createElementNSNode(const XMLCh *namespaceURI, const XMLCh *qualifiedName) { ReaderMgr::LastExtEntityInfo lastInfo; ((ReaderMgr*) fScanner->getLocator())->getLastExtEntityInfo(lastInfo); return getDocument()->createElementNS(namespaceURI, qualifiedName, lastInfo.lineNumber, lastInfo.colNumber); } void XSDDOMParser::startAnnotation( const XMLElementDecl& elemDecl , const RefVectorOf& attrList , const XMLSize_t attrCount) { fAnnotationBuf.append(chOpenAngle); fAnnotationBuf.append(elemDecl.getFullName()); fAnnotationBuf.append(chSpace); // attributes are a bit of a pain. To get this right, we have to keep track // of the namespaces we've seen declared, then examine the namespace context // for other namespaces so that we can also include them. // optimized for simplicity and the case that not many // namespaces are declared on this annotation... fURIs->removeAllElements(); for (XMLSize_t i=0; i < attrCount; i++) { const XMLAttr* oneAttrib = attrList.elementAt(i); const XMLCh* attrValue = oneAttrib->getValue(); if (XMLString::equals(oneAttrib->getName(), XMLUni::fgXMLNSString)) fURIs->addElement(fScanner->getPrefixId(XMLUni::fgZeroLenString)); else if (!XMLString::compareNString(oneAttrib->getQName(), XMLUni::fgXMLNSColonString, 6)) fURIs->addElement(fScanner->getPrefixId(oneAttrib->getName())); fAnnotationBuf.append(oneAttrib->getQName()); fAnnotationBuf.append(chEqual); fAnnotationBuf.append(chDoubleQuote); fAnnotationBuf.append(attrValue); fAnnotationBuf.append(chDoubleQuote); fAnnotationBuf.append(chSpace); } // now we have to look through currently in-scope namespaces to see what // wasn't declared here ValueVectorOf* namespaceContext = fScanner->getNamespaceContext(); for (XMLSize_t j=0; j < namespaceContext->size(); j++) { unsigned int prefId = namespaceContext->elementAt(j)->fPrefId; if (!fURIs->containsElement(prefId)) { const XMLCh* prefix = fScanner->getPrefixForId(prefId); if (XMLString::equals(prefix, XMLUni::fgZeroLenString)) { fAnnotationBuf.append(XMLUni::fgXMLNSString); } else { fAnnotationBuf.append(XMLUni::fgXMLNSColonString); fAnnotationBuf.append(prefix); } fAnnotationBuf.append(chEqual); fAnnotationBuf.append(chDoubleQuote); fAnnotationBuf.append(fScanner->getURIText(namespaceContext->elementAt(j)->fURIId)); fAnnotationBuf.append(chDoubleQuote); fAnnotationBuf.append(chSpace); fURIs->addElement(prefId); } } fAnnotationBuf.append(chCloseAngle); fAnnotationBuf.append(chLF); } void XSDDOMParser::startAnnotationElement( const XMLElementDecl& elemDecl , const RefVectorOf& attrList , const XMLSize_t attrCount) { fAnnotationBuf.append(chOpenAngle); fAnnotationBuf.append(elemDecl.getFullName()); //fAnnotationBuf.append(chSpace); for(XMLSize_t i=0; i < attrCount; i++) { const XMLAttr* oneAttr = attrList.elementAt(i); fAnnotationBuf.append(chSpace); fAnnotationBuf.append(oneAttr ->getQName()); fAnnotationBuf.append(chEqual); fAnnotationBuf.append(chDoubleQuote); fAnnotationBuf.append(oneAttr->getValue()); fAnnotationBuf.append(chDoubleQuote); } fAnnotationBuf.append(chCloseAngle); } void XSDDOMParser::endAnnotationElement( const XMLElementDecl& elemDecl , bool complete) { if (complete) { fAnnotationBuf.append(chLF); fAnnotationBuf.append(chOpenAngle); fAnnotationBuf.append(chForwardSlash); fAnnotationBuf.append(elemDecl.getFullName()); fAnnotationBuf.append(chCloseAngle); // note that this is always called after endElement on 's // child and before endElement on annotation. // hence, we must make this the child of the current // parent's only child. DOMTextImpl *node = (DOMTextImpl *)fDocument->createTextNode(fAnnotationBuf.getRawBuffer()); fCurrentNode->appendChild(node); fAnnotationBuf.reset(); } else //capturing character calls { fAnnotationBuf.append(chOpenAngle); fAnnotationBuf.append(chForwardSlash); fAnnotationBuf.append(elemDecl.getFullName()); fAnnotationBuf.append(chCloseAngle); } } // --------------------------------------------------------------------------- // XSDDOMParser: Setter methods // --------------------------------------------------------------------------- void XSDDOMParser::setUserErrorReporter(XMLErrorReporter* const errorReporter) { fUserErrorReporter = errorReporter; fScanner->setErrorReporter(this); } void XSDDOMParser::setUserEntityHandler(XMLEntityHandler* const entityHandler) { fUserEntityHandler = entityHandler; fScanner->setEntityHandler(this); } // --------------------------------------------------------------------------- // XSDDOMParser: Implementation of the XMLDocumentHandler interface // --------------------------------------------------------------------------- void XSDDOMParser::startElement( const XMLElementDecl& elemDecl , const unsigned int urlId , const XMLCh* const elemPrefix , const RefVectorOf& attrList , const XMLSize_t attrCount , const bool isEmpty , const bool isRoot) { fDepth++; // while it is true that non-whitespace character data // may only occur in appInfo or documentation // elements, it's certainly legal for comments and PI's to // occur as children of annotation; we need // to account for these here. if (fAnnotationDepth == -1) { if (XMLString::equals(elemDecl.getBaseName(), SchemaSymbols::fgELT_ANNOTATION) && XMLString::equals(getURIText(urlId), SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { fAnnotationDepth = fDepth; startAnnotation(elemDecl, attrList, attrCount); } } else if (fDepth == fAnnotationDepth+1) { fInnerAnnotationDepth = fDepth; startAnnotationElement(elemDecl, attrList, attrCount); } else { startAnnotationElement(elemDecl, attrList, attrCount); if(isEmpty) endElement(elemDecl, urlId, isRoot, elemPrefix); // avoid falling through; don't call startElement in this case return; } DOMElement *elem; if (urlId != fScanner->getEmptyNamespaceId()) //TagName has a prefix { if (elemPrefix && *elemPrefix) { XMLBufBid elemQName(&fBufMgr); elemQName.set(elemPrefix); elemQName.append(chColon); elemQName.append(elemDecl.getBaseName()); elem = createElementNSNode( fScanner->getURIText(urlId), elemQName.getRawBuffer()); } else { elem = createElementNSNode( fScanner->getURIText(urlId), elemDecl.getBaseName()); } } else { elem = createElementNSNode(0, elemDecl.getBaseName()); } DOMElementImpl *elemImpl = (DOMElementImpl *) elem; for (XMLSize_t index = 0; index < attrCount; ++index) { const XMLAttr* oneAttrib = attrList.elementAt(index); unsigned int attrURIId = oneAttrib->getURIId(); const XMLCh* namespaceURI = 0; //for xmlns=... if (XMLString::equals(oneAttrib->getName(), XMLUni::fgXMLNSString)) attrURIId = fScanner->getXMLNSNamespaceId(); //TagName has a prefix if (attrURIId != fScanner->getEmptyNamespaceId()) namespaceURI = fScanner->getURIText(attrURIId); //get namespaceURI // revisit. Optimize to init the named node map to the // right size up front. DOMAttrImpl *attr = (DOMAttrImpl *) fDocument->createAttributeNS(namespaceURI, oneAttrib->getQName()); attr->setValue(oneAttrib -> getValue()); DOMNode* remAttr = elemImpl->setAttributeNodeNS(attr); if (remAttr) remAttr->release(); // Attributes of type ID. If this is one, add it to the hashtable of IDs // that is constructed for use by GetElementByID(). if (oneAttrib->getType()==XMLAttDef::ID) { if (fDocument->fNodeIDMap == 0) fDocument->fNodeIDMap = new (fDocument) DOMNodeIDMap(500, fDocument); fDocument->fNodeIDMap->add(attr); attr->fNode.isIdAttr(true); } attr->setSpecified(oneAttrib->getSpecified()); } // set up the default attributes if (elemDecl.hasAttDefs()) { XMLAttDefList* defAttrs = &elemDecl.getAttDefList(); XMLAttDef* attr = 0; DOMAttrImpl * insertAttr = 0; for (XMLSize_t i=0; igetAttDefCount(); i++) { attr = &defAttrs->getAttDef(i); const XMLAttDef::DefAttTypes defType = attr->getDefaultType(); if ((defType == XMLAttDef::Default) || (defType == XMLAttDef::Fixed)) { // DOM Level 2 wants all namespace declaration attributes // to be bound to "http://www.w3.org/2000/xmlns/" // So as long as the XML parser doesn't do it, it needs to // done here. const XMLCh* qualifiedName = attr->getFullName(); XMLBufBid bbPrefixQName(&fBufMgr); XMLBuffer& prefixBuf = bbPrefixQName.getBuffer(); int colonPos = -1; unsigned int uriId = fScanner->resolveQName(qualifiedName, prefixBuf, ElemStack::Mode_Attribute, colonPos); const XMLCh* namespaceURI = 0; if (XMLString::equals(qualifiedName, XMLUni::fgXMLNSString)) uriId = fScanner->getXMLNSNamespaceId(); //TagName has a prefix if (uriId != fScanner->getEmptyNamespaceId()) namespaceURI = fScanner->getURIText(uriId); insertAttr = (DOMAttrImpl *) fDocument->createAttributeNS( namespaceURI, qualifiedName); DOMAttr* remAttr = elemImpl->setDefaultAttributeNodeNS(insertAttr); if (remAttr) remAttr->release(); if (attr->getValue() != 0) { insertAttr->setValue(attr->getValue()); insertAttr->setSpecified(false); } } insertAttr = 0; attr->reset(); } } fCurrentParent->appendChild(elem); fCurrentParent = elem; fCurrentNode = elem; fWithinElement = true; // If an empty element, do end right now (no endElement() will be called) if (isEmpty) endElement(elemDecl, urlId, isRoot, elemPrefix); } void XSDDOMParser::endElement( const XMLElementDecl& elemDecl , const unsigned int , const bool , const XMLCh* const) { if(fAnnotationDepth > -1) { if (fInnerAnnotationDepth == fDepth) { fInnerAnnotationDepth = -1; endAnnotationElement(elemDecl, false); } else if (fAnnotationDepth == fDepth) { fAnnotationDepth = -1; endAnnotationElement(elemDecl, true); } else { // inside a child of annotation endAnnotationElement(elemDecl, false); fDepth--; return; } } fDepth--; fCurrentNode = fCurrentParent; fCurrentParent = fCurrentNode->getParentNode (); // If we've hit the end of content, clear the flag. // if (fCurrentParent == fDocument) fWithinElement = false; } void XSDDOMParser::docCharacters( const XMLCh* const chars , const XMLSize_t length , const bool cdataSection) { // Ignore chars outside of content if (!fWithinElement) return; if (fInnerAnnotationDepth == -1) { if (!((ReaderMgr*) fScanner->getReaderMgr())->getCurrentReader()->isAllSpaces(chars, length)) { ReaderMgr::LastExtEntityInfo lastInfo; fScanner->getReaderMgr()->getLastExtEntityInfo(lastInfo); fXSLocator.setValues(lastInfo.systemId, lastInfo.publicId, lastInfo.lineNumber, lastInfo.colNumber); fXSDErrorReporter.emitError(XMLValid::NonWSContent, XMLUni::fgValidityDomain, &fXSLocator); } } // when it's within either of the 2 annotation subelements, characters are // allowed and we need to store them. else if (cdataSection == true) { fAnnotationBuf.append(XMLUni::fgCDataStart); fAnnotationBuf.append(chars, length); fAnnotationBuf.append(XMLUni::fgCDataEnd); } else { for(unsigned int i = 0; i < length; i++ ) { if(chars[i] == chAmpersand) { fAnnotationBuf.append(chAmpersand); fAnnotationBuf.append(XMLUni::fgAmp); fAnnotationBuf.append(chSemiColon); } else if (chars[i] == chOpenAngle) { fAnnotationBuf.append(chAmpersand); fAnnotationBuf.append(XMLUni::fgLT); fAnnotationBuf.append(chSemiColon); } else { fAnnotationBuf.append(chars[i]); } } } } void XSDDOMParser::docComment(const XMLCh* const comment) { if (fAnnotationDepth > -1) { fAnnotationBuf.append(XMLUni::fgCommentString); fAnnotationBuf.append(comment); fAnnotationBuf.append(chDash); fAnnotationBuf.append(chDash); fAnnotationBuf.append(chCloseAngle); } } void XSDDOMParser::startEntityReference(const XMLEntityDecl&) { } void XSDDOMParser::endEntityReference(const XMLEntityDecl&) { } void XSDDOMParser::ignorableWhitespace( const XMLCh* const chars , const XMLSize_t length , const bool) { // Ignore chars before the root element if (!fWithinElement || !fIncludeIgnorableWhitespace) return; if (fAnnotationDepth > -1) fAnnotationBuf.append(chars, length); } // --------------------------------------------------------------------------- // XSDDOMParser: Implementation of the XMLErrorReporter interface // --------------------------------------------------------------------------- void XSDDOMParser::error(const unsigned int code , const XMLCh* const msgDomain , const XMLErrorReporter::ErrTypes errType , const XMLCh* const errorText , const XMLCh* const systemId , const XMLCh* const publicId , const XMLFileLoc lineNum , const XMLFileLoc colNum) { if (errType >= XMLErrorReporter::ErrType_Fatal) fSawFatal = true; if (fUserErrorReporter) fUserErrorReporter->error(code, msgDomain, errType, errorText, systemId, publicId, lineNum, colNum); } InputSource* XSDDOMParser::resolveEntity(XMLResourceIdentifier* resourceIdentifier) { if (fUserEntityHandler) return fUserEntityHandler->resolveEntity(resourceIdentifier); return 0; } XERCES_CPP_NAMESPACE_END