GME  13
XSDDOMParser.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00024 // ---------------------------------------------------------------------------
00025 //  Includes
00026 // ---------------------------------------------------------------------------
00027 #include <xercesc/validators/schema/XSDDOMParser.hpp>
00028 #include <xercesc/validators/schema/SchemaSymbols.hpp>
00029 #include <xercesc/internal/XMLScanner.hpp>
00030 #include <xercesc/internal/ElemStack.hpp>
00031 #include <xercesc/dom/DOMDocument.hpp>
00032 #include <xercesc/dom/impl/DOMElementImpl.hpp>
00033 #include <xercesc/dom/impl/DOMAttrImpl.hpp>
00034 #include <xercesc/dom/impl/DOMTextImpl.hpp>
00035 #include <xercesc/framework/XMLValidityCodes.hpp>
00036 
00037 XERCES_CPP_NAMESPACE_BEGIN
00038 
00039 // ---------------------------------------------------------------------------
00040 //  XSDDOMParser: Constructors and Destructor
00041 // ---------------------------------------------------------------------------
00042 XSDDOMParser::XSDDOMParser( XMLValidator* const   valToAdopt
00043                           , MemoryManager* const  manager
00044                           , XMLGrammarPool* const gramPool):
00045     XercesDOMParser(valToAdopt, manager, gramPool)
00046     , fSawFatal(false)
00047     , fAnnotationDepth(-1)
00048     , fInnerAnnotationDepth(-1)
00049     , fDepth(-1)
00050     , fUserErrorReporter(0)
00051     , fUserEntityHandler(0)
00052     , fURIs(0)
00053     , fAnnotationBuf(1023, manager)
00054 
00055 {
00056     fURIs = new (manager) ValueVectorOf<unsigned int>(16, manager);
00057     fXSDErrorReporter.setErrorReporter(this);
00058     setValidationScheme(XercesDOMParser::Val_Never);
00059     setDoNamespaces(true);
00060 }
00061 
00062 
00063 XSDDOMParser::~XSDDOMParser()
00064 {
00065     delete fURIs;
00066 }
00067 
00068 
00069 // ---------------------------------------------------------------------------
00070 //  XSDDOMParser: Helper methods
00071 // ---------------------------------------------------------------------------
00072 DOMElement* XSDDOMParser::createElementNSNode(const XMLCh *namespaceURI,
00073                                               const XMLCh *qualifiedName)
00074 {
00075     ReaderMgr::LastExtEntityInfo lastInfo;
00076     ((ReaderMgr*) fScanner->getLocator())->getLastExtEntityInfo(lastInfo);
00077 
00078     return getDocument()->createElementNS(namespaceURI, qualifiedName,
00079                                           lastInfo.lineNumber, lastInfo.colNumber);
00080 }
00081 
00082 
00083 void XSDDOMParser::startAnnotation( const XMLElementDecl&       elemDecl
00084                                   , const RefVectorOf<XMLAttr>& attrList
00085                                   , const XMLSize_t             attrCount)
00086 {
00087     fAnnotationBuf.append(chOpenAngle);
00088         fAnnotationBuf.append(elemDecl.getFullName());
00089     fAnnotationBuf.append(chSpace);
00090 
00091     // attributes are a bit of a pain.  To get this right, we have to keep track
00092     // of the namespaces we've seen declared, then examine the namespace context
00093     // for other namespaces so that we can also include them.
00094     // optimized for simplicity and the case that not many
00095     // namespaces are declared on this annotation...
00096     fURIs->removeAllElements();
00097     for (XMLSize_t i=0; i < attrCount; i++) {
00098 
00099         const XMLAttr* oneAttrib = attrList.elementAt(i);
00100         const XMLCh* attrValue = oneAttrib->getValue();
00101 
00102         if (XMLString::equals(oneAttrib->getName(), XMLUni::fgXMLNSString))
00103             fURIs->addElement(fScanner->getPrefixId(XMLUni::fgZeroLenString));
00104         else  if (!XMLString::compareNString(oneAttrib->getQName(), XMLUni::fgXMLNSColonString, 6))
00105             fURIs->addElement(fScanner->getPrefixId(oneAttrib->getName()));
00106 
00107         fAnnotationBuf.append(oneAttrib->getQName());
00108         fAnnotationBuf.append(chEqual);
00109         fAnnotationBuf.append(chDoubleQuote);
00110         fAnnotationBuf.append(attrValue);
00111         fAnnotationBuf.append(chDoubleQuote);
00112         fAnnotationBuf.append(chSpace);
00113     }
00114 
00115     // now we have to look through currently in-scope namespaces to see what
00116     // wasn't declared here
00117     ValueVectorOf<PrefMapElem*>* namespaceContext = fScanner->getNamespaceContext();
00118     for (XMLSize_t j=0; j < namespaceContext->size(); j++)
00119     {
00120         unsigned int prefId = namespaceContext->elementAt(j)->fPrefId;
00121 
00122         if (!fURIs->containsElement(prefId)) {
00123 
00124             const XMLCh* prefix = fScanner->getPrefixForId(prefId);
00125 
00126             if (XMLString::equals(prefix, XMLUni::fgZeroLenString)) {
00127                 fAnnotationBuf.append(XMLUni::fgXMLNSString);
00128             }
00129             else  {
00130                 fAnnotationBuf.append(XMLUni::fgXMLNSColonString);
00131                 fAnnotationBuf.append(prefix);
00132             }
00133 
00134             fAnnotationBuf.append(chEqual);
00135             fAnnotationBuf.append(chDoubleQuote);
00136             fAnnotationBuf.append(fScanner->getURIText(namespaceContext->elementAt(j)->fURIId));
00137             fAnnotationBuf.append(chDoubleQuote);
00138             fAnnotationBuf.append(chSpace);
00139 
00140             fURIs->addElement(prefId);
00141         }
00142     }
00143 
00144     fAnnotationBuf.append(chCloseAngle);
00145     fAnnotationBuf.append(chLF);
00146 }
00147 
00148 void XSDDOMParser::startAnnotationElement( const XMLElementDecl&       elemDecl
00149                                          , const RefVectorOf<XMLAttr>& attrList
00150                                          , const XMLSize_t             attrCount)
00151 {
00152     fAnnotationBuf.append(chOpenAngle);
00153     fAnnotationBuf.append(elemDecl.getFullName());
00154     //fAnnotationBuf.append(chSpace);
00155 
00156     for(XMLSize_t i=0; i < attrCount; i++) {
00157 
00158         const XMLAttr* oneAttr = attrList.elementAt(i);
00159         fAnnotationBuf.append(chSpace);
00160         fAnnotationBuf.append(oneAttr ->getQName());
00161         fAnnotationBuf.append(chEqual);
00162         fAnnotationBuf.append(chDoubleQuote);
00163         fAnnotationBuf.append(oneAttr->getValue());
00164         fAnnotationBuf.append(chDoubleQuote);
00165     }
00166 
00167     fAnnotationBuf.append(chCloseAngle);
00168 }
00169 
00170 void XSDDOMParser::endAnnotationElement( const XMLElementDecl& elemDecl
00171                                        , bool complete)
00172 {
00173     if (complete)
00174     {
00175         fAnnotationBuf.append(chLF);
00176         fAnnotationBuf.append(chOpenAngle);
00177         fAnnotationBuf.append(chForwardSlash);
00178         fAnnotationBuf.append(elemDecl.getFullName());
00179         fAnnotationBuf.append(chCloseAngle);
00180 
00181         // note that this is always called after endElement on <annotation>'s
00182         // child and before endElement on annotation.
00183         // hence, we must make this the child of the current
00184         // parent's only child.
00185         DOMTextImpl *node = (DOMTextImpl *)fDocument->createTextNode(fAnnotationBuf.getRawBuffer());
00186         fCurrentNode->appendChild(node);
00187         fAnnotationBuf.reset();
00188     }
00189     else      //capturing character calls
00190     {
00191         fAnnotationBuf.append(chOpenAngle);
00192         fAnnotationBuf.append(chForwardSlash);
00193         fAnnotationBuf.append(elemDecl.getFullName());
00194         fAnnotationBuf.append(chCloseAngle);
00195     }
00196 }
00197 
00198 
00199 // ---------------------------------------------------------------------------
00200 //  XSDDOMParser: Setter methods
00201 // ---------------------------------------------------------------------------
00202 void XSDDOMParser::setUserErrorReporter(XMLErrorReporter* const errorReporter)
00203 {
00204     fUserErrorReporter = errorReporter;
00205     fScanner->setErrorReporter(this);
00206 }
00207 
00208 void XSDDOMParser::setUserEntityHandler(XMLEntityHandler* const entityHandler)
00209 {
00210     fUserEntityHandler = entityHandler;
00211     fScanner->setEntityHandler(this);
00212 }
00213 
00214 
00215 // ---------------------------------------------------------------------------
00216 //  XSDDOMParser: Implementation of the XMLDocumentHandler interface
00217 // ---------------------------------------------------------------------------
00218 void XSDDOMParser::startElement( const XMLElementDecl&       elemDecl
00219                                , const unsigned int          urlId
00220                                , const XMLCh* const          elemPrefix
00221                                , const RefVectorOf<XMLAttr>& attrList
00222                                , const XMLSize_t             attrCount
00223                                , const bool                  isEmpty
00224                                , const bool                  isRoot)
00225 {
00226     fDepth++;
00227 
00228     // while it is true that non-whitespace character data
00229     // may only occur in appInfo or documentation
00230     // elements, it's certainly legal for comments and PI's to
00231     // occur as children of annotation; we need
00232     // to account for these here.
00233     if (fAnnotationDepth == -1)
00234     {
00235         if (XMLString::equals(elemDecl.getBaseName(), SchemaSymbols::fgELT_ANNOTATION) &&
00236             XMLString::equals(getURIText(urlId), SchemaSymbols::fgURI_SCHEMAFORSCHEMA))
00237         {
00238 
00239             fAnnotationDepth = fDepth;
00240             startAnnotation(elemDecl, attrList, attrCount);
00241         }
00242     }
00243     else if (fDepth == fAnnotationDepth+1)
00244     {
00245         fInnerAnnotationDepth = fDepth;
00246         startAnnotationElement(elemDecl, attrList, attrCount);
00247     }
00248     else
00249     {
00250         startAnnotationElement(elemDecl, attrList, attrCount);
00251         if(isEmpty)
00252             endElement(elemDecl, urlId, isRoot, elemPrefix);
00253         // avoid falling through; don't call startElement in this case
00254         return;
00255     }
00256 
00257     DOMElement *elem;
00258     if (urlId != fScanner->getEmptyNamespaceId())  //TagName has a prefix
00259     {
00260         if (elemPrefix && *elemPrefix)
00261         {
00262             XMLBufBid elemQName(&fBufMgr);
00263             elemQName.set(elemPrefix);
00264             elemQName.append(chColon);
00265             elemQName.append(elemDecl.getBaseName());
00266             elem = createElementNSNode(
00267                 fScanner->getURIText(urlId), elemQName.getRawBuffer());
00268         }
00269         else {
00270             elem = createElementNSNode(
00271                 fScanner->getURIText(urlId), elemDecl.getBaseName());
00272         }
00273     }
00274     else {
00275         elem = createElementNSNode(0, elemDecl.getBaseName());
00276     }
00277 
00278     DOMElementImpl *elemImpl = (DOMElementImpl *) elem;
00279     for (XMLSize_t index = 0; index < attrCount; ++index)
00280     {
00281         const XMLAttr* oneAttrib = attrList.elementAt(index);
00282         unsigned int attrURIId = oneAttrib->getURIId();
00283         const XMLCh* namespaceURI = 0;
00284 
00285         //for xmlns=...
00286         if (XMLString::equals(oneAttrib->getName(), XMLUni::fgXMLNSString))
00287             attrURIId = fScanner->getXMLNSNamespaceId();
00288 
00289         //TagName has a prefix
00290         if (attrURIId != fScanner->getEmptyNamespaceId())
00291             namespaceURI = fScanner->getURIText(attrURIId); //get namespaceURI
00292 
00293         //  revisit.  Optimize to init the named node map to the
00294         //            right size up front.
00295         DOMAttrImpl *attr = (DOMAttrImpl *)
00296             fDocument->createAttributeNS(namespaceURI, oneAttrib->getQName());
00297         attr->setValue(oneAttrib -> getValue());
00298         DOMNode* remAttr = elemImpl->setAttributeNodeNS(attr);
00299         if (remAttr)
00300             remAttr->release();
00301 
00302         // Attributes of type ID.  If this is one, add it to the hashtable of IDs
00303         //   that is constructed for use by GetElementByID().
00304         if (oneAttrib->getType()==XMLAttDef::ID)
00305         {
00306             if (fDocument->fNodeIDMap == 0)
00307                 fDocument->fNodeIDMap = new (fDocument) DOMNodeIDMap(500, fDocument);
00308             fDocument->fNodeIDMap->add(attr);
00309             attr->fNode.isIdAttr(true);
00310         }
00311 
00312         attr->setSpecified(oneAttrib->getSpecified());
00313     }
00314 
00315     // set up the default attributes
00316     if (elemDecl.hasAttDefs())
00317         {
00318         XMLAttDefList* defAttrs = &elemDecl.getAttDefList();
00319         XMLAttDef* attr = 0;
00320         DOMAttrImpl * insertAttr = 0;
00321 
00322         for (XMLSize_t i=0; i<defAttrs->getAttDefCount(); i++)
00323         {
00324             attr = &defAttrs->getAttDef(i);
00325 
00326             const XMLAttDef::DefAttTypes defType = attr->getDefaultType();
00327             if ((defType == XMLAttDef::Default)
00328             ||  (defType == XMLAttDef::Fixed))
00329             {
00330                 // DOM Level 2 wants all namespace declaration attributes
00331                 // to be bound to "http://www.w3.org/2000/xmlns/"
00332                 // So as long as the XML parser doesn't do it, it needs to
00333                 // done here.
00334                 const XMLCh* qualifiedName = attr->getFullName();
00335                 XMLBufBid bbPrefixQName(&fBufMgr);
00336                 XMLBuffer& prefixBuf = bbPrefixQName.getBuffer();
00337                 int colonPos = -1;
00338                 unsigned int uriId = fScanner->resolveQName(qualifiedName, prefixBuf, ElemStack::Mode_Attribute, colonPos);
00339 
00340                 const XMLCh* namespaceURI = 0;
00341                 if (XMLString::equals(qualifiedName, XMLUni::fgXMLNSString))
00342                     uriId = fScanner->getXMLNSNamespaceId();
00343 
00344                 //TagName has a prefix
00345                 if (uriId != fScanner->getEmptyNamespaceId())
00346                     namespaceURI = fScanner->getURIText(uriId);
00347 
00348                 insertAttr = (DOMAttrImpl *) fDocument->createAttributeNS(
00349                     namespaceURI, qualifiedName);
00350 
00351                 DOMAttr* remAttr = elemImpl->setDefaultAttributeNodeNS(insertAttr);
00352                 if (remAttr)
00353                     remAttr->release();
00354 
00355                 if (attr->getValue() != 0)
00356                 {
00357                     insertAttr->setValue(attr->getValue());
00358                     insertAttr->setSpecified(false);
00359                 }
00360             }
00361 
00362             insertAttr = 0;
00363             attr->reset();
00364         }
00365     }
00366 
00367     fCurrentParent->appendChild(elem);
00368     fCurrentParent = elem;
00369     fCurrentNode = elem;
00370     fWithinElement = true;
00371 
00372     // If an empty element, do end right now (no endElement() will be called)
00373     if (isEmpty)
00374         endElement(elemDecl, urlId, isRoot, elemPrefix);
00375 }
00376 
00377 
00378 
00379 void XSDDOMParser::endElement( const XMLElementDecl& elemDecl
00380                              , const unsigned int
00381                              , const bool
00382                              , const XMLCh* const)
00383 {
00384     if(fAnnotationDepth > -1)
00385     {
00386         if (fInnerAnnotationDepth == fDepth)
00387         {
00388             fInnerAnnotationDepth = -1;
00389             endAnnotationElement(elemDecl, false);
00390             }
00391         else if (fAnnotationDepth == fDepth)
00392         {
00393             fAnnotationDepth = -1;
00394             endAnnotationElement(elemDecl, true);
00395         }
00396         else
00397         {   // inside a child of annotation
00398             endAnnotationElement(elemDecl, false);
00399             fDepth--;
00400             return;
00401         }
00402     }
00403 
00404     fDepth--;
00405     fCurrentNode   = fCurrentParent;
00406     fCurrentParent = fCurrentNode->getParentNode ();
00407 
00408     // If we've hit the end of content, clear the flag.
00409     //
00410     if (fCurrentParent == fDocument)
00411         fWithinElement = false;
00412 }
00413 
00414 void XSDDOMParser::docCharacters(  const   XMLCh* const    chars
00415                               , const XMLSize_t       length
00416                               , const bool            cdataSection)
00417 {
00418     // Ignore chars outside of content
00419     if (!fWithinElement)
00420         return;
00421 
00422     if (fInnerAnnotationDepth == -1)
00423     {
00424         if (!((ReaderMgr*) fScanner->getReaderMgr())->getCurrentReader()->isAllSpaces(chars, length))
00425         {
00426             ReaderMgr::LastExtEntityInfo lastInfo;
00427             fScanner->getReaderMgr()->getLastExtEntityInfo(lastInfo);
00428             fXSLocator.setValues(lastInfo.systemId, lastInfo.publicId, lastInfo.lineNumber, lastInfo.colNumber);
00429             fXSDErrorReporter.emitError(XMLValid::NonWSContent, XMLUni::fgValidityDomain, &fXSLocator);
00430         }
00431     }
00432     // when it's within either of the 2 annotation subelements, characters are
00433     // allowed and we need to store them.
00434     else if (cdataSection == true)
00435     {
00436         fAnnotationBuf.append(XMLUni::fgCDataStart);
00437         fAnnotationBuf.append(chars, length);
00438         fAnnotationBuf.append(XMLUni::fgCDataEnd);
00439     }
00440     else
00441     {
00442         for(unsigned int i = 0; i < length; i++ )
00443         {
00444             if(chars[i] == chAmpersand)
00445             {
00446                 fAnnotationBuf.append(chAmpersand);
00447                 fAnnotationBuf.append(XMLUni::fgAmp);
00448                 fAnnotationBuf.append(chSemiColon);
00449             }
00450             else if (chars[i] == chOpenAngle)
00451             {
00452                 fAnnotationBuf.append(chAmpersand);
00453                 fAnnotationBuf.append(XMLUni::fgLT);
00454                 fAnnotationBuf.append(chSemiColon);
00455             }
00456             else {
00457                 fAnnotationBuf.append(chars[i]);
00458             }
00459         }
00460     }
00461 }
00462 
00463 void XSDDOMParser::docComment(const XMLCh* const comment)
00464 {
00465     if (fAnnotationDepth > -1)
00466     {
00467         fAnnotationBuf.append(XMLUni::fgCommentString);
00468         fAnnotationBuf.append(comment);
00469         fAnnotationBuf.append(chDash);
00470         fAnnotationBuf.append(chDash);
00471         fAnnotationBuf.append(chCloseAngle);
00472     }
00473 }
00474 
00475 void XSDDOMParser::startEntityReference(const XMLEntityDecl&)
00476 {
00477 }
00478 
00479 void XSDDOMParser::endEntityReference(const XMLEntityDecl&)
00480 {
00481 }
00482 
00483 void XSDDOMParser::ignorableWhitespace( const XMLCh* const chars
00484                                       , const XMLSize_t    length
00485                                       , const bool)
00486 {
00487     // Ignore chars before the root element
00488     if (!fWithinElement || !fIncludeIgnorableWhitespace)
00489         return;
00490 
00491     if (fAnnotationDepth > -1)
00492         fAnnotationBuf.append(chars, length);
00493 }
00494 
00495 // ---------------------------------------------------------------------------
00496 //  XSDDOMParser: Implementation of the XMLErrorReporter interface
00497 // ---------------------------------------------------------------------------
00498 void XSDDOMParser::error(const   unsigned int                code
00499                          , const XMLCh* const                msgDomain
00500                          , const XMLErrorReporter::ErrTypes  errType
00501                          , const XMLCh* const                errorText
00502                          , const XMLCh* const                systemId
00503                          , const XMLCh* const                publicId
00504                          , const XMLFileLoc                  lineNum
00505                          , const XMLFileLoc                  colNum)
00506 {
00507     if (errType >= XMLErrorReporter::ErrType_Fatal)
00508         fSawFatal = true;
00509 
00510     if (fUserErrorReporter)
00511         fUserErrorReporter->error(code, msgDomain, errType, errorText,
00512                                   systemId, publicId, lineNum, colNum);
00513 }
00514 
00515 InputSource*
00516 XSDDOMParser::resolveEntity(XMLResourceIdentifier* resourceIdentifier)
00517 {
00518     if (fUserEntityHandler)
00519         return fUserEntityHandler->resolveEntity(resourceIdentifier);
00520 
00521     return 0;
00522 }
00523 
00524 XERCES_CPP_NAMESPACE_END