GME  13
XPathMatcher.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 
00018 /*
00019  * $Id: XPathMatcher.cpp 804234 2009-08-14 14:20:16Z amassari $
00020  */
00021 
00022 // ---------------------------------------------------------------------------
00023 //  Includes
00024 // ---------------------------------------------------------------------------
00025 #include <xercesc/validators/schema/identity/XPathMatcher.hpp>
00026 #include <xercesc/validators/schema/identity/XercesXPath.hpp>
00027 #include <xercesc/validators/schema/SchemaElementDecl.hpp>
00028 #include <xercesc/validators/schema/SchemaAttDef.hpp>
00029 #include <xercesc/validators/schema/SchemaSymbols.hpp>
00030 #include <xercesc/util/RuntimeException.hpp>
00031 #include <xercesc/util/OutOfMemoryException.hpp>
00032 #include <xercesc/framework/ValidationContext.hpp>
00033 
00034 XERCES_CPP_NAMESPACE_BEGIN
00035 
00036 typedef JanitorMemFunCall<XPathMatcher>     CleanupType;
00037 
00038 // ---------------------------------------------------------------------------
00039 //  XPathMatcher: Constructors and Destructor
00040 // ---------------------------------------------------------------------------
00041 XPathMatcher::XPathMatcher( XercesXPath* const xpath
00042                           , MemoryManager* const manager)
00043     : fLocationPathSize(0)
00044     , fMatched(0)
00045     , fNoMatchDepth(0)
00046     , fCurrentStep(0)
00047     , fStepIndexes(0)
00048     , fLocationPaths(0)
00049     , fIdentityConstraint(0)
00050     , fMemoryManager(manager)
00051 {
00052     CleanupType cleanup(this, &XPathMatcher::cleanUp);
00053 
00054     try {
00055         init(xpath);
00056     }
00057     catch(const OutOfMemoryException&)
00058     {
00059         cleanup.release();
00060 
00061         throw;
00062     }
00063 
00064     cleanup.release();
00065 }
00066 
00067 
00068 XPathMatcher::XPathMatcher(XercesXPath* const xpath,
00069                            IdentityConstraint* const ic,
00070                                                    MemoryManager* const manager)
00071     : fLocationPathSize(0)
00072     , fMatched(0)
00073     , fNoMatchDepth(0)
00074     , fCurrentStep(0)
00075     , fStepIndexes(0)
00076     , fLocationPaths(0)
00077     , fIdentityConstraint(ic)
00078     , fMemoryManager(manager)
00079 {
00080     CleanupType cleanup(this, &XPathMatcher::cleanUp);
00081 
00082     try {
00083         init(xpath);
00084     }
00085     catch(const OutOfMemoryException&)
00086     {
00087         cleanup.release();
00088 
00089         throw;
00090     }
00091 
00092     cleanup.release();
00093 }
00094 
00095 
00096 XPathMatcher::~XPathMatcher()
00097 {
00098     cleanUp();
00099 }
00100 
00101 // ---------------------------------------------------------------------------
00102 //  XPathMatcher: Helper methods
00103 // ---------------------------------------------------------------------------
00104 void XPathMatcher::init(XercesXPath* const xpath) {
00105 
00106     if (xpath) {
00107 
00108         fLocationPaths = xpath->getLocationPaths();
00109         fLocationPathSize = (fLocationPaths ? fLocationPaths->size() : 0);
00110 
00111         if (fLocationPathSize) {
00112 
00113             fStepIndexes = new (fMemoryManager) RefVectorOf<ValueStackOf<XMLSize_t> >(fLocationPathSize, true, fMemoryManager);
00114             fCurrentStep = (XMLSize_t*) fMemoryManager->allocate
00115             (
00116                 fLocationPathSize * sizeof(XMLSize_t)
00117             );//new int[fLocationPathSize];
00118             fNoMatchDepth = (XMLSize_t*) fMemoryManager->allocate
00119             (
00120                 fLocationPathSize * sizeof(XMLSize_t)
00121             );//new int[fLocationPathSize];
00122             fMatched = (unsigned char*) fMemoryManager->allocate
00123             (
00124                 fLocationPathSize * sizeof(unsigned char)
00125             );//new int[fLocationPathSize];
00126 
00127             for(XMLSize_t i=0; i < fLocationPathSize; i++) {
00128                 fStepIndexes->addElement(new (fMemoryManager) ValueStackOf<XMLSize_t>(8, fMemoryManager));
00129             }
00130         }
00131     }
00132 }
00133 
00134 
00135 // ---------------------------------------------------------------------------
00136 //  XPathMatcher: XMLDocumentHandler methods
00137 // ---------------------------------------------------------------------------
00138 void XPathMatcher::startDocumentFragment() {
00139 
00140     for(XMLSize_t i = 0; i < fLocationPathSize; i++) {
00141 
00142         fStepIndexes->elementAt(i)->removeAllElements();
00143         fCurrentStep[i] = 0;
00144         fNoMatchDepth[i] = 0;
00145         fMatched[i] = 0;
00146     }
00147 }
00148 
00149 void XPathMatcher::startElement(const XMLElementDecl& elemDecl,
00150                                 const unsigned int urlId,
00151                                 const XMLCh* const elemPrefix,
00152                                                                 const RefVectorOf<XMLAttr>& attrList,
00153                                 const XMLSize_t attrCount,
00154                                 ValidationContext* validationContext /*=0*/) {
00155 
00156     for (XMLSize_t i = 0; i < fLocationPathSize; i++) {
00157 
00158         // push context
00159         XMLSize_t startStep = fCurrentStep[i];
00160         fStepIndexes->elementAt(i)->push(startStep);
00161 
00162         // try next xpath, if not matching
00163         if ((fMatched[i] & XP_MATCHED_D) == XP_MATCHED || fNoMatchDepth[i] > 0) {
00164             fNoMatchDepth[i]++;
00165             continue;
00166         }
00167 
00168         if((fMatched[i] & XP_MATCHED_D) == XP_MATCHED_D) {
00169             fMatched[i] = XP_MATCHED_DP;
00170         }
00171 
00172         // consume self::node() steps
00173         XercesLocationPath* locPath = fLocationPaths->elementAt(i);
00174         XMLSize_t stepSize = locPath->getStepSize();
00175 
00176         while (fCurrentStep[i] < stepSize &&
00177                locPath->getStep(fCurrentStep[i])->getAxisType() == XercesStep::AxisType_SELF) {
00178             fCurrentStep[i]++;
00179         }
00180 
00181         if (fCurrentStep[i] == stepSize) {
00182 
00183             fMatched[i] = XP_MATCHED;
00184             continue;
00185         }
00186 
00187         // now if the current step is a descendant step, we let the next
00188         // step do its thing; if it fails, we reset ourselves
00189         // to look at this step for next time we're called.
00190         // so first consume all descendants:
00191         XMLSize_t descendantStep = fCurrentStep[i];
00192 
00193         while (fCurrentStep[i] < stepSize &&
00194                locPath->getStep(fCurrentStep[i])->getAxisType() == XercesStep::AxisType_DESCENDANT) {
00195             fCurrentStep[i]++;
00196         }
00197 
00198         bool sawDescendant = fCurrentStep[i] > descendantStep;
00199         if (fCurrentStep[i] == stepSize) {
00200 
00201             fNoMatchDepth[i]++;
00202             continue;
00203         }
00204 
00205         // match child::... step, if haven't consumed any self::node()
00206         if ((fCurrentStep[i] == startStep || fCurrentStep[i] > descendantStep) &&
00207             locPath->getStep(fCurrentStep[i])->getAxisType() == XercesStep::AxisType_CHILD) {
00208 
00209             XercesStep* step = locPath->getStep(fCurrentStep[i]);
00210             XercesNodeTest* nodeTest = step->getNodeTest();
00211 
00212             QName elemQName(elemPrefix, elemDecl.getElementName()->getLocalPart(), urlId, fMemoryManager);
00213             if (!matches(nodeTest, &elemQName)) {
00214 
00215                 if(fCurrentStep[i] > descendantStep) {
00216                     fCurrentStep[i] = descendantStep;
00217                     continue;
00218                 }
00219 
00220                 fNoMatchDepth[i]++;
00221                 continue;
00222             }
00223 
00224             fCurrentStep[i]++;
00225         }
00226 
00227         if (fCurrentStep[i] == stepSize) {
00228 
00229             if (sawDescendant) {
00230 
00231                 fCurrentStep[i] = descendantStep;
00232                 fMatched[i] = XP_MATCHED_D;
00233             }
00234             else {
00235                 fMatched[i] = XP_MATCHED;
00236             }
00237 
00238             continue;
00239         }
00240 
00241         // match attribute::... step
00242         if (fCurrentStep[i] < stepSize &&
00243             locPath->getStep(fCurrentStep[i])->getAxisType() == XercesStep::AxisType_ATTRIBUTE) {
00244 
00245             if (attrCount) {
00246 
00247                 XercesNodeTest* nodeTest = locPath->getStep(fCurrentStep[i])->getNodeTest();
00248 
00249                 for (XMLSize_t attrIndex = 0; attrIndex < attrCount; attrIndex++) {
00250 
00251                     const XMLAttr* curDef = attrList.elementAt(attrIndex);
00252 
00253                     if (matches(nodeTest, curDef->getAttName())) {
00254 
00255                         fCurrentStep[i]++;
00256 
00257                         if (fCurrentStep[i] == stepSize) {
00258 
00259                             fMatched[i] = XP_MATCHED_A;
00260 
00261                             SchemaAttDef* attDef = ((SchemaElementDecl&) elemDecl).getAttDef(curDef->getName(), curDef->getURIId());
00262                             DatatypeValidator* dv = (attDef) ? attDef->getDatatypeValidator() : 0;
00263                             const XMLCh* value = curDef->getValue();
00264                             // store QName using their Clark name
00265                             if(dv && dv->getType()==DatatypeValidator::QName)
00266                             {
00267                                 int index=XMLString::indexOf(value, chColon);
00268                                 if(index==-1)
00269                                     matched(value, dv, false);
00270                                 else
00271                                 {
00272                                     XMLBuffer buff(1023, fMemoryManager);
00273                                     buff.append(chOpenCurly);
00274                                     if(validationContext)
00275                                     {
00276                                         XMLCh* prefix=(XMLCh*)fMemoryManager->allocate((index+1)*sizeof(XMLCh));
00277                                         ArrayJanitor<XMLCh> janPrefix(prefix, fMemoryManager);
00278                                         XMLString::subString(prefix, value, 0, (XMLSize_t)index, fMemoryManager);
00279                                         buff.append(validationContext->getURIForPrefix(prefix));
00280                                     }
00281                                     buff.append(chCloseCurly);
00282                                     buff.append(value+index+1);
00283                                     matched(buff.getRawBuffer(), dv, false);
00284                                 }
00285                             }
00286                             else
00287                                 matched(value, dv, false);
00288                         }
00289                         break;
00290                     }
00291                 }
00292             }
00293 
00294             if ((fMatched[i] & XP_MATCHED) != XP_MATCHED) {
00295 
00296                 if(fCurrentStep[i] > descendantStep) {
00297 
00298                     fCurrentStep[i] = descendantStep;
00299                     continue;
00300                 }
00301 
00302                 fNoMatchDepth[i]++;
00303             }
00304         }
00305     }
00306 }
00307 
00308 void XPathMatcher::endElement(const XMLElementDecl& elemDecl,
00309                               const XMLCh* const elemContent,
00310                               ValidationContext* validationContext /*=0*/,
00311                               DatatypeValidator* actualValidator /*=0*/) {
00312 
00313     for(XMLSize_t i = 0; i < fLocationPathSize; i++) {
00314 
00315         // go back a step
00316         fCurrentStep[i] = fStepIndexes->elementAt(i)->pop();
00317 
00318         // don't do anything, if not matching
00319         if (fNoMatchDepth[i] > 0) {
00320             fNoMatchDepth[i]--;
00321         }
00322         // signal match, if appropriate
00323         else {
00324 
00325             if (fMatched[i] == 0)
00326                 continue;
00327             
00328             if ((fMatched[i] & XP_MATCHED_A) == XP_MATCHED_A) {
00329                 fMatched[i] = 0;
00330                 continue;
00331             }
00332 
00333             DatatypeValidator* dv = actualValidator?actualValidator:((SchemaElementDecl*) &elemDecl)->getDatatypeValidator();
00334             bool isNillable = (((SchemaElementDecl *) &elemDecl)->getMiscFlags() & SchemaSymbols::XSD_NILLABLE) != 0;
00335 
00336             // store QName using their Clark name
00337             if(dv && dv->getType()==DatatypeValidator::QName)
00338             {
00339                 int index=XMLString::indexOf(elemContent, chColon);
00340                 if(index==-1)
00341                     matched(elemContent, dv, isNillable);
00342                 else
00343                 {
00344                     XMLBuffer buff(1023, fMemoryManager);
00345                     buff.append(chOpenCurly);
00346                     if(validationContext)
00347                     {
00348                         XMLCh* prefix=(XMLCh*)fMemoryManager->allocate((index+1)*sizeof(XMLCh));
00349                         ArrayJanitor<XMLCh> janPrefix(prefix, fMemoryManager);
00350                         XMLString::subString(prefix, elemContent, 0, (XMLSize_t)index, fMemoryManager);
00351                         buff.append(validationContext->getURIForPrefix(prefix));
00352                     }
00353                     buff.append(chCloseCurly);
00354                     buff.append(elemContent+index+1);
00355                     matched(buff.getRawBuffer(), dv, isNillable);
00356                 }
00357             }
00358             else
00359                 matched(elemContent, dv, isNillable);
00360             fMatched[i] = 0;
00361         }
00362     }
00363 }
00364 
00365 
00366 // ---------------------------------------------------------------------------
00367 //  XPathMatcher: Match methods
00368 // ---------------------------------------------------------------------------
00369 unsigned char XPathMatcher::isMatched() {
00370 
00371     // xpath has been matched if any one of the members of the union have matched.
00372     for (XMLSize_t i=0; i < fLocationPathSize; i++) {
00373         if (((fMatched[i] & XP_MATCHED) == XP_MATCHED)
00374             && ((fMatched[i] & XP_MATCHED_DP) != XP_MATCHED_DP))
00375             return fMatched[i];
00376     }
00377 
00378     return 0;
00379 }
00380 
00381 void XPathMatcher::matched(const XMLCh* const,
00382                            DatatypeValidator* const,
00383                            const bool) {
00384     return;
00385 }
00386 
00387 bool XPathMatcher::matches(const XercesNodeTest* nodeTest, const QName* qName)
00388 {
00389     if (nodeTest->getType() == XercesNodeTest::NodeType_QNAME) {
00390         return (*nodeTest->getName())==(*qName);
00391     }
00392     if (nodeTest->getType() == XercesNodeTest::NodeType_NAMESPACE) {
00393         return nodeTest->getName()->getURI() == qName->getURI();
00394     }
00395     // NodeType_WILDCARD
00396     return true;
00397 }
00398 
00399 // ---------------------------------------------------------------------------
00400 //  XPathMatcher: Match methods
00401 // ---------------------------------------------------------------------------
00402 int XPathMatcher::getInitialDepth() const
00403 {
00404     ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Regex_NotSupported, fMemoryManager);
00405     return 0; // to make some compilers happy
00406 }
00407 
00408 XERCES_CPP_NAMESPACE_END
00409