source: icXML/icXML-devel/src/icxercesc/validators/common/AllContentModel.cpp @ 2721

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

Fix imports in icXML modified Xerces files

File size: 13.1 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: AllContentModel.cpp 676911 2008-07-15 13:27:32Z amassari $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <xercesc/util/Janitor.hpp>
27#include <xercesc/util/RuntimeException.hpp>
28#include <icxercesc/framework/XMLElementDecl.hpp>
29#include <icxercesc/framework/XMLValidator.hpp>
30#include <xercesc/validators/common/ContentSpecNode.hpp>
31#include <icxercesc/validators/common/AllContentModel.hpp>
32#include <xercesc/validators/schema/SubstitutionGroupComparator.hpp>
33#include <xercesc/validators/schema/XercesElementWildcard.hpp>
34
35XERCES_CPP_NAMESPACE_BEGIN
36
37// ---------------------------------------------------------------------------
38//  AllContentModel: Constructors and Destructor
39// ---------------------------------------------------------------------------
40AllContentModel::AllContentModel( ContentSpecNode* const parentContentSpec
41                                                                , const bool             isMixed
42                                                                , MemoryManager* const   manager) :
43   fMemoryManager(manager)
44 , fCount(0)
45 , fChildren(0)
46 , fChildOptional(0)
47 , fNumRequired(0)
48 , fIsMixed(isMixed)
49 , fHasOptionalContent(false)
50{
51        //
52        //  Create a vector of unsigned ints that will be filled in with the
53        //  ids of the child nodes. It will be expanded as needed but we give
54        //  it an initial capacity of 64 which should be more than enough for
55        //  99% of the scenarios.
56        //
57
58        ValueVectorOf<QName*> children(64, fMemoryManager);
59        ValueVectorOf<bool> childOptional(64, fMemoryManager);
60
61        //
62        //  Get the parent element's content spec. This is the head of the tree
63        //  of nodes that describes the content model. We will iterate this
64        //  tree.
65        //
66        ContentSpecNode* curNode = parentContentSpec;
67        if (!curNode)
68                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_NoParentCSN, fMemoryManager);
69
70        // And now call the private recursive method that iterates the tree
71        if (curNode->getType() == ContentSpecNode::All
72                && curNode->getMinOccurs() == 0) {
73                fHasOptionalContent = true;
74        }
75        buildChildList(curNode, children, childOptional);
76
77        //
78        //  And now we know how many elements we need in our member list. So
79        //  fill them in.
80        //
81        fCount = children.size();
82        fChildren = (QName**) fMemoryManager->allocate(fCount * sizeof(QName*)); //new QName*[fCount];
83        fChildOptional = (bool*) fMemoryManager->allocate(fCount * sizeof(bool)); //new bool[fCount];
84        for (unsigned int index = 0; index < fCount; index++) {
85                fChildren[index] = new (fMemoryManager) QName(*(children.elementAt(index)));
86                fChildOptional[index] = childOptional.elementAt(index);
87        }
88}
89
90AllContentModel::~AllContentModel()
91{
92        for (XMLSize_t index = 0; index < fCount; index++)
93                delete fChildren[index];
94        fMemoryManager->deallocate(fChildren); //delete [] fChildren;
95        fMemoryManager->deallocate(fChildOptional); //delete [] fChildOptional;
96}
97
98// ---------------------------------------------------------------------------
99//  AllContentModel: Implementation of the ContentModel virtual interface
100// ---------------------------------------------------------------------------
101//
102//Under the XML Schema mixed model,
103//the order and number of child elements appearing in an instance
104//must agree with
105//the order and number of child elements specified in the model.
106//
107bool
108AllContentModel::validateContent
109(
110        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
111        XMLElementDecl ** const         children
112        #else
113        QName** const                           children
114        #endif
115        , XMLSize_t                                     childCount
116        , XMLSize_t*                            indexOfFailingChild
117        , MemoryManager*    const       manager
118) const
119{
120        DEBUG_MESSAGE("AllContentModel::validateContent");
121
122        // If <all> had minOccurs of zero and there are
123        // no children to validate, trivially validate
124        if (childCount == 0 && (fHasOptionalContent || !fNumRequired))
125                return true;
126
127        // keep track of the required element seen
128        XMLSize_t numRequiredSeen = 0;
129
130        if (childCount > 0)
131        {
132                // Check for duplicate element
133                bool* elementSeen = (bool*) manager->allocate(fCount*sizeof(bool)); //new bool[fCount];
134
135                const ArrayJanitor<bool> jan(elementSeen, manager);
136
137                // initialize the array
138                for (XMLSize_t i = 0; i < fCount; i++)
139                {
140                        elementSeen[i] = false;
141                }
142
143                for (XMLSize_t outIndex = 0; outIndex < childCount; outIndex++)
144                {
145                        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
146                        QName * const curChild = children[outIndex]->getElementName();
147                        curChild->setURI(children[outIndex]->getURI());
148                        #else
149                        // Get the current child out of the source index
150                        QName * const curChild = children[outIndex];
151                        #endif
152
153                        // If it's PCDATA, then we just accept that
154                        if (fIsMixed && curChild->getURI() == XMLElementDecl::fgPCDataElemId)
155                        {
156                                continue;
157                        }
158
159                        // And try to find it in our list
160                        XMLSize_t inIndex = 0;
161                        for (; inIndex < fCount; inIndex++)
162                        {
163                                const QName* inChild = fChildren[inIndex];
164                                if ((inChild->getURI() == curChild->getURI()) && XMLString::equals(inChild->getLocalPart(), curChild->getLocalPart()))
165                                {
166                                        // found it
167                                        // If this element was seen already, indicate an error was
168                                        // found at the duplicate index.
169                                        if (elementSeen[inIndex])
170                                        {
171                                                *indexOfFailingChild = outIndex;
172                                                return false;
173                                        }
174                                        else
175                                        {
176                                                elementSeen[inIndex] = true;
177                                        }
178
179                                        if (!fChildOptional[inIndex])
180                                        {
181                                                numRequiredSeen++;
182                                        }
183                                        break;
184                                }
185                        }
186
187                        // We did not find this one, so the validation failed
188                        if (inIndex == fCount)
189                        {
190                                *indexOfFailingChild = outIndex;
191                                return false;
192                        }
193
194                }
195        }
196
197        // Were all the required elements of the <all> encountered?
198        if (numRequiredSeen != fNumRequired) {
199                *indexOfFailingChild=childCount;
200                return false;
201        }
202
203        // Everything seems to be ok, so return success
204        return true;
205}
206
207bool AllContentModel::validateContentSpecial
208(
209        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
210        XMLElementDecl ** const                 children
211        #else
212        QName** const                                   children
213        #endif
214        , XMLSize_t                                             childCount
215        , GrammarResolver*  const               pGrammarResolver
216        , XMLNamespaceResolver* const   pUriResolver
217        , XMLSize_t*                                    indexOfFailingChild
218        , MemoryManager*    const               manager
219) const
220{
221        // If <all> had minOccurs of zero and there are
222        // no children to validate, trivially validate
223        if (childCount == 0 && (fHasOptionalContent || !fNumRequired))
224                return true;
225
226        // keep track of the required element seen
227        XMLSize_t numRequiredSeen = 0;
228
229        if(childCount > 0)
230        {
231                SubstitutionGroupComparator comparator(pGrammarResolver, pUriResolver);
232
233                // Check for duplicate element
234                bool* elementSeen = (bool*) manager->allocate(fCount*sizeof(bool)); //new bool[fCount];
235
236                const ArrayJanitor<bool> jan(elementSeen, manager);
237
238                // initialize the array
239                for (XMLSize_t i = 0; i < fCount; i++)
240                {
241                        elementSeen[i] = false;
242                }
243
244                for (XMLSize_t outIndex = 0; outIndex < childCount; outIndex++)
245                {
246                        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
247                        QName * const curChild = children[outIndex]->getElementName();
248                        curChild->setURI(children[outIndex]->getURI());
249                        #else
250                        // Get the current child out of the source index
251                        QName * const curChild = children[outIndex];
252                        #endif
253
254                        // If it's PCDATA, then we just accept that
255                        if (fIsMixed && curChild->getURI() == XMLElementDecl::fgPCDataElemId)
256                                continue;
257
258                        // And try to find it in our list
259                        XMLSize_t inIndex = 0;
260                        for (; inIndex < fCount; inIndex++)
261                        {
262                                QName* const inChild = fChildren[inIndex];
263                                if ( comparator.isEquivalentTo(curChild, inChild)) {
264                                        // match
265                                        // If this element was seen already, indicate an error was
266                                        // found at the duplicate index.
267                                        if (elementSeen[inIndex]) {
268                                                *indexOfFailingChild=outIndex;
269                                                return false;
270                                        }
271                                        else
272                                                elementSeen[inIndex] = true;
273
274                                        if (!fChildOptional[inIndex])
275                                                numRequiredSeen++;
276
277                                        break;
278                                }
279                        }
280
281                        // We did not find this one, so the validation failed
282                        if (inIndex == fCount) {
283                                *indexOfFailingChild=outIndex;
284                                return false;
285                        }
286
287                }
288        }
289
290        // Were all the required elements of the <all> encountered?
291        if (numRequiredSeen != fNumRequired) {
292                *indexOfFailingChild=childCount;
293                return false;
294        }
295
296        // Everything seems to be ok, so return success
297        return true;
298
299}
300
301void AllContentModel::checkUniqueParticleAttribution
302(
303        SchemaGrammar*    const                 pGrammar
304        , GrammarResolver*  const               pGrammarResolver
305        , XMLNamespaceResolver* const   pUriResolver
306        , XMLValidator*     const               pValidator
307        , unsigned int*     const               pContentSpecOrgURI
308        , const XMLCh*                                  pComplexTypeName /*= 0*/
309)
310{
311        SubstitutionGroupComparator comparator(pGrammarResolver, pUriResolver);
312
313        XMLSize_t i, j;
314
315        // rename back
316        for (i = 0; i < fCount; i++)
317        {
318                unsigned int orgURIIndex = fChildren[i]->getURI();
319                fChildren[i]->setURI(pContentSpecOrgURI[orgURIIndex]);
320        }
321
322        // check whether there is conflict between any two leaves
323        for (i = 0; i < fCount; i++)
324        {
325                for (j = i+1; j < fCount; j++)
326                {
327                        // If this is text in a Schema mixed content model, skip it.
328                        if ( fIsMixed &&
329                                 (( fChildren[i]->getURI() == XMLElementDecl::fgPCDataElemId) ||
330                                  ( fChildren[j]->getURI() == XMLElementDecl::fgPCDataElemId)))
331                                continue;
332
333                        if (XercesElementWildcard::conflict(pGrammar,
334                                                                                                ContentSpecNode::Leaf,
335                                                                                                fChildren[i],
336                                                                                                ContentSpecNode::Leaf,
337                                                                                                fChildren[j],
338                                                                                                &comparator)) {
339                                pValidator->emitError(XMLValid::UniqueParticleAttributionFail,
340                                                                          pComplexTypeName,
341                                                                          fChildren[i]->getRawName(),
342                                                                          fChildren[j]->getRawName());
343                         }
344                 }
345        }
346}
347
348// ---------------------------------------------------------------------------
349//  AllContentModel: Private helper methods
350// ---------------------------------------------------------------------------
351void
352AllContentModel::buildChildList(ContentSpecNode* const       curNode
353                                                          , ValueVectorOf<QName*>&       toFill
354                                                          , ValueVectorOf<bool>&         toOptional)
355{
356        // Get the type of spec node our current node is
357        const ContentSpecNode::NodeTypes curType = curNode->getType();
358
359        if (curType == ContentSpecNode::All)
360        {
361                // Get both the child node pointers
362                ContentSpecNode* leftNode = curNode->getFirst();
363                ContentSpecNode* rightNode = curNode->getSecond();
364
365                // Recurse on the left and right nodes
366                buildChildList(leftNode, toFill, toOptional);
367                if(rightNode)
368                        buildChildList(rightNode, toFill, toOptional);
369        }
370        else if (curType == ContentSpecNode::Leaf)
371        {
372                // At leaf, add the element to list of elements permitted in the all
373                toFill.addElement(curNode->getElement());
374                toOptional.addElement(false);
375                fNumRequired++;
376        }
377        else if (curType == ContentSpecNode::ZeroOrOne)
378        {
379                // At ZERO_OR_ONE node, subtree must be an element
380                // that was specified with minOccurs=0, maxOccurs=1
381                ContentSpecNode* leftNode = curNode->getFirst();
382                if (leftNode->getType() != ContentSpecNode::Leaf)
383                        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMSpecType, fMemoryManager);
384
385                toFill.addElement(leftNode->getElement());
386                toOptional.addElement(true);
387        }
388        // only allow ZeroOrMore when it's the father of a Loop
389        else if (curType == ContentSpecNode::ZeroOrMore &&
390                         curNode->getFirst()!=0 &&
391                         curNode->getFirst()->getType()==ContentSpecNode::Loop)
392        {
393                ContentSpecNode* leftNode = curNode->getFirst();
394                buildChildList(leftNode, toFill, toOptional);
395        }
396        else if (curType == ContentSpecNode::Loop)
397        {
398                // At leaf, add the element to list of elements permitted in the all
399                int i;
400                for(i=0;i<curNode->getMinOccurs();i++)
401                {
402                        toFill.addElement(curNode->getElement());
403                        toOptional.addElement(false);
404                        fNumRequired++;
405                }
406                if(curNode->getMaxOccurs()!=-1)
407                        for(i=0;i<(curNode->getMaxOccurs() - curNode->getMinOccurs());i++)
408                        {
409                                toFill.addElement(curNode->getElement());
410                                toOptional.addElement(true);
411                        }
412        }
413        else
414                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMSpecType, fMemoryManager);
415}
416
417/** @@@ DEPRECATED FUNCTIONS; KEPT FOR DLL COMPATIBILITY! @@@ **/
418
419bool AllContentModel::validateContent
420(
421        QName** const
422  , XMLSize_t
423  , unsigned int
424  , XMLSize_t*
425  , MemoryManager*  const
426)
427const
428{
429        DEPRECATED_FEATURE_IN_ICXML;
430}
431
432bool AllContentModel::validateContentSpecial
433(
434        QName** const
435  , XMLSize_t
436  , unsigned int
437  , GrammarResolver*  const
438  , XMLStringPool*    const
439  , XMLSize_t*
440  , MemoryManager*    const
441)
442const
443{
444        DEPRECATED_FEATURE_IN_ICXML;
445}
446
447void AllContentModel::checkUniqueParticleAttribution
448(
449        SchemaGrammar*    const
450  , GrammarResolver*  const
451  , XMLStringPool*    const
452  , XMLValidator*     const
453  , unsigned int*     const
454  , const XMLCh*
455)
456{
457        DEPRECATED_FEATURE_IN_ICXML;
458}
459
460XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.