| /* |
| * 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: XSDDOMParser.cpp 568078 2007-08-21 11:43:25Z amassari $ |
| */ |
| |
| |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #include <xercesc/validators/schema/XSDDOMParser.hpp> |
| #include <xercesc/validators/schema/SchemaSymbols.hpp> |
| #include <xercesc/internal/XMLScanner.hpp> |
| #include <xercesc/internal/ElemStack.hpp> |
| #include <xercesc/dom/DOMDocument.hpp> |
| #include <xercesc/dom/impl/DOMElementImpl.hpp> |
| #include <xercesc/dom/impl/DOMAttrImpl.hpp> |
| #include <xercesc/dom/impl/DOMTextImpl.hpp> |
| #include <xercesc/framework/XMLValidityCodes.hpp> |
| |
| 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<unsigned int>(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<XMLAttr>& attrList |
| , const unsigned int 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 (unsigned int 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<PrefMapElem*>* namespaceContext = fScanner->getNamespaceContext(); |
| for (unsigned int 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); |
| } |
| } |
| |
| fAnnotationBuf.append(chCloseAngle); |
| fAnnotationBuf.append(chLF); |
| } |
| |
| void XSDDOMParser::startAnnotationElement( const XMLElementDecl& elemDecl |
| , const RefVectorOf<XMLAttr>& attrList |
| , const unsigned int attrCount) |
| { |
| fAnnotationBuf.append(chOpenAngle); |
| fAnnotationBuf.append(elemDecl.getFullName()); |
| //fAnnotationBuf.append(chSpace); |
| |
| for(unsigned int 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 <annotation>'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<XMLAttr>& attrList |
| , const unsigned int 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 (unsigned int 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 (unsigned int i=0; i<defAttrs->getAttDefCount(); 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); |
| fNodeStack->push(fCurrentParent); |
| 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 = fNodeStack->pop(); |
| |
| // If we've hit the end of content, clear the flag |
| if (fNodeStack->empty()) |
| fWithinElement = false; |
| } |
| |
| void XSDDOMParser::docCharacters( const XMLCh* const chars |
| , const unsigned int 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 unsigned int 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 XMLSSize_t lineNum |
| , const XMLSSize_t colNum) |
| { |
| if (errType >= XMLErrorReporter::ErrType_Fatal) |
| fSawFatal = true; |
| |
| if (fUserErrorReporter) |
| fUserErrorReporter->error(code, msgDomain, errType, errorText, |
| systemId, publicId, lineNum, colNum); |
| } |
| |
| InputSource* XSDDOMParser::resolveEntity(const XMLCh* const publicId, |
| const XMLCh* const systemId, |
| const XMLCh* const baseURI) |
| { |
| if (fUserEntityHandler) |
| return fUserEntityHandler->resolveEntity(publicId, systemId, baseURI); |
| |
| return 0; |
| } |
| |
| InputSource* |
| XSDDOMParser::resolveEntity(XMLResourceIdentifier* resourceIdentifier) |
| { |
| if (fUserEntityHandler) |
| return fUserEntityHandler->resolveEntity(resourceIdentifier); |
| |
| return 0; |
| } |
| |
| XERCES_CPP_NAMESPACE_END |