source: icXML/icXML-devel/src/xercesc/validators/schema/identity/XPathMatcher.cpp @ 2779

Last change on this file since 2779 was 2779, checked in by cameron, 6 years ago

Synchronize files with IC svn

File size: 14.0 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: XPathMatcher.cpp 804234 2009-08-14 14:20:16Z amassari $
20 */
21
22// ---------------------------------------------------------------------------
23//  Includes
24// ---------------------------------------------------------------------------
25#include <xercesc/validators/schema/identity/XPathMatcher.hpp>
26#include <xercesc/validators/schema/identity/XercesXPath.hpp>
27#include <xercesc/validators/schema/SchemaElementDecl.hpp>
28#include <icxercesc/validators/schema/SchemaAttDef.hpp>
29#include <icxercesc/validators/schema/SchemaSymbols.hpp>
30#include <xercesc/util/RuntimeException.hpp>
31#include <xercesc/util/OutOfMemoryException.hpp>
32#include <xercesc/framework/ValidationContext.hpp>
33
34XERCES_CPP_NAMESPACE_BEGIN
35
36typedef JanitorMemFunCall<XPathMatcher>     CleanupType;
37
38// ---------------------------------------------------------------------------
39//  XPathMatcher: Constructors and Destructor
40// ---------------------------------------------------------------------------
41XPathMatcher::XPathMatcher( XercesXPath* const xpath
42                          , MemoryManager* const manager)
43    : fLocationPathSize(0)
44    , fMatched(0)
45    , fNoMatchDepth(0)
46    , fCurrentStep(0)
47    , fStepIndexes(0)
48    , fLocationPaths(0)
49    , fIdentityConstraint(0)
50    , fMemoryManager(manager)
51{
52    CleanupType cleanup(this, &XPathMatcher::cleanUp);
53
54    try {
55        init(xpath);
56    }
57    catch(const OutOfMemoryException&)
58    {
59        cleanup.release();
60
61        throw;
62    }
63
64    cleanup.release();
65}
66
67
68XPathMatcher::XPathMatcher(XercesXPath* const xpath,
69                           IdentityConstraint* const ic,
70                                                   MemoryManager* const manager)
71    : fLocationPathSize(0)
72    , fMatched(0)
73    , fNoMatchDepth(0)
74    , fCurrentStep(0)
75    , fStepIndexes(0)
76    , fLocationPaths(0)
77    , fIdentityConstraint(ic)
78    , fMemoryManager(manager)
79{
80    CleanupType cleanup(this, &XPathMatcher::cleanUp);
81
82    try {
83        init(xpath);
84    }
85    catch(const OutOfMemoryException&)
86    {
87        cleanup.release();
88
89        throw;
90    }
91
92    cleanup.release();
93}
94
95
96XPathMatcher::~XPathMatcher()
97{
98    cleanUp();
99}
100
101// ---------------------------------------------------------------------------
102//  XPathMatcher: Helper methods
103// ---------------------------------------------------------------------------
104void XPathMatcher::init(XercesXPath* const xpath) {
105
106    if (xpath) {
107
108        fLocationPaths = xpath->getLocationPaths();
109        fLocationPathSize = (fLocationPaths ? fLocationPaths->size() : 0);
110
111        if (fLocationPathSize) {
112
113            fStepIndexes = new (fMemoryManager) RefVectorOf<ValueStackOf<XMLSize_t> >(fLocationPathSize, true, fMemoryManager);
114            fCurrentStep = (XMLSize_t*) fMemoryManager->allocate
115            (
116                fLocationPathSize * sizeof(XMLSize_t)
117            );//new int[fLocationPathSize];
118            fNoMatchDepth = (XMLSize_t*) fMemoryManager->allocate
119            (
120                fLocationPathSize * sizeof(XMLSize_t)
121            );//new int[fLocationPathSize];
122            fMatched = (unsigned char*) fMemoryManager->allocate
123            (
124                fLocationPathSize * sizeof(unsigned char)
125            );//new int[fLocationPathSize];
126
127            for(XMLSize_t i=0; i < fLocationPathSize; i++) {
128                fStepIndexes->addElement(new (fMemoryManager) ValueStackOf<XMLSize_t>(8, fMemoryManager));
129            }
130        }
131    }
132}
133
134
135// ---------------------------------------------------------------------------
136//  XPathMatcher: XMLDocumentHandler methods
137// ---------------------------------------------------------------------------
138void XPathMatcher::startDocumentFragment() {
139
140    for(XMLSize_t i = 0; i < fLocationPathSize; i++) {
141
142        fStepIndexes->elementAt(i)->removeAllElements();
143        fCurrentStep[i] = 0;
144        fNoMatchDepth[i] = 0;
145        fMatched[i] = 0;
146    }
147}
148
149void XPathMatcher::startElement(const XMLElementDecl& elemDecl,
150                                const unsigned int urlId,
151                                const XMLCh* const elemPrefix,
152                                                                const RefVectorOf<XMLAttr>& attrList,
153                                const XMLSize_t attrCount,
154                                ValidationContext* validationContext /*=0*/) {
155
156    for (XMLSize_t i = 0; i < fLocationPathSize; i++) {
157
158        // push context
159        XMLSize_t startStep = fCurrentStep[i];
160        fStepIndexes->elementAt(i)->push(startStep);
161
162        // try next xpath, if not matching
163        if ((fMatched[i] & XP_MATCHED_D) == XP_MATCHED || fNoMatchDepth[i] > 0) {
164            fNoMatchDepth[i]++;
165            continue;
166        }
167
168        if((fMatched[i] & XP_MATCHED_D) == XP_MATCHED_D) {
169            fMatched[i] = XP_MATCHED_DP;
170        }
171
172        // consume self::node() steps
173        XercesLocationPath* locPath = fLocationPaths->elementAt(i);
174        XMLSize_t stepSize = locPath->getStepSize();
175
176        while (fCurrentStep[i] < stepSize &&
177               locPath->getStep(fCurrentStep[i])->getAxisType() == XercesStep::AxisType_SELF) {
178            fCurrentStep[i]++;
179        }
180
181        if (fCurrentStep[i] == stepSize) {
182
183            fMatched[i] = XP_MATCHED;
184            continue;
185        }
186
187        // now if the current step is a descendant step, we let the next
188        // step do its thing; if it fails, we reset ourselves
189        // to look at this step for next time we're called.
190        // so first consume all descendants:
191        XMLSize_t descendantStep = fCurrentStep[i];
192
193        while (fCurrentStep[i] < stepSize &&
194               locPath->getStep(fCurrentStep[i])->getAxisType() == XercesStep::AxisType_DESCENDANT) {
195            fCurrentStep[i]++;
196        }
197
198        bool sawDescendant = fCurrentStep[i] > descendantStep;
199        if (fCurrentStep[i] == stepSize) {
200
201            fNoMatchDepth[i]++;
202            continue;
203        }
204
205        // match child::... step, if haven't consumed any self::node()
206        if ((fCurrentStep[i] == startStep || fCurrentStep[i] > descendantStep) &&
207            locPath->getStep(fCurrentStep[i])->getAxisType() == XercesStep::AxisType_CHILD) {
208
209            XercesStep* step = locPath->getStep(fCurrentStep[i]);
210            XercesNodeTest* nodeTest = step->getNodeTest();
211
212            QName elemQName(elemPrefix, elemDecl.getElementName()->getLocalPart(), urlId, fMemoryManager);
213            if (!matches(nodeTest, &elemQName)) {
214
215                if(fCurrentStep[i] > descendantStep) {
216                    fCurrentStep[i] = descendantStep;
217                    continue;
218                }
219
220                fNoMatchDepth[i]++;
221                continue;
222            }
223
224            fCurrentStep[i]++;
225        }
226
227        if (fCurrentStep[i] == stepSize) {
228
229            if (sawDescendant) {
230
231                fCurrentStep[i] = descendantStep;
232                fMatched[i] = XP_MATCHED_D;
233            }
234            else {
235                fMatched[i] = XP_MATCHED;
236            }
237
238            continue;
239        }
240
241        // match attribute::... step
242        if (fCurrentStep[i] < stepSize &&
243            locPath->getStep(fCurrentStep[i])->getAxisType() == XercesStep::AxisType_ATTRIBUTE) {
244
245            if (attrCount) {
246
247                XercesNodeTest* nodeTest = locPath->getStep(fCurrentStep[i])->getNodeTest();
248
249                for (XMLSize_t attrIndex = 0; attrIndex < attrCount; attrIndex++) {
250
251                    const XMLAttr* curDef = attrList.elementAt(attrIndex);
252
253                    if (matches(nodeTest, curDef->getAttName())) {
254
255                        fCurrentStep[i]++;
256
257                        if (fCurrentStep[i] == stepSize) {
258
259                            fMatched[i] = XP_MATCHED_A;
260
261                            SchemaAttDef* attDef = ((SchemaElementDecl&) elemDecl).getAttDef(curDef->getName(), curDef->getURIId());
262                            DatatypeValidator* dv = (attDef) ? attDef->getDatatypeValidator() : 0;
263                            const XMLCh* value = curDef->getValue();
264                            // store QName using their Clark name
265                            if(dv && dv->getType()==DatatypeValidator::QName)
266                            {
267                                int index=XMLString::indexOf(value, chColon);
268                                if(index==-1)
269                                    matched(value, dv, false);
270                                else
271                                {
272                                    XMLBuffer buff(1023, fMemoryManager);
273                                    buff.append(chOpenCurly);
274                                    if(validationContext)
275                                    {
276                                        XMLCh* prefix=(XMLCh*)fMemoryManager->allocate((index+1)*sizeof(XMLCh));
277                                        ArrayJanitor<XMLCh> janPrefix(prefix, fMemoryManager);
278                                        XMLString::subString(prefix, value, 0, (XMLSize_t)index, fMemoryManager);
279                                        buff.append(validationContext->getURIForPrefix(prefix));
280                                    }
281                                    buff.append(chCloseCurly);
282                                    buff.append(value+index+1);
283                                    matched(buff.getRawBuffer(), dv, false);
284                                }
285                            }
286                            else
287                                matched(value, dv, false);
288                        }
289                        break;
290                    }
291                }
292            }
293
294            if ((fMatched[i] & XP_MATCHED) != XP_MATCHED) {
295
296                if(fCurrentStep[i] > descendantStep) {
297
298                    fCurrentStep[i] = descendantStep;
299                    continue;
300                }
301
302                fNoMatchDepth[i]++;
303            }
304        }
305    }
306}
307
308void XPathMatcher::endElement(const XMLElementDecl& elemDecl,
309                              const XMLCh* const elemContent,
310                              ValidationContext* validationContext /*=0*/,
311                              DatatypeValidator* actualValidator /*=0*/) {
312
313    for(XMLSize_t i = 0; i < fLocationPathSize; i++) {
314
315        // go back a step
316        fCurrentStep[i] = fStepIndexes->elementAt(i)->pop();
317
318        // don't do anything, if not matching
319        if (fNoMatchDepth[i] > 0) {
320            fNoMatchDepth[i]--;
321        }
322        // signal match, if appropriate
323        else {
324
325            if (fMatched[i] == 0)
326                continue;
327           
328            if ((fMatched[i] & XP_MATCHED_A) == XP_MATCHED_A) {
329                fMatched[i] = 0;
330                continue;
331            }
332
333            DatatypeValidator* dv = actualValidator?actualValidator:((SchemaElementDecl*) &elemDecl)->getDatatypeValidator();
334            bool isNillable = (((SchemaElementDecl *) &elemDecl)->getMiscFlags() & SchemaSymbols::XSD_NILLABLE) != 0;
335
336            // store QName using their Clark name
337            if(dv && dv->getType()==DatatypeValidator::QName)
338            {
339                int index=XMLString::indexOf(elemContent, chColon);
340                if(index==-1)
341                    matched(elemContent, dv, isNillable);
342                else
343                {
344                    XMLBuffer buff(1023, fMemoryManager);
345                    buff.append(chOpenCurly);
346                    if(validationContext)
347                    {
348                        XMLCh* prefix=(XMLCh*)fMemoryManager->allocate((index+1)*sizeof(XMLCh));
349                        ArrayJanitor<XMLCh> janPrefix(prefix, fMemoryManager);
350                        XMLString::subString(prefix, elemContent, 0, (XMLSize_t)index, fMemoryManager);
351                        buff.append(validationContext->getURIForPrefix(prefix));
352                    }
353                    buff.append(chCloseCurly);
354                    buff.append(elemContent+index+1);
355                    matched(buff.getRawBuffer(), dv, isNillable);
356                }
357            }
358            else
359                matched(elemContent, dv, isNillable);
360            fMatched[i] = 0;
361        }
362    }
363}
364
365
366// ---------------------------------------------------------------------------
367//  XPathMatcher: Match methods
368// ---------------------------------------------------------------------------
369unsigned char XPathMatcher::isMatched() {
370
371    // xpath has been matched if any one of the members of the union have matched.
372    for (XMLSize_t i=0; i < fLocationPathSize; i++) {
373        if (((fMatched[i] & XP_MATCHED) == XP_MATCHED)
374            && ((fMatched[i] & XP_MATCHED_DP) != XP_MATCHED_DP))
375            return fMatched[i];
376    }
377
378    return 0;
379}
380
381void XPathMatcher::matched(const XMLCh* const,
382                           DatatypeValidator* const,
383                           const bool) {
384    return;
385}
386
387bool XPathMatcher::matches(const XercesNodeTest* nodeTest, const QName* qName)
388{
389    if (nodeTest->getType() == XercesNodeTest::NodeType_QNAME) {
390        return (*nodeTest->getName())==(*qName);
391    }
392    if (nodeTest->getType() == XercesNodeTest::NodeType_NAMESPACE) {
393        return nodeTest->getName()->getURI() == qName->getURI();
394    }
395    // NodeType_WILDCARD
396    return true;
397}
398
399// ---------------------------------------------------------------------------
400//  XPathMatcher: Match methods
401// ---------------------------------------------------------------------------
402int XPathMatcher::getInitialDepth() const
403{
404    ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Regex_NotSupported, fMemoryManager);
405    return 0; // to make some compilers happy
406}
407
408XERCES_CPP_NAMESPACE_END
409
410/**
411  * End of file XPathMatcher.cpp
412  */
413
Note: See TracBrowser for help on using the repository browser.