1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qxsdschemahelper_p.h"
44 #include "qbuiltintypes_p.h"
45 #include "qvaluefactory_p.h"
46 #include "qxsdcomplextype_p.h"
47 #include "qxsdmodelgroup_p.h"
48 #include "qxsdsimpletype_p.h"
49 #include "qxsdtypechecker_p.h"
53 using namespace QPatternist;
56 * Calculates the effective total range minimum of the given @p particle as
57 * described by the algorithm in the schema spec.
59 static inline unsigned int effectiveTotalRangeMinimum(const XsdParticle::Ptr &particle)
61 const XsdModelGroup::Ptr group = particle->term();
63 if (group->compositor() == XsdModelGroup::ChoiceCompositor) {
64 // @see http://www.w3.org/TR/xmlschema11-1/# cos-choice-range
68 const XsdParticle::List particles = group->particles();
69 if (particles.isEmpty())
72 for (int i = 0; i < particles.count(); ++i) {
73 const XsdParticle::Ptr particle = particles.at(i);
75 if (particle->term()->isElement() || particle->term()->isWildcard()) {
77 minValue = particle->minimumOccurs();
79 minValue = qMin((unsigned int)minValue, particle->minimumOccurs());
81 } else if (particle->term()->isModelGroup()) {
83 minValue = effectiveTotalRangeMinimum(particle);
85 minValue = qMin((unsigned int)minValue, effectiveTotalRangeMinimum(particle));
90 return (particle->minimumOccurs() * minValue);
93 // @see http://www.w3.org/TR/xmlschema11-1/# cos-seq-range
96 const XsdParticle::List particles = group->particles();
97 for (int i = 0; i < particles.count(); ++i) {
98 const XsdParticle::Ptr particle = particles.at(i);
100 if (particle->term()->isElement() || particle->term()->isWildcard())
101 sum += particle->minimumOccurs();
102 else if (particle->term()->isModelGroup())
103 sum += effectiveTotalRangeMinimum(particle);
106 return (particle->minimumOccurs() * sum);
110 bool XsdSchemaHelper::isParticleEmptiable(const XsdParticle::Ptr &particle)
112 // @see http://www.w3.org/TR/xmlschema11-1/#cos-group-emptiable
114 if (particle->minimumOccurs() == 0)
117 if (!(particle->term()->isModelGroup()))
120 return (effectiveTotalRangeMinimum(particle) == 0);
123 bool XsdSchemaHelper::wildcardAllowsNamespaceName(const QString &nameSpace, const XsdWildcard::NamespaceConstraint::Ptr &constraint)
125 // @see http://www.w3.org/TR/xmlschema11-1/#cvc-wildcard-namespace
128 if (constraint->variety() == XsdWildcard::NamespaceConstraint::Any)
132 if (constraint->variety() == XsdWildcard::NamespaceConstraint::Not) { // 2.1
133 if (!constraint->namespaces().contains(nameSpace)) // 2.2
134 if (nameSpace != XsdWildcard::absentNamespace()) // 2.3
139 if (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) {
140 if (constraint->namespaces().contains(nameSpace))
147 bool XsdSchemaHelper::wildcardAllowsExpandedName(const QXmlName &name, const XsdWildcard::Ptr &wildcard, const NamePool::Ptr &namePool)
149 // @see http://www.w3.org/TR/xmlschema11-1/#cvc-wildcard-name
152 if (!wildcardAllowsNamespaceName(namePool->stringForNamespace(name.namespaceURI()), wildcard->namespaceConstraint()))
156 //TODO: we have no disallowed namespace yet
161 // small helper function that should be available in Qt 4.6
163 static inline bool containsSet(const QSet<T> &super, const QSet<T> &sub)
165 QSetIterator<T> it(sub);
166 while (it.hasNext()) {
167 if (!super.contains(it.next()))
174 bool XsdSchemaHelper::isWildcardSubset(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard)
176 // @see http://www.w3.org/TR/xmlschema11-1/#cos-ns-subset
178 // otherWildcard =^ super
180 const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint());
181 const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint());
184 if (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any)
188 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
189 if (containsSet<QString>(otherConstraint->namespaces(), constraint->namespaces()))
194 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) {
195 if (constraint->namespaces().intersect(otherConstraint->namespaces()).isEmpty())
200 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) {
201 if (containsSet<QString>(constraint->namespaces(), otherConstraint->namespaces()))
208 XsdWildcard::Ptr XsdSchemaHelper::wildcardUnion(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard)
210 // @see http://www.w3.org/TR/xmlschema11-1/#cos-aw-union
212 XsdWildcard::Ptr unionWildcard(new XsdWildcard());
214 const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint());
215 const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint());
218 if ((constraint->variety() == otherConstraint->variety()) &&
219 (constraint->namespaces() == otherConstraint->namespaces())) {
220 unionWildcard->namespaceConstraint()->setVariety(constraint->variety());
221 unionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces());
222 return unionWildcard;
226 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Any) || (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any)) {
227 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any);
228 return unionWildcard;
232 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
233 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration);
234 unionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces() + otherConstraint->namespaces());
235 return unionWildcard;
239 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) {
240 if (constraint->namespaces() != otherConstraint->namespaces()) {
241 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not);
242 unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace());
243 return unionWildcard;
248 QSet<QString> sSet, negatedSet;
249 bool matches5 = false;
250 if (((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && !constraint->namespaces().contains(XsdWildcard::absentNamespace()))
251 && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
253 negatedSet = constraint->namespaces();
254 sSet = otherConstraint->namespaces();
256 } else if (((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) && !otherConstraint->namespaces().contains(XsdWildcard::absentNamespace()))
257 && (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
259 negatedSet = otherConstraint->namespaces();
260 sSet = constraint->namespaces();
265 if (sSet.contains(negatedSet.values().first()) && sSet.contains(XsdWildcard::absentNamespace())) { // 5.1
266 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any);
267 return unionWildcard;
269 if (sSet.contains(negatedSet.values().first()) && !sSet.contains(XsdWildcard::absentNamespace())) { // 5.2
270 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not);
271 unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace());
272 return unionWildcard;
274 if (!sSet.contains(negatedSet.values().first()) && sSet.contains(XsdWildcard::absentNamespace())) { // 5.3
275 return XsdWildcard::Ptr(); // not expressible
277 if (!sSet.contains(negatedSet.values().first()) && !sSet.contains(XsdWildcard::absentNamespace())) { // 5.4
278 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not);
279 unionWildcard->namespaceConstraint()->setNamespaces(negatedSet);
280 return unionWildcard;
285 bool matches6 = false;
286 if (((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && constraint->namespaces().contains(XsdWildcard::absentNamespace()))
287 && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
289 negatedSet = constraint->namespaces();
290 sSet = otherConstraint->namespaces();
292 } else if (((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) && otherConstraint->namespaces().contains(XsdWildcard::absentNamespace()))
293 && (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
295 negatedSet = otherConstraint->namespaces();
296 sSet = constraint->namespaces();
301 if (sSet.contains(XsdWildcard::absentNamespace())) { // 6.1
302 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any);
303 return unionWildcard;
305 if (!sSet.contains(XsdWildcard::absentNamespace())) { // 6.2
306 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not);
307 unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() += XsdWildcard::absentNamespace());
308 return unionWildcard;
312 return XsdWildcard::Ptr();
315 XsdWildcard::Ptr XsdSchemaHelper::wildcardIntersection(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard)
317 // @see http://www.w3.org/TR/xmlschema11-1/#cos-aw-intersect
319 const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint());
320 const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint());
322 const XsdWildcard::Ptr intersectionWildcard(new XsdWildcard());
325 if ((constraint->variety() == otherConstraint->variety()) &&
326 (constraint->namespaces() == otherConstraint->namespaces())) {
327 intersectionWildcard->namespaceConstraint()->setVariety(constraint->variety());
328 intersectionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces());
329 return intersectionWildcard;
333 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Any) &&
334 (otherConstraint->variety() != XsdWildcard::NamespaceConstraint::Any)) {
335 intersectionWildcard->namespaceConstraint()->setVariety(otherConstraint->variety());
336 intersectionWildcard->namespaceConstraint()->setNamespaces(otherConstraint->namespaces());
337 return intersectionWildcard;
341 if ((constraint->variety() != XsdWildcard::NamespaceConstraint::Any) &&
342 (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any)) {
343 intersectionWildcard->namespaceConstraint()->setVariety(constraint->variety());
344 intersectionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces());
345 return intersectionWildcard;
349 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) &&
350 (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
352 QSet<QString> set = otherConstraint->namespaces();
353 set.subtract(constraint->namespaces());
354 set.remove(XsdWildcard::absentNamespace());
356 intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration);
357 intersectionWildcard->namespaceConstraint()->setNamespaces(set);
359 return intersectionWildcard;
363 if ((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) &&
364 (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
366 QSet<QString> set = constraint->namespaces();
367 set.subtract(otherConstraint->namespaces());
368 set.remove(XsdWildcard::absentNamespace());
370 intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration);
371 intersectionWildcard->namespaceConstraint()->setNamespaces(set);
373 return intersectionWildcard;
377 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) &&
378 (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
380 QSet<QString> set = constraint->namespaces();
381 set.intersect(otherConstraint->namespaces());
383 intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration);
384 intersectionWildcard->namespaceConstraint()->setNamespaces(set);
386 return intersectionWildcard;
390 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) &&
391 (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) {
392 if (!(constraint->namespaces().contains(XsdWildcard::absentNamespace())) && otherConstraint->namespaces().contains(XsdWildcard::absentNamespace())) {
395 if (constraint->namespaces().contains(XsdWildcard::absentNamespace()) && !(otherConstraint->namespaces().contains(XsdWildcard::absentNamespace()))) {
396 return otherWildcard;
400 // 5 as not expressible return empty wildcard
401 return XsdWildcard::Ptr();
404 static SchemaType::DerivationConstraints convertBlockingConstraints(const NamedSchemaComponent::BlockingConstraints &constraints)
406 SchemaType::DerivationConstraints result = 0;
408 if (constraints & NamedSchemaComponent::RestrictionConstraint)
409 result |= SchemaType::RestrictionConstraint;
410 if (constraints & NamedSchemaComponent::ExtensionConstraint)
411 result |= SchemaType::ExtensionConstraint;
416 bool XsdSchemaHelper::isValidlySubstitutable(const SchemaType::Ptr &type, const SchemaType::Ptr &otherType, const SchemaType::DerivationConstraints &constraints)
418 // @see http://www.w3.org/TR/xmlschema11-1/#key-val-sub-type
421 if (type->isComplexType() && otherType->isComplexType()) {
422 SchemaType::DerivationConstraints keywords = constraints;
423 if (otherType->isDefinedBySchema())
424 keywords |= convertBlockingConstraints(XsdComplexType::Ptr(otherType)->prohibitedSubstitutions());
426 return isComplexDerivationOk(type, otherType, keywords);
430 if (type->isComplexType() && otherType->isSimpleType()) {
431 return isComplexDerivationOk(type, otherType, constraints);
435 if (type->isSimpleType() && otherType->isSimpleType()) {
436 return isSimpleDerivationOk(type, otherType, constraints);
442 bool XsdSchemaHelper::isSimpleDerivationOk(const SchemaType::Ptr &derivedType, const SchemaType::Ptr &baseType, const SchemaType::DerivationConstraints &constraints)
444 // @see http://www.w3.org/TR/xmlschema11-1/#cos-st-derived-ok
447 if (derivedType == baseType)
451 if ((constraints & SchemaType::RestrictionConstraint) || derivedType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) {
456 if (derivedType->wxsSuperType() == baseType)
460 if (derivedType->wxsSuperType() != BuiltinTypes::xsAnyType) {
461 if (isSimpleDerivationOk(derivedType->wxsSuperType(), baseType, constraints))
466 if (derivedType->category() == SchemaType::SimpleTypeList || derivedType->category() == SchemaType::SimpleTypeUnion) {
467 if (baseType == BuiltinTypes::xsAnySimpleType)
472 if (baseType->category() == SchemaType::SimpleTypeUnion && baseType->isDefinedBySchema()) { // 2.2.4.1
473 const AnySimpleType::List memberTypes = XsdSimpleType::Ptr(baseType)->memberTypes();
474 for (int i = 0; i < memberTypes.count(); ++i) {
475 if (isSimpleDerivationOk(derivedType, memberTypes.at(i), constraints)) { // 2.2.4.2
476 if (XsdSimpleType::Ptr(baseType)->facets().isEmpty()) { // 2.2.4.3
486 bool XsdSchemaHelper::isComplexDerivationOk(const SchemaType::Ptr &derivedType, const SchemaType::Ptr &baseType, const SchemaType::DerivationConstraints &constraints)
491 // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-derived-ok
494 if (derivedType != baseType) {
495 if ((derivedType->derivationMethod() == SchemaType::DerivationRestriction) && (constraints & SchemaType::RestrictionConstraint))
497 if ((derivedType->derivationMethod() == SchemaType::DerivationExtension) && (constraints & SchemaType::ExtensionConstraint))
502 if (derivedType == baseType)
506 if (derivedType->wxsSuperType() == baseType)
511 if (derivedType->wxsSuperType() == BuiltinTypes::xsAnyType) { // 2.3.1
514 if (!derivedType->wxsSuperType())
517 if (derivedType->wxsSuperType()->isComplexType()) { // 2.3.2.1
518 isOk = isComplexDerivationOk(derivedType->wxsSuperType(), baseType, constraints);
520 isOk = isSimpleDerivationOk(derivedType->wxsSuperType(), baseType, constraints);
529 bool XsdSchemaHelper::constructAndCompare(const DerivedString<TypeString>::Ptr &operand1,
530 const AtomicComparator::Operator op,
531 const DerivedString<TypeString>::Ptr &operand2,
532 const SchemaType::Ptr &type,
533 const ReportContext::Ptr &context,
534 const SourceLocationReflection *const sourceLocationReflection)
536 Q_ASSERT_X(type->category() == SchemaType::SimpleTypeAtomic, Q_FUNC_INFO,
537 "We can only compare atomic values.");
539 // we can not cast a xs:String to a xs:QName, so lets go the safe way
540 if (type->name(context->namePool()) == BuiltinTypes::xsQName->name(context->namePool()))
543 const AtomicValue::Ptr value1 = ValueFactory::fromLexical(operand1->stringValue(), type, context, sourceLocationReflection);
544 if (value1->hasError())
547 const AtomicValue::Ptr value2 = ValueFactory::fromLexical(operand2->stringValue(), type, context, sourceLocationReflection);
548 if (value2->hasError())
551 return ComparisonFactory::compare(value1, op, value2, type, context, sourceLocationReflection);
554 bool XsdSchemaHelper::checkWildcardProcessContents(const XsdWildcard::Ptr &baseWildcard, const XsdWildcard::Ptr &derivedWildcard)
556 if (baseWildcard->processContents() == XsdWildcard::Strict) {
557 if (derivedWildcard->processContents() == XsdWildcard::Lax || derivedWildcard->processContents() == XsdWildcard::Skip) {
560 } else if (baseWildcard->processContents() == XsdWildcard::Lax) {
561 if (derivedWildcard->processContents() == XsdWildcard::Skip)
568 bool XsdSchemaHelper::foundSubstitutionGroupTransitive(const XsdElement::Ptr &head, const XsdElement::Ptr &member, QSet<XsdElement::Ptr> &visitedElements)
570 if (visitedElements.contains(member))
573 visitedElements.insert(member);
575 if (member->substitutionGroupAffiliations().isEmpty())
578 if (member->substitutionGroupAffiliations().contains(head)) {
581 const XsdElement::List affiliations = member->substitutionGroupAffiliations();
582 for (int i = 0; i < affiliations.count(); ++i) {
583 if (foundSubstitutionGroupTransitive(head, affiliations.at(i), visitedElements))
591 void XsdSchemaHelper::foundSubstitutionGroupTypeInheritance(const SchemaType::Ptr &headType, const SchemaType::Ptr &memberType,
592 QSet<SchemaType::DerivationMethod> &derivationSet, NamedSchemaComponent::BlockingConstraints &blockSet)
597 if (memberType == headType)
600 derivationSet.insert(memberType->derivationMethod());
602 if (memberType->isComplexType()) {
603 const XsdComplexType::Ptr complexType(memberType);
604 blockSet |= complexType->prohibitedSubstitutions();
607 foundSubstitutionGroupTypeInheritance(headType, memberType->wxsSuperType(), derivationSet, blockSet);
610 bool XsdSchemaHelper::substitutionGroupOkTransitive(const XsdElement::Ptr &head, const XsdElement::Ptr &member, const NamePool::Ptr &namePool)
612 // @see http://www.w3.org/TR/xmlschema11-1/#cos-equiv-derived-ok-rec
615 if ((member->name(namePool) == head->name(namePool)) && (member->type() == head->type()))
619 if (head->disallowedSubstitutions() & NamedSchemaComponent::SubstitutionConstraint)
624 QSet<XsdElement::Ptr> visitedElements;
625 if (!foundSubstitutionGroupTransitive(head, member, visitedElements))
631 QSet<SchemaType::DerivationMethod> derivationSet;
632 NamedSchemaComponent::BlockingConstraints blockSet;
634 foundSubstitutionGroupTypeInheritance(head->type(), member->type(), derivationSet, blockSet);
636 NamedSchemaComponent::BlockingConstraints checkSet(blockSet);
637 checkSet |= head->disallowedSubstitutions();
638 if (head->type()->isComplexType()) {
639 const XsdComplexType::Ptr complexType(head->type());
640 checkSet |= complexType->prohibitedSubstitutions();
643 if ((checkSet & NamedSchemaComponent::RestrictionConstraint) && derivationSet.contains(SchemaType::DerivationRestriction))
645 if ((checkSet & NamedSchemaComponent::ExtensionConstraint) && derivationSet.contains(SchemaType::DerivationExtension))
647 if (checkSet & NamedSchemaComponent::SubstitutionConstraint)
654 bool XsdSchemaHelper::isValidAttributeGroupRestriction(const XsdAttributeGroup::Ptr &derivedAttributeGroup, const XsdAttributeGroup::Ptr &attributeGroup, const XsdSchemaContext::Ptr &context, QString &errorMsg)
656 // @see http://www.w3.org/TR/xmlschema-1/#derivation-ok-restriction
658 const XsdAttributeUse::List derivedAttributeUses = derivedAttributeGroup->attributeUses();
659 const XsdAttributeUse::List baseAttributeUses = attributeGroup->attributeUses();
661 return isValidAttributeUsesRestriction(derivedAttributeUses, baseAttributeUses,
662 derivedAttributeGroup->wildcard(), attributeGroup->wildcard(), context, errorMsg);
665 bool XsdSchemaHelper::isValidAttributeUsesRestriction(const XsdAttributeUse::List &derivedAttributeUses, const XsdAttributeUse::List &baseAttributeUses,
666 const XsdWildcard::Ptr &derivedWildcard, const XsdWildcard::Ptr &wildcard, const XsdSchemaContext::Ptr &context, QString &errorMsg)
668 const NamePool::Ptr namePool(context->namePool());
670 QHash<QXmlName, XsdAttributeUse::Ptr> baseAttributeUsesLookup;
671 for (int i = 0; i < baseAttributeUses.count(); ++i)
672 baseAttributeUsesLookup.insert(baseAttributeUses.at(i)->attribute()->name(namePool), baseAttributeUses.at(i));
674 QHash<QXmlName, XsdAttributeUse::Ptr> derivedAttributeUsesLookup;
675 for (int i = 0; i < derivedAttributeUses.count(); ++i)
676 derivedAttributeUsesLookup.insert(derivedAttributeUses.at(i)->attribute()->name(namePool), derivedAttributeUses.at(i));
679 for (int i = 0; i < derivedAttributeUses.count(); ++i) {
680 const XsdAttributeUse::Ptr derivedAttributeUse = derivedAttributeUses.at(i);
682 // prohibited attributes are no real attributes, so skip them in that test here
683 if (derivedAttributeUse->useType() == XsdAttributeUse::ProhibitedUse)
686 if (baseAttributeUsesLookup.contains(derivedAttributeUse->attribute()->name(namePool))) {
687 const XsdAttributeUse::Ptr baseAttributeUse(baseAttributeUsesLookup.value(derivedAttributeUse->attribute()->name(namePool)));
690 if (baseAttributeUse->isRequired() == true && derivedAttributeUse->isRequired() == false) {
691 errorMsg = QtXmlPatterns::tr("Base attribute %1 is required but derived attribute is not.").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool)));
696 if (!isSimpleDerivationOk(derivedAttributeUse->attribute()->type(), baseAttributeUse->attribute()->type(), SchemaType::DerivationConstraints())) {
697 errorMsg = QtXmlPatterns::tr("Type of derived attribute %1 cannot be validly derived from type of base attribute.").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool)));
702 XsdAttributeUse::ValueConstraint::Ptr derivedConstraint;
703 if (derivedAttributeUse->valueConstraint())
704 derivedConstraint = derivedAttributeUse->valueConstraint();
705 else if (derivedAttributeUse->attribute()->valueConstraint())
706 derivedConstraint = XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(derivedAttributeUse->attribute()->valueConstraint());
708 XsdAttributeUse::ValueConstraint::Ptr baseConstraint;
709 if (baseAttributeUse->valueConstraint())
710 baseConstraint = baseAttributeUse->valueConstraint();
711 else if (baseAttributeUse->attribute()->valueConstraint())
712 baseConstraint = XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(baseAttributeUse->attribute()->valueConstraint());
715 if (!baseConstraint || baseConstraint->variety() == XsdAttributeUse::ValueConstraint::Default)
718 if (derivedConstraint && baseConstraint) {
719 const XsdTypeChecker checker(context, QVector<QXmlName>(), QSourceLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1));
720 if (derivedConstraint->variety() == XsdAttributeUse::ValueConstraint::Fixed && checker.valuesAreEqual(derivedConstraint->value(), baseConstraint->value(), baseAttributeUse->attribute()->type()))
725 errorMsg = QtXmlPatterns::tr("Value constraint of derived attribute %1 does not match value constraint of base attribute.").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool)));
730 errorMsg = QtXmlPatterns::tr("Derived attribute %1 does not exist in the base definition.").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool)));
734 QXmlName name = derivedAttributeUse->attribute()->name(namePool);
736 // wildcards using XsdWildcard::absentNamespace, so we have to fix that here
737 if (name.namespaceURI() == StandardNamespaces::empty)
738 name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace()));
740 if (!wildcardAllowsExpandedName(name, wildcard, namePool)) {
741 errorMsg = QtXmlPatterns::tr("Derived attribute %1 does not match the wildcard in the base definition.").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool)));
748 for (int i = 0; i < baseAttributeUses.count(); ++i) {
749 const XsdAttributeUse::Ptr baseAttributeUse = baseAttributeUses.at(i);
751 if (baseAttributeUse->isRequired()) {
752 if (derivedAttributeUsesLookup.contains(baseAttributeUse->attribute()->name(namePool))) {
753 if (!derivedAttributeUsesLookup.value(baseAttributeUse->attribute()->name(namePool))->isRequired()) {
754 errorMsg = QtXmlPatterns::tr("Base attribute %1 is required but derived attribute is not.").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool)));
758 errorMsg = QtXmlPatterns::tr("Base attribute %1 is required but missing in derived definition.").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool)));
765 if (derivedWildcard) {
767 errorMsg = QtXmlPatterns::tr("Derived definition contains an %1 element that does not exists in the base definition").arg(formatElement("anyAttribute."));
771 if (!isWildcardSubset(derivedWildcard, wildcard)) {
772 errorMsg = QtXmlPatterns::tr("Derived wildcard is not a subset of the base wildcard.");
776 if (!checkWildcardProcessContents(wildcard, derivedWildcard)) {
777 errorMsg = QtXmlPatterns::tr("%1 of derived wildcard is not a valid restriction of %2 of base wildcard").arg(formatKeyword("processContents")).arg(formatKeyword("processContents."));
785 bool XsdSchemaHelper::isValidAttributeUsesExtension(const XsdAttributeUse::List &derivedAttributeUses, const XsdAttributeUse::List &attributeUses,
786 const XsdWildcard::Ptr &derivedWildcard, const XsdWildcard::Ptr &wildcard, const XsdSchemaContext::Ptr &context, QString &errorMsg)
788 // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-extends
790 const NamePool::Ptr namePool(context->namePool());
793 QHash<QXmlName, XsdAttribute::Ptr> lookupHash;
794 for (int i = 0; i < derivedAttributeUses.count(); ++i)
795 lookupHash.insert(derivedAttributeUses.at(i)->attribute()->name(namePool), derivedAttributeUses.at(i)->attribute());
797 for (int i = 0; i < attributeUses.count(); ++i) {
798 const QXmlName attributeName = attributeUses.at(i)->attribute()->name(namePool);
799 if (!lookupHash.contains(attributeName)) {
800 errorMsg = QtXmlPatterns::tr("Attribute %1 from base type is missing in derived type.").arg(formatKeyword(namePool->displayName(attributeName)));
804 if (lookupHash.value(attributeName)->type() != attributeUses.at(i)->attribute()->type()) {
805 errorMsg = QtXmlPatterns::tr("Type of derived attribute %1 differs from type of base attribute.").arg(formatKeyword(namePool->displayName(attributeName)));
812 if (!derivedWildcard) {
813 errorMsg = QtXmlPatterns::tr("Base definition contains an %1 element that is missing in the derived definition").arg(formatElement("anyAttribute."));