source: icXML/icXML-devel/src/icxercesc/validators/common/MixedContentModel.cpp @ 3153

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

Updates for various icxercesc modified 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 <icxercesc/validators/common/Grammar.hpp>
33#include <icxercesc/validators/schema/SubstitutionGroupComparator.hpp>
34#include <icxmlc/XMLConfig.hpp>
35
36XERCES_CPP_NAMESPACE_BEGIN
37
38// ---------------------------------------------------------------------------
39//  MixedContentModel: Constructors and Destructor
40// ---------------------------------------------------------------------------
41MixedContentModel::MixedContentModel(const bool             dtd
42                                                                   , ContentSpecNode* const parentContentSpec
43                                                                   , const bool             ordered
44                                                                   , MemoryManager* const   manager) :
45   fCount(0)
46 , fChildren(0)
47 , fChildTypes(0)
48 , fOrdered(ordered)
49 , fDTD(dtd)
50 , fMemoryManager(manager)
51{
52        //
53        //  Get the parent element's content spec. This is the head of the tree
54        //  of nodes that describes the content model. We will iterate this
55        //  tree.
56        //
57        ContentSpecNode* curNode = parentContentSpec;
58        if (!curNode)
59                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_NoParentCSN, fMemoryManager);
60
61    //
62    //  Create a vector of unsigned ints that will be filled in with the
63    //  ids of the child nodes. It will be expanded as needed but we give
64    //  it an initial capacity of 64 which should be more than enough for
65    //  99% of the scenarios.
66    //
67    ValueVectorOf<QName*> children(64, fMemoryManager);
68    ValueVectorOf<ContentSpecNode::NodeTypes> childTypes(64, fMemoryManager);
69
70        // And now call the private recursive method that iterates the tree
71        buildChildList(curNode, children, childTypes);
72
73        //
74        //  And now we know how many elements we need in our member list. So
75        //  fill them in.
76        //
77        fCount = children.size();
78    fChildren = (QName**)fMemoryManager->allocate(fCount * sizeof(QName*));
79    fChildTypes = (ContentSpecNode::NodeTypes*)fMemoryManager->allocate(fCount * sizeof(ContentSpecNode::NodeTypes));
80    for (XMLSize_t index = 0; index < fCount; index++)
81    {
82        fChildren[index] = new QName(*children.elementAt(index));
83                fChildTypes[index] = childTypes.elementAt(index);
84        }
85}
86
87MixedContentModel::~MixedContentModel()
88{
89    for (XMLSize_t index = 0; index < fCount; index++)
90    {
91        delete fChildren[index];
92    }
93    fMemoryManager->deallocate(fChildren);
94    fMemoryManager->deallocate(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) || ((curType & 0x0f) == ContentSpecNode::Sequence))
466        {
467                // Recurse on the left and right nodes
468                buildChildList(leftNode, toFill, toType);
469
470                // The last node of a choice or sequence has a null right
471                if (rightNode)
472                        buildChildList(rightNode, toFill, toType);
473        }
474        else if ((curType == ContentSpecNode::OneOrMore)
475                 ||  (curType == ContentSpecNode::ZeroOrOne)
476                 ||  (curType == ContentSpecNode::ZeroOrMore))
477        {
478                // Just do the left node on this one
479                buildChildList(leftNode, toFill, toType);
480        }
481}
482
483bool MixedContentModel::validateContent
484(
485        QName** const
486  , XMLSize_t
487  , unsigned int
488  , XMLSize_t*
489  , MemoryManager*  const
490)
491const
492{
493        DEPRECATED_FEATURE_IN_ICXML;
494}
495
496bool MixedContentModel::validateContentSpecial
497(
498        QName** const
499  , XMLSize_t
500  , unsigned int
501  , GrammarResolver*  const
502  , XMLStringPool*    const
503  , XMLSize_t*
504  , MemoryManager*    const
505)
506const
507{
508        DEPRECATED_FEATURE_IN_ICXML;
509}
510
511void MixedContentModel::checkUniqueParticleAttribution
512(
513        SchemaGrammar*    const
514  , GrammarResolver*  const
515  , XMLStringPool*    const
516  , XMLValidator*     const
517  , unsigned int*     const
518  , const XMLCh*
519)
520{
521        DEPRECATED_FEATURE_IN_ICXML;
522}
523
524XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.