source: icXML/icXML-devel/src/icxercesc/validators/common/MixedContentModel.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: 14.3 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: MixedContentModel.cpp 676911 2008-07-15 13:27:32Z amassari $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <string.h>
27#include <xercesc/util/RuntimeException.hpp>
28#include <icxercesc/framework/XMLElementDecl.hpp>
29#include <xercesc/validators/common/ContentSpecNode.hpp>
30#include <icxercesc/validators/common/MixedContentModel.hpp>
31#include <icxercesc/validators/common/CMStateSet.hpp>
32#include <xercesc/validators/common/Grammar.hpp>
33#include <xercesc/validators/schema/SubstitutionGroupComparator.hpp>
34
35XERCES_CPP_NAMESPACE_BEGIN
36
37// ---------------------------------------------------------------------------
38//  MixedContentModel: Constructors and Destructor
39// ---------------------------------------------------------------------------
40MixedContentModel::MixedContentModel(const bool             dtd
41                                                                   , ContentSpecNode* const parentContentSpec
42                                                                   , const bool             ordered
43                                                                   , MemoryManager* const   manager) :
44   fCount(0)
45 , fChildren(0)
46 , fChildTypes(0)
47 , fOrdered(ordered)
48 , fDTD(dtd)
49 , fMemoryManager(manager)
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        ValueVectorOf<QName*> children(64, fMemoryManager);
58        ValueVectorOf<ContentSpecNode::NodeTypes> childTypes(64, fMemoryManager);
59
60        //
61        //  Get the parent element's content spec. This is the head of the tree
62        //  of nodes that describes the content model. We will iterate this
63        //  tree.
64        //
65        ContentSpecNode* curNode = parentContentSpec;
66        if (!curNode)
67                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_NoParentCSN, fMemoryManager);
68
69        // And now call the private recursive method that iterates the tree
70        buildChildList(curNode, children, childTypes);
71
72        //
73        //  And now we know how many elements we need in our member list. So
74        //  fill them in.
75        //
76        fCount = children.size();
77        fChildren = (QName**) fMemoryManager->allocate(fCount * sizeof(QName*)); //new QName*[fCount];
78        fChildTypes = (ContentSpecNode::NodeTypes*) fMemoryManager->allocate
79        (
80                fCount * sizeof(ContentSpecNode::NodeTypes)
81        ); //new ContentSpecNode::NodeTypes[fCount];
82        for (XMLSize_t index = 0; index < fCount; index++) {
83                fChildren[index] = new (fMemoryManager) QName(*children.elementAt(index));
84                fChildTypes[index] = childTypes.elementAt(index);
85        }
86}
87
88MixedContentModel::~MixedContentModel()
89{
90        for (XMLSize_t index = 0; index < fCount; index++) {
91                delete fChildren[index];
92        }
93        fMemoryManager->deallocate(fChildren); //delete [] fChildren;
94        fMemoryManager->deallocate(fChildTypes); //delete [] fChildTypes;
95}
96
97
98// ---------------------------------------------------------------------------
99//  MixedContentModel: Getter methods
100// ---------------------------------------------------------------------------
101bool MixedContentModel::hasDups() const
102{
103        // Can't have dups if only one child
104        if (fCount == 1)
105                return false;
106
107        for (XMLSize_t index = 0; index < fCount; index++)
108        {
109                const QName* curVal = fChildren[index];
110                for (XMLSize_t iIndex = 0; iIndex < fCount; iIndex++)
111                {
112                        if (iIndex == index)
113                                continue;
114
115                        if (fDTD) {
116                                if (XMLString::equals(curVal->getRawName(), fChildren[iIndex]->getRawName())) {
117                                        return true;
118                                }
119                        }
120                        else {
121                                if ((curVal->getURI() == fChildren[iIndex]->getURI()) &&
122                                        (XMLString::equals(curVal->getLocalPart(), fChildren[iIndex]->getLocalPart()))) {
123                                        return true;
124                                }
125                        }
126                }
127        }
128        return false;
129}
130
131
132// ---------------------------------------------------------------------------
133//  MixedContentModel: Implementation of the ContentModel virtual interface
134// ---------------------------------------------------------------------------
135//
136//Under the XML Schema mixed model,
137//the order and number of child elements appearing in an instance
138//must agree with
139//the order and number of child elements specified in the model.
140//
141bool
142MixedContentModel::validateContent
143(
144        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
145        XMLElementDecl ** const         children
146        #else
147        QName** const                           children
148        #endif
149        , XMLSize_t                                     childCount
150        , XMLSize_t*                            indexOfFailingChild
151        , MemoryManager*    const       manager
152) const
153{
154        DEBUG_MESSAGE("MixedContentModel::validateContent");
155
156        // must match order
157        if (fOrdered)
158        {
159                unsigned int inIndex = 0;
160                for (unsigned int outIndex = 0; outIndex < childCount; outIndex++)
161                {
162                        // Get the current child out of the source index
163                        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
164                        QName * const curChild = children[outIndex]->getElementName();
165                        #else
166                        // Get the current child out of the source index
167                        QName * const curChild = children[outIndex];
168                        #endif
169
170                        // If its PCDATA, then we just accept that
171                        if (curChild->getURI() == XMLElementDecl::fgPCDataElemId)
172                                continue;
173
174                        ContentSpecNode::NodeTypes type = fChildTypes[inIndex];
175                        const QName* inChild = fChildren[inIndex];
176
177                        if (type == ContentSpecNode::Leaf)
178                        {
179                                if (fDTD)
180                                {
181                                        if (!XMLString::equals(inChild->getRawName(), curChild->getRawName()))
182                                        {
183                                                *indexOfFailingChild=outIndex;
184                                                return false;
185                                        }
186                                }
187                                else
188                                {
189                                        if ((inChild->getURI() != curChild->getURI()) || (!XMLString::equals(inChild->getLocalPart(), curChild->getLocalPart())))
190                                        {
191                                                *indexOfFailingChild=outIndex;
192                                                return false;
193                                        }
194                                }
195                        }
196                        else if (type == ContentSpecNode::Any)
197                        {
198
199                        }
200                        else if (type == ContentSpecNode::Any_NS) {
201                                if (inChild->getURI() != curChild->getURI())
202                                {
203                                        *indexOfFailingChild=outIndex;
204                                        return false;
205                                }
206                        }
207                        else if (type == ContentSpecNode::Any_Other)
208                        {
209                                // Here we assume that empty string has id 1.
210                                //
211                                unsigned int uriId = curChild->getURI();
212                                if (uriId == 1 || uriId == inChild->getURI())
213                                {
214                                        *indexOfFailingChild=outIndex;
215                                        return false;
216                                }
217                        }
218
219                        // advance index
220                        inIndex++;
221                }
222        }
223        else // can appear in any order
224        {
225                for (unsigned int outIndex = 0; outIndex < childCount; outIndex++)
226                {
227                        // Get the current child out of the source index
228                        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
229                        QName * const curChild = children[outIndex]->getElementName();
230                        #else
231                        // Get the current child out of the source index
232                        QName * const curChild = children[outIndex];
233                        #endif
234
235                        // If its PCDATA, then we just accept that
236                        if (curChild->getURI() == XMLElementDecl::fgPCDataElemId)
237                                continue;
238
239                        // And try to find it in our list
240                        unsigned int inIndex = 0;
241                        for (; inIndex < fCount; inIndex++)
242                        {
243                                ContentSpecNode::NodeTypes type = fChildTypes[inIndex];
244                                const QName* inChild = fChildren[inIndex];
245
246                                if (type == ContentSpecNode::Leaf)
247                                {
248                                        if (fDTD)
249                                        {
250                                                if (XMLString::equals(inChild->getRawName(), curChild->getRawName()))
251                                                {
252                                                        break;
253                                                }
254                                        }
255                                        else
256                                        {
257                                                if ((inChild->getURI() == curChild->getURI()) && (XMLString::equals(inChild->getLocalPart(), curChild->getLocalPart())))
258                                                {
259                                                        break;
260                                                }
261                                        }
262                                }
263                                else if (type == ContentSpecNode::Any)
264                                {
265                                        break;
266                                }
267                                else if (type == ContentSpecNode::Any_NS)
268                                {
269                                        if (inChild->getURI() == curChild->getURI())
270                                                break;
271                                }
272                                else if (type == ContentSpecNode::Any_Other)
273                                {
274                                        // Here we assume that empty string has id 1.
275                                        //
276                                        unsigned int uriId = curChild->getURI();
277                                        if (uriId != 1 && uriId != inChild->getURI())
278                                                break;
279                                }
280
281                                // REVISIT: What about checking for multiple ANY matches?
282                                //          The content model ambiguity *could* be checked
283                                //          by the caller before constructing the mixed
284                                //          content model.
285                        }
286                        // We did not find this one, so the validation failed
287                        if (inIndex == fCount)
288                        {
289                                *indexOfFailingChild=outIndex;
290                                return false;
291                        }
292                }
293        }
294
295        // Everything seems to be in order, so return success
296        return true;
297}
298
299bool MixedContentModel::validateContentSpecial
300(
301        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
302        XMLElementDecl ** const                 children
303        #else
304        QName** const                                   children
305        #endif
306        , XMLSize_t                                             childCount
307        , GrammarResolver*  const               pGrammarResolver
308        , XMLNamespaceResolver* const   pUriResolver
309        , XMLSize_t*                                    indexOfFailingChild
310        , MemoryManager*    const               manager
311) const
312{
313        SubstitutionGroupComparator comparator(pGrammarResolver, pUriResolver);
314
315        // must match order
316        if (fOrdered)
317        {
318                unsigned int inIndex = 0;
319                for (unsigned int outIndex = 0; outIndex < childCount; outIndex++)
320                {
321                        // Get the current child out of the source index
322                        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
323                        QName * const curChild = children[outIndex]->getElementName();
324                        #else
325                        // Get the current child out of the source index
326                        QName * const curChild = children[outIndex];
327                        #endif
328
329                        // If its PCDATA, then we just accept that
330                        if (curChild->getURI() == XMLElementDecl::fgPCDataElemId)
331                                continue;
332
333                        ContentSpecNode::NodeTypes type = fChildTypes[inIndex];
334                        QName* inChild = fChildren[inIndex];
335
336                        if (type == ContentSpecNode::Leaf)
337                        {
338                                if ( !comparator.isEquivalentTo(curChild, inChild))
339                                {
340                                        *indexOfFailingChild=outIndex;
341                                        return false;
342                                }
343                        }
344                        else if (type == ContentSpecNode::Any)
345                        {
346
347                        }
348                        else if (type == ContentSpecNode::Any_NS)
349                        {
350                                if (inChild->getURI() != curChild->getURI())
351                                {
352                                        *indexOfFailingChild=outIndex;
353                                        return false;
354                                }
355                        }
356                        else if (type == ContentSpecNode::Any_Other)
357                        {
358                                // Here we assume that empty string has id 1.
359                                //
360                                unsigned int uriId = curChild->getURI();
361                                if (uriId == 1 || uriId == inChild->getURI())
362                                {
363                                        *indexOfFailingChild=outIndex;
364                                        return false;
365                                }
366                        }
367
368                        // advance index
369                        inIndex++;
370                }
371        }
372
373        // can appear in any order
374        else
375        {
376                for (unsigned int outIndex = 0; outIndex < childCount; outIndex++)
377                {
378                        // Get the current child out of the source index
379                        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
380                        QName * const curChild = children[outIndex]->getElementName();
381                        #else
382                        // Get the current child out of the source index
383                        QName * const curChild = children[outIndex];
384                        #endif
385
386                        // If its PCDATA, then we just accept that
387                        if (curChild->getURI() == XMLElementDecl::fgPCDataElemId)
388                                continue;
389
390                        // And try to find it in our list
391                        unsigned int inIndex = 0;
392                        for (; inIndex < fCount; inIndex++)
393                        {
394                                ContentSpecNode::NodeTypes type = fChildTypes[inIndex];
395                                QName* inChild = fChildren[inIndex];
396
397                                if (type == ContentSpecNode::Leaf)
398                                {
399                                        if ( comparator.isEquivalentTo(curChild, inChild))
400                                                break;
401                                }
402                                else if (type == ContentSpecNode::Any)
403                                {
404                                        break;
405                                }
406                                else if (type == ContentSpecNode::Any_NS)
407                                {
408                                        if (inChild->getURI() == curChild->getURI())
409                                                break;
410                                }
411                                else if (type == ContentSpecNode::Any_Other)
412                                {
413                                  // Here we assume that empty string has id 1.
414                                  //
415                                  unsigned int uriId = curChild->getURI();
416                                  if (uriId != 1 && uriId != inChild->getURI())
417                                        break;
418                                }
419
420                                // REVISIT: What about checking for multiple ANY matches?
421                                //          The content model ambiguity *could* be checked
422                                //          by the caller before constructing the mixed
423                                //          content model.
424                        }
425                        // We did not find this one, so the validation failed
426                        if (inIndex == fCount)
427                        {
428                                *indexOfFailingChild=outIndex;
429                                return false;
430                        }
431                }
432        }
433
434        // Everything seems to be in order, so return success
435        return true;
436}
437
438// ---------------------------------------------------------------------------
439//  MixedContentModel: Private helper methods
440// ---------------------------------------------------------------------------
441void
442MixedContentModel::buildChildList(  ContentSpecNode* const       curNode
443                                                                  , ValueVectorOf<QName*>&       toFill
444                                                                  , ValueVectorOf<ContentSpecNode::NodeTypes>& toType)
445{
446        // Get the type of spec node our current node is
447        const ContentSpecNode::NodeTypes curType = curNode->getType();
448
449        // If its a leaf, then store its id in the target list
450        if ((curType == ContentSpecNode::Leaf)      ||
451                (curType == ContentSpecNode::Any)       ||
452                (curType == ContentSpecNode::Any_Other) ||
453                (curType == ContentSpecNode::Any_NS)   )
454        {
455                toFill.addElement(curNode->getElement());
456                toType.addElement(curType);
457                return;
458        }
459
460        // Get both the child node pointers
461        ContentSpecNode* leftNode = curNode->getFirst();
462        ContentSpecNode* rightNode = curNode->getSecond();
463
464        // And recurse according to the type of node
465        if (((curType & 0x0f) == ContentSpecNode::Choice)
466        ||  ((curType & 0x0f) == ContentSpecNode::Sequence))
467        {
468                // Recurse on the left and right nodes
469                buildChildList(leftNode, toFill, toType);
470
471                // The last node of a choice or sequence has a null right
472                if (rightNode)
473                        buildChildList(rightNode, toFill, toType);
474        }
475        else if ((curType == ContentSpecNode::OneOrMore)
476                 ||  (curType == ContentSpecNode::ZeroOrOne)
477                 ||  (curType == ContentSpecNode::ZeroOrMore))
478        {
479                // Just do the left node on this one
480                buildChildList(leftNode, toFill, toType);
481        }
482}
483
484bool MixedContentModel::validateContent
485(
486        QName** const
487  , XMLSize_t
488  , unsigned int
489  , XMLSize_t*
490  , MemoryManager*  const
491)
492const
493{
494        DEPRECATED_FEATURE_IN_ICXML;
495}
496
497bool MixedContentModel::validateContentSpecial
498(
499        QName** const
500  , XMLSize_t
501  , unsigned int
502  , GrammarResolver*  const
503  , XMLStringPool*    const
504  , XMLSize_t*
505  , MemoryManager*    const
506)
507const
508{
509        DEPRECATED_FEATURE_IN_ICXML;
510}
511
512void MixedContentModel::checkUniqueParticleAttribution
513(
514        SchemaGrammar*    const
515  , GrammarResolver*  const
516  , XMLStringPool*    const
517  , XMLValidator*     const
518  , unsigned int*     const
519  , const XMLCh*
520)
521{
522        DEPRECATED_FEATURE_IN_ICXML;
523}
524
525XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.