src/xmlpatterns/schema/qxsdschemachecker_helper.cpp
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 QT_BEGIN_NAMESPACE
       
    43 
       
    44 using namespace QPatternist;
       
    45 
       
    46 bool XsdSchemaChecker::hasDuplicatedAttributeUses(const XsdAttributeUse::List &list, XsdAttribute::Ptr &conflictingAttribute) const
       
    47 {
       
    48     const int length = list.count();
       
    49 
       
    50     for (int i = 0; i < length; ++i) {
       
    51         for (int j = 0; j < length; ++j) {
       
    52             if (i == j)
       
    53                 continue;
       
    54 
       
    55             if (list.at(i)->attribute()->name(m_namePool) == list.at(j)->attribute()->name(m_namePool)) {
       
    56                 conflictingAttribute = list.at(i)->attribute();
       
    57                 return true;
       
    58             }
       
    59         }
       
    60     }
       
    61 
       
    62     return false;
       
    63 }
       
    64 
       
    65 bool XsdSchemaChecker::hasMultipleIDAttributeUses(const XsdAttributeUse::List &list) const
       
    66 {
       
    67     const int length = list.count();
       
    68 
       
    69     bool hasIdDerivedAttribute = false;
       
    70     for (int i = 0; i < length; ++i) {
       
    71         if (BuiltinTypes::xsID->wxsTypeMatches(list.at(i)->attribute()->type())) {
       
    72             if (hasIdDerivedAttribute)
       
    73                 return true;
       
    74             else
       
    75                 hasIdDerivedAttribute = true;
       
    76         }
       
    77     }
       
    78 
       
    79     return false;
       
    80 }
       
    81 
       
    82 bool XsdSchemaChecker::hasConstraintIDAttributeUse(const XsdAttributeUse::List &list, XsdAttribute::Ptr &conflictingAttribute) const
       
    83 {
       
    84     const int length = list.count();
       
    85 
       
    86     for (int i = 0; i < length; ++i) {
       
    87         const XsdAttributeUse::Ptr attributeUse(list.at(i));
       
    88         if (BuiltinTypes::xsID->wxsTypeMatches(attributeUse->attribute()->type())) {
       
    89             if (attributeUse->valueConstraint()) {
       
    90                 conflictingAttribute = attributeUse->attribute();
       
    91                 return true;
       
    92             }
       
    93         }
       
    94     }
       
    95 
       
    96     return false;
       
    97 }
       
    98 
       
    99 bool XsdSchemaChecker::particleEqualsRecursively(const XsdParticle::Ptr &particle, const XsdParticle::Ptr &otherParticle) const
       
   100 {
       
   101     // @see http://www.w3.org/TR/xmlschema11-1/#cos-particle-extend
       
   102     //TODO: find out what 'properties' of a particle should be checked here...
       
   103 
       
   104     if (particle->minimumOccurs() != otherParticle->minimumOccurs())
       
   105         return false;
       
   106 
       
   107     if (particle->maximumOccursUnbounded() != otherParticle->maximumOccursUnbounded())
       
   108         return false;
       
   109 
       
   110     if (particle->maximumOccurs() != otherParticle->maximumOccurs())
       
   111         return false;
       
   112 
       
   113     const XsdTerm::Ptr term = particle->term();
       
   114     const XsdTerm::Ptr otherTerm = otherParticle->term();
       
   115 
       
   116     if (term->isElement() && !(otherTerm->isElement()))
       
   117         return false;
       
   118 
       
   119     if (term->isModelGroup() && !(otherTerm->isModelGroup()))
       
   120         return false;
       
   121 
       
   122     if (term->isWildcard() && !(otherTerm->isWildcard()))
       
   123         return false;
       
   124 
       
   125     if (term->isElement()) {
       
   126         const XsdElement::Ptr element = term;
       
   127         const XsdElement::Ptr otherElement = otherTerm;
       
   128 
       
   129         if (element->name(m_namePool) != otherElement->name(m_namePool))
       
   130             return false;
       
   131 
       
   132         if (element->type()->name(m_namePool) != otherElement->type()->name(m_namePool))
       
   133             return false;
       
   134     }
       
   135 
       
   136     if (term->isModelGroup()) {
       
   137         const XsdModelGroup::Ptr group = term;
       
   138         const XsdModelGroup::Ptr otherGroup = otherTerm;
       
   139 
       
   140         if (group->particles().count() != otherGroup->particles().count())
       
   141             return false;
       
   142 
       
   143         for (int i = 0; i < group->particles().count(); ++i) {
       
   144             if (!particleEqualsRecursively(group->particles().at(i), otherGroup->particles().at(i)))
       
   145                 return false;
       
   146         }
       
   147     }
       
   148 
       
   149     if (term->isWildcard()) {
       
   150     }
       
   151 
       
   152     return true;
       
   153 }
       
   154 
       
   155 bool XsdSchemaChecker::isValidParticleExtension(const XsdParticle::Ptr &extension, const XsdParticle::Ptr &base) const
       
   156 {
       
   157     // @see http://www.w3.org/TR/xmlschema11-1/#cos-particle-extend
       
   158 
       
   159     // 1
       
   160     if (extension == base)
       
   161         return true;
       
   162 
       
   163     // 2
       
   164     if (extension->minimumOccurs() == 1 && extension->maximumOccurs() == 1 && extension->maximumOccursUnbounded() == false) {
       
   165         if (extension->term()->isModelGroup()) {
       
   166             const XsdModelGroup::Ptr modelGroup = extension->term();
       
   167             if (modelGroup->compositor() == XsdModelGroup::SequenceCompositor) {
       
   168                 if (particleEqualsRecursively(modelGroup->particles().first(), base))
       
   169                     return true;
       
   170             }
       
   171         }
       
   172     }
       
   173 
       
   174     // 3
       
   175     if (extension->minimumOccurs() == base->minimumOccurs()) { // 3.1
       
   176         if (extension->term()->isModelGroup() && base->term()->isModelGroup()) {
       
   177             const XsdModelGroup::Ptr extensionGroup(extension->term());
       
   178             const XsdModelGroup::Ptr baseGroup(base->term());
       
   179 
       
   180             if (extensionGroup->compositor() == XsdModelGroup::AllCompositor && baseGroup->compositor() == XsdModelGroup::AllCompositor) {
       
   181                 const XsdParticle::List extensionParticles = extensionGroup->particles();
       
   182                 const XsdParticle::List baseParticles = baseGroup->particles();
       
   183                 for (int i = 0; i < baseParticles.count() && i < extensionParticles.count(); ++i) {
       
   184                     if (baseParticles.at(i) != extensionParticles.at(i))
       
   185                         return false;
       
   186                 }
       
   187             }
       
   188         }
       
   189     }
       
   190 
       
   191     return false;
       
   192 }
       
   193 
       
   194 QSet<XsdElement::Ptr> collectAllElements(const XsdParticle::Ptr &particle)
       
   195 {
       
   196     QSet<XsdElement::Ptr> elements;
       
   197 
       
   198     const XsdTerm::Ptr term(particle->term());
       
   199     if (term->isElement()) {
       
   200         elements.insert(XsdElement::Ptr(term));
       
   201     } else if (term->isModelGroup()) {
       
   202         const XsdModelGroup::Ptr group(term);
       
   203 
       
   204         for (int i = 0; i < group->particles().count(); ++i)
       
   205             elements.unite(collectAllElements(group->particles().at(i)));
       
   206     }
       
   207 
       
   208     return elements;
       
   209 }
       
   210 
       
   211 QSet<XsdElement::Ptr> collectAllElements(const XsdSchema::Ptr &schema)
       
   212 {
       
   213     QSet<XsdElement::Ptr> elements;
       
   214 
       
   215     // collect global elements
       
   216     const XsdElement::List elementList = schema->elements();
       
   217     for (int i = 0; i < elementList.count(); ++i)
       
   218         elements.insert(elementList.at(i));
       
   219 
       
   220     // collect all elements from global groups
       
   221     const XsdModelGroup::List groupList = schema->elementGroups();
       
   222     for (int i = 0; i < groupList.count(); ++i) {
       
   223         const XsdModelGroup::Ptr group(groupList.at(i));
       
   224 
       
   225         for (int j = 0; j < group->particles().count(); ++j)
       
   226             elements.unite(collectAllElements(group->particles().at(j)));
       
   227     }
       
   228 
       
   229     // collect all elements from complex type definitions
       
   230     SchemaType::List types;
       
   231     types << schema->types() << schema->anonymousTypes();
       
   232 
       
   233     for (int i = 0; i < types.count(); ++i) {
       
   234         if (types.at(i)->isComplexType() && types.at(i)->isDefinedBySchema()) {
       
   235             const XsdComplexType::Ptr complexType(types.at(i));
       
   236             if (complexType->contentType()->particle())
       
   237                 elements.unite(collectAllElements(complexType->contentType()->particle()));
       
   238         }
       
   239     }
       
   240 
       
   241     return elements;
       
   242 }
       
   243 
       
   244 bool XsdSchemaChecker::elementSequenceAccepted(const XsdModelGroup::Ptr &sequence, const XsdParticle::Ptr &particle) const
       
   245 {
       
   246     // @see http://www.w3.org/TR/xmlschema11-1/#cvc-accept
       
   247 
       
   248     if (particle->term()->isWildcard()) { // 1
       
   249         const XsdWildcard::Ptr wildcard(particle->term());
       
   250 
       
   251         // 1.1
       
   252         if ((unsigned int)sequence->particles().count() < particle->minimumOccurs())
       
   253             return false;
       
   254 
       
   255         // 1.2
       
   256         if (!particle->maximumOccursUnbounded()) {
       
   257             if ((unsigned int)sequence->particles().count() > particle->maximumOccurs())
       
   258                 return false;
       
   259         }
       
   260 
       
   261         // 1.3
       
   262         const XsdParticle::List particles(sequence->particles());
       
   263         for (int i = 0; i < particles.count(); ++i) {
       
   264             if (particles.at(i)->term()->isElement()) {
       
   265                 if (!XsdSchemaHelper::wildcardAllowsExpandedName(XsdElement::Ptr(particles.at(i)->term())->name(m_namePool), wildcard, m_namePool))
       
   266                     return false;
       
   267             }
       
   268         }
       
   269     } else if (particle->term()->isElement()) { // 2
       
   270         const XsdElement::Ptr element(particle->term());
       
   271 
       
   272         // 2.1
       
   273         if ((unsigned int)sequence->particles().count() < particle->minimumOccurs())
       
   274             return false;
       
   275 
       
   276         // 2.2
       
   277         if (!particle->maximumOccursUnbounded()) {
       
   278             if ((unsigned int)sequence->particles().count() > particle->maximumOccurs())
       
   279                 return false;
       
   280         }
       
   281 
       
   282         // 2.3
       
   283         const XsdParticle::List particles(sequence->particles());
       
   284         for (int i = 0; i < particles.count(); ++i) {
       
   285             bool isValid = false;
       
   286             if (particles.at(i)->term()->isElement()) {
       
   287                 const XsdElement::Ptr seqElement(particles.at(i)->term());
       
   288 
       
   289                 // 2.3.1
       
   290                 if (element->name(m_namePool) == seqElement->name(m_namePool))
       
   291                     isValid = true;
       
   292 
       
   293                 // 2.3.2
       
   294                 if (element->scope() && element->scope()->variety() == XsdElement::Scope::Global) {
       
   295                     if (!(element->disallowedSubstitutions() & NamedSchemaComponent::SubstitutionConstraint)) {
       
   296                         //TODO: continue
       
   297                     }
       
   298                 }
       
   299             }
       
   300         }
       
   301     }
       
   302 
       
   303     return true;
       
   304 }
       
   305 
       
   306 QT_END_NAMESPACE