GME
13
|
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