1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qxsdschemachecker_p.h"
44 #include "qderivedinteger_p.h"
45 #include "qderivedstring_p.h"
46 #include "qpatternplatform_p.h"
47 #include "qqnamevalue_p.h"
48 #include "qsourcelocationreflection_p.h"
49 #include "qvaluefactory_p.h"
50 #include "qxsdattributereference_p.h"
51 #include "qxsdparticlechecker_p.h"
52 #include "qxsdreference_p.h"
53 #include "qxsdschemacontext_p.h"
54 #include "qxsdschemahelper_p.h"
55 #include "qxsdschemaparsercontext_p.h"
56 #include "qxsdschematypesfactory_p.h"
57 #include "qxsdtypechecker_p.h"
59 #include "qxsdschemachecker_helper.cpp"
63 using namespace QPatternist;
65 XsdSchemaChecker::XsdSchemaChecker(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext)
67 , m_namePool(parserContext->namePool())
68 , m_schema(parserContext->schema())
70 setupAllowedAtomicFacets();
73 XsdSchemaChecker::~XsdSchemaChecker()
78 * This method is called after the resolver has set the base type for every
79 * type and information about deriavtion and 'is simple type vs. is complex type'
82 void XsdSchemaChecker::basicCheck()
84 // first check that there is no circular inheritance, only the
85 // wxsSuperType is used here
86 checkBasicCircularInheritances();
88 // check the basic constraints like simple type can not inherit from complex type etc.
89 checkBasicSimpleTypeConstraints();
90 checkBasicComplexTypeConstraints();
93 void XsdSchemaChecker::check()
95 checkCircularInheritances();
96 checkInheritanceRestrictions();
97 checkSimpleDerivationRestrictions();
98 checkSimpleTypeConstraints();
99 checkComplexTypeConstraints();
100 checkDuplicatedAttributeUses();
102 checkElementConstraints();
103 checkAttributeConstraints();
104 checkAttributeUseConstraints();
105 // checkElementDuplicates();
108 void XsdSchemaChecker::addComponentLocationHash(const ComponentLocationHash &hash)
110 m_componentLocationHash.unite(hash);
114 * Checks whether the @p otherType is the same as @p myType or if one of its
115 * ancestors is the same as @p myType.
117 static bool matchesType(const SchemaType::Ptr &myType, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> visitedTypes)
122 if (visitedTypes.contains(otherType)) {
125 visitedTypes.insert(otherType);
127 // simple types can have different varieties, so we have to check each of them
128 if (otherType->isSimpleType()) {
129 const XsdSimpleType::Ptr simpleType = otherType;
130 if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) {
131 // for atomic type we use the same test as in SchemaType::wxsTypeMatches
132 retval = (myType == simpleType ? true : matchesType(myType, simpleType->wxsSuperType(), visitedTypes));
133 } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
134 // for list type we test against the itemType property
135 retval = (myType == simpleType->itemType() ? true : matchesType(myType, simpleType->itemType()->wxsSuperType(), visitedTypes));
136 } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
137 // for union type we test against each member type
138 const XsdSimpleType::List members = simpleType->memberTypes();
139 for (int i = 0; i < members.count(); ++i) {
140 if (myType == members.at(i) ? true : matchesType(myType, members.at(i)->wxsSuperType(), visitedTypes)) {
146 // reached xsAnySimple type whichs category is None
150 // if no simple type we handle it like in SchemaType::wxsTypeMatches
151 retval = (myType == otherType ? true : matchesType(myType, otherType->wxsSuperType(), visitedTypes));
153 } else // if otherType is null it doesn't match
160 * Checks whether there is a circular inheritance for the union inheritance.
162 static bool hasCircularUnionInheritance(const XsdSimpleType::Ptr &type, const SchemaType::Ptr &otherType, NamePool::Ptr &namePool)
164 if (type == otherType) {
168 if (!otherType->isSimpleType() || !otherType->isDefinedBySchema()) {
172 const XsdSimpleType::Ptr simpleOtherType = otherType;
174 if (simpleOtherType->category() == XsdSimpleType::SimpleTypeUnion) {
175 const XsdSimpleType::List memberTypes = simpleOtherType->memberTypes();
176 for (int i = 0; i < memberTypes.count(); ++i) {
177 if (otherType->wxsSuperType() == type) {
180 if (hasCircularUnionInheritance(type, memberTypes.at(i), namePool)) {
189 static inline bool wxsTypeMatches(const SchemaType::Ptr &type, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> &visitedTypes, SchemaType::Ptr &conflictingType)
194 if (visitedTypes.contains(otherType)) { // inheritance loop detected
195 conflictingType = otherType;
198 visitedTypes.insert(otherType);
201 if (type == otherType)
204 return wxsTypeMatches(type, otherType->wxsSuperType(), visitedTypes, conflictingType);
207 void XsdSchemaChecker::checkBasicCircularInheritances()
209 // check all global types...
210 SchemaType::List types = m_schema->types();
212 // .. and anonymous types
213 types << m_schema->anonymousTypes();
215 for (int i = 0; i < types.count(); ++i) {
216 const SchemaType::Ptr type = types.at(i);
217 const QSourceLocation location = sourceLocationForType(type);
219 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3)
221 // check normal base type inheritance
222 QSet<SchemaType::Ptr> visitedTypes;
223 SchemaType::Ptr conflictingType;
225 if (wxsTypeMatches(type, type->wxsSuperType(), visitedTypes, conflictingType)) {
227 m_context->error(QtXmlPatterns::tr("%1 has inheritance loop in its base type %2.")
228 .arg(formatType(m_namePool, type))
229 .arg(formatType(m_namePool, conflictingType)),
230 XsdSchemaContext::XSDError, location);
232 m_context->error(QtXmlPatterns::tr("Circular inheritance of base type %1.").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location);
239 void XsdSchemaChecker::checkCircularInheritances()
241 // check all global types...
242 SchemaType::List types = m_schema->types();
244 // .. and anonymous types
245 types << m_schema->anonymousTypes();
247 for (int i = 0; i < types.count(); ++i) {
248 const SchemaType::Ptr type = types.at(i);
249 const QSourceLocation location = sourceLocationForType(type);
251 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3)
253 // check normal base type inheritance
254 QSet<SchemaType::Ptr> visitedTypes;
255 if (matchesType(type, type->wxsSuperType(), visitedTypes)) {
256 m_context->error(QtXmlPatterns::tr("Circular inheritance of base type %1.").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location);
260 // check union member inheritance
261 if (type->isSimpleType() && type->isDefinedBySchema()) {
262 const XsdSimpleType::Ptr simpleType = type;
263 if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
264 const XsdSimpleType::List memberTypes = simpleType->memberTypes();
265 for (int j = 0; j < memberTypes.count(); ++j) {
266 if (hasCircularUnionInheritance(simpleType, memberTypes.at(j), m_namePool)) {
267 m_context->error(QtXmlPatterns::tr("Circular inheritance of union %1.").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location);
276 void XsdSchemaChecker::checkInheritanceRestrictions()
278 // check all global types...
279 SchemaType::List types = m_schema->types();
281 // .. and anonymous types
282 types << m_schema->anonymousTypes();
284 for (int i = 0; i < types.count(); ++i) {
285 const SchemaType::Ptr type = types.at(i);
286 const QSourceLocation location = sourceLocationForType(type);
288 // check inheritance restrictions given by final property of base class
289 const SchemaType::Ptr baseType = type->wxsSuperType();
290 if (baseType->isDefinedBySchema()) {
291 if ((type->derivationMethod() == SchemaType::DerivationRestriction) && (baseType->derivationConstraints() & SchemaType::RestrictionConstraint)) {
292 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by restriction as the latter defines it as final.")
293 .arg(formatType(m_namePool, type))
294 .arg(formatType(m_namePool, baseType)), XsdSchemaContext::XSDError, location);
296 } else if ((type->derivationMethod() == SchemaType::DerivationExtension) && (baseType->derivationConstraints() & SchemaType::ExtensionConstraint)) {
297 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by extension as the latter defines it as final.")
298 .arg(formatType(m_namePool, type))
299 .arg(formatType(m_namePool, baseType)), XsdSchemaContext::XSDError, location);
306 void XsdSchemaChecker::checkBasicSimpleTypeConstraints()
308 // check all global types...
309 SchemaType::List types = m_schema->types();
311 // .. and anonymous types
312 types << m_schema->anonymousTypes();
314 for (int i = 0; i < types.count(); ++i) {
315 const SchemaType::Ptr type = types.at(i);
317 if (!type->isSimpleType())
320 const XsdSimpleType::Ptr simpleType = type;
322 const QSourceLocation location = sourceLocation(simpleType);
324 // check inheritance restrictions of simple type defined by schema constraints
325 const SchemaType::Ptr baseType = simpleType->wxsSuperType();
327 if (baseType->isComplexType() && (simpleType->name(m_namePool) != BuiltinTypes::xsAnySimpleType->name(m_namePool))) {
328 m_context->error(QtXmlPatterns::tr("Base type of simple type %1 cannot be complex type %2.")
329 .arg(formatType(m_namePool, simpleType))
330 .arg(formatType(m_namePool, baseType)),
331 XsdSchemaContext::XSDError, location);
335 if (baseType == BuiltinTypes::xsAnyType) {
336 if (type->name(m_namePool) != BuiltinTypes::xsAnySimpleType->name(m_namePool)) {
337 m_context->error(QtXmlPatterns::tr("Simple type %1 cannot have direct base type %2.")
338 .arg(formatType(m_namePool, simpleType))
339 .arg(formatType(m_namePool, BuiltinTypes::xsAnyType)),
340 XsdSchemaContext::XSDError, location);
347 void XsdSchemaChecker::checkSimpleTypeConstraints()
349 // check all global types...
350 SchemaType::List types = m_schema->types();
352 // .. and anonymous types
353 types << m_schema->anonymousTypes();
355 for (int i = 0; i < types.count(); ++i) {
356 const SchemaType::Ptr type = types.at(i);
358 if (!type->isSimpleType())
361 const XsdSimpleType::Ptr simpleType = type;
363 const QSourceLocation location = sourceLocation(simpleType);
365 if (simpleType->category() == XsdSimpleType::None) {
367 // check that no user defined type has xs:AnySimpleType as base type (except xs:AnyAtomicType)
368 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) {
369 if (simpleType->name(m_namePool) != BuiltinTypes::xsAnyAtomicType->name(m_namePool)) {
370 m_context->error(QtXmlPatterns::tr("Simple type %1 is not allowed to have base type %2.")
371 .arg(formatType(m_namePool, simpleType))
372 .arg(formatType(m_namePool, simpleType->wxsSuperType())),
373 XsdSchemaContext::XSDError, location);
377 // check that no user defined type has xs:AnyAtomicType as base type
378 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnyAtomicType->name(m_namePool)) {
379 m_context->error(QtXmlPatterns::tr("Simple type %1 is not allowed to have base type %2.")
380 .arg(formatType(m_namePool, simpleType))
381 .arg(formatType(m_namePool, simpleType->wxsSuperType())),
382 XsdSchemaContext::XSDError, location);
387 // @see http://www.w3.org/TR/xmlschema11-1/#d0e37310
388 if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) {
390 if ((simpleType->wxsSuperType()->category() != XsdSimpleType::SimpleTypeAtomic) && (simpleType->name(m_namePool) != BuiltinTypes::xsAnyAtomicType->name(m_namePool))) {
391 m_context->error(QtXmlPatterns::tr("Simple type %1 can only have simple atomic type as base type.")
392 .arg(formatType(m_namePool, simpleType)),
393 XsdSchemaContext::XSDError, location);
396 if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) {
397 m_context->error(QtXmlPatterns::tr("Simple type %1 cannot derive from %2 as the latter defines restriction as final.")
398 .arg(formatType(m_namePool, simpleType->wxsSuperType()))
399 .arg(formatType(m_namePool, simpleType)),
400 XsdSchemaContext::XSDError, location);
404 // checked by checkConstrainingFacets already
405 } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
406 const AnySimpleType::Ptr itemType = simpleType->itemType();
408 // 2.1 or @see http://www.w3.org/TR/xmlschema-2/#cos-list-of-atomic
409 if (itemType->category() != SchemaType::SimpleTypeAtomic && itemType->category() != SchemaType::SimpleTypeUnion) {
410 m_context->error(QtXmlPatterns::tr("Variety of item type of %1 must be either atomic or union.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
415 if (itemType->category() == SchemaType::SimpleTypeUnion && itemType->isDefinedBySchema()) {
416 const XsdSimpleType::Ptr simpleItemType = itemType;
417 const AnySimpleType::List memberTypes = simpleItemType->memberTypes();
418 for (int j = 0; j < memberTypes.count(); ++j) {
419 if (memberTypes.at(j)->category() != SchemaType::SimpleTypeAtomic) {
420 m_context->error(QtXmlPatterns::tr("Variety of member types of %1 must be atomic.").arg(formatType(m_namePool, simpleItemType)), XsdSchemaContext::XSDError, location);
427 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) {
428 if (itemType->isSimpleType() && itemType->isDefinedBySchema()) {
429 const XsdSimpleType::Ptr simpleItemType = itemType;
432 if (simpleItemType->derivationConstraints() & XsdSimpleType::ListConstraint) {
433 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by list as the latter defines it as final.")
434 .arg(formatType(m_namePool, simpleType))
435 .arg(formatType(m_namePool, simpleItemType)), XsdSchemaContext::XSDError, location);
440 const XsdFacet::Hash facets = simpleType->facets();
441 XsdFacet::HashIterator it(facets);
443 bool invalidFacetFound = false;
444 while (it.hasNext()) {
446 if (it.key() != XsdFacet::WhiteSpace) {
447 invalidFacetFound = true;
452 if (invalidFacetFound) {
453 m_context->error(QtXmlPatterns::tr("Simple type %1 is only allowed to have %2 facet.")
454 .arg(formatType(m_namePool, simpleType))
455 .arg(formatKeyword("whiteSpace")),
456 XsdSchemaContext::XSDError, location);
462 if (simpleType->wxsSuperType()->category() != XsdSimpleType::SimpleTypeList) {
463 m_context->error(QtXmlPatterns::tr("Base type of simple type %1 must have variety of type list.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
468 if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) {
469 m_context->error(QtXmlPatterns::tr("Base type of simple type %1 has defined derivation by restriction as final.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
474 if (!XsdSchemaHelper::isSimpleDerivationOk(itemType, XsdSimpleType::Ptr(simpleType->wxsSuperType())->itemType(), SchemaType::DerivationConstraints())) {
475 m_context->error(QtXmlPatterns::tr("Item type of base type does not match item type of %1.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
480 const XsdFacet::Hash facets = simpleType->facets();
481 XsdFacet::HashIterator it(facets);
483 bool invalidFacetFound = false;
484 XsdFacet::Type invalidFacetType = XsdFacet::None;
485 while (it.hasNext()) {
487 const XsdFacet::Type facetType = it.key();
488 if (facetType != XsdFacet::Length &&
489 facetType != XsdFacet::MinimumLength &&
490 facetType != XsdFacet::MaximumLength &&
491 facetType != XsdFacet::WhiteSpace &&
492 facetType != XsdFacet::Pattern &&
493 facetType != XsdFacet::Enumeration) {
494 invalidFacetType = facetType;
495 invalidFacetFound = true;
500 if (invalidFacetFound) {
501 m_context->error(QtXmlPatterns::tr("Simple type %1 contains not allowed facet type %2.")
502 .arg(formatType(m_namePool, simpleType))
503 .arg(formatKeyword(XsdFacet::typeName(invalidFacetType))),
504 XsdSchemaContext::XSDError, location);
509 // TODO: check value constraints
513 } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
514 const AnySimpleType::List memberTypes = simpleType->memberTypes();
516 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) { // 3.1.1
518 for (int i = 0; i < memberTypes.count(); ++i) {
519 const AnySimpleType::Ptr memberType = memberTypes.at(i);
521 if (memberType->derivationConstraints() & XsdSimpleType::UnionConstraint) {
522 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by union as the latter defines it as final.")
523 .arg(formatType(m_namePool, simpleType))
524 .arg(formatType(m_namePool, memberType)), XsdSchemaContext::XSDError, location);
530 if (!simpleType->facets().isEmpty()) {
531 m_context->error(QtXmlPatterns::tr("%1 is not allowed to have any facets.")
532 .arg(formatType(m_namePool, simpleType)),
533 XsdSchemaContext::XSDError, location);
538 if (simpleType->wxsSuperType()->category() != SchemaType::SimpleTypeUnion) {
539 m_context->error(QtXmlPatterns::tr("Base type %1 of simple type %2 must have variety of union.")
540 .arg(formatType(m_namePool, simpleType->wxsSuperType()))
541 .arg(formatType(m_namePool, simpleType)),
542 XsdSchemaContext::XSDError, location);
547 if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::DerivationRestriction) {
548 m_context->error(QtXmlPatterns::tr("Base type %1 of simple type %2 is not allowed to have restriction in %3 attribute.")
549 .arg(formatType(m_namePool, simpleType->wxsSuperType()))
550 .arg(formatType(m_namePool, simpleType))
551 .arg(formatAttribute("final")),
552 XsdSchemaContext::XSDError, location);
557 if (simpleType->wxsSuperType()->isDefinedBySchema()) {
558 const XsdSimpleType::Ptr simpleBaseType(simpleType->wxsSuperType());
560 AnySimpleType::List baseMemberTypes = simpleBaseType->memberTypes();
561 for (int i = 0; i < memberTypes.count(); ++i) {
562 const AnySimpleType::Ptr memberType = memberTypes.at(i);
563 const AnySimpleType::Ptr baseMemberType = baseMemberTypes.at(i);
565 if (!XsdSchemaHelper::isSimpleDerivationOk(memberType, baseMemberType, SchemaType::DerivationConstraints())) {
566 m_context->error(QtXmlPatterns::tr("Member type %1 cannot be derived from member type %2 of %3's base type %4.")
567 .arg(formatType(m_namePool, memberType))
568 .arg(formatType(m_namePool, baseMemberType))
569 .arg(formatType(m_namePool, simpleType))
570 .arg(formatType(m_namePool, simpleBaseType)),
571 XsdSchemaContext::XSDError, location);
577 const XsdFacet::Hash facets = simpleType->facets();
578 XsdFacet::HashIterator it(facets);
580 bool invalidFacetFound = false;
581 XsdFacet::Type invalidFacetType = XsdFacet::None;
582 while (it.hasNext()) {
584 const XsdFacet::Type facetType = it.key();
585 if (facetType != XsdFacet::Pattern &&
586 facetType != XsdFacet::Enumeration) {
587 invalidFacetType = facetType;
588 invalidFacetFound = true;
593 if (invalidFacetFound) {
594 m_context->error(QtXmlPatterns::tr("Simple type %1 contains not allowed facet type %2.")
595 .arg(formatType(m_namePool, simpleType))
596 .arg(formatKeyword(XsdFacet::typeName(invalidFacetType))),
597 XsdSchemaContext::XSDError, location);
602 // TODO: check value constraints
608 void XsdSchemaChecker::checkBasicComplexTypeConstraints()
610 // check all global types...
611 SchemaType::List types = m_schema->types();
613 // .. and anonymous types
614 types << m_schema->anonymousTypes();
616 for (int i = 0; i < types.count(); ++i) {
617 const SchemaType::Ptr type = types.at(i);
619 if (!type->isComplexType() || !type->isDefinedBySchema())
622 const XsdComplexType::Ptr complexType = type;
624 const QSourceLocation location = sourceLocation(complexType);
626 // check inheritance restrictions of complex type defined by schema constraints
627 const SchemaType::Ptr baseType = complexType->wxsSuperType();
629 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 2)
630 if (baseType->isSimpleType() && (complexType->derivationMethod() != XsdComplexType::DerivationExtension)) {
631 m_context->error(QtXmlPatterns::tr("Derivation method of %1 must be extension because the base type %2 is a simple type.")
632 .arg(formatType(m_namePool, complexType))
633 .arg(formatType(m_namePool, baseType)),
634 XsdSchemaContext::XSDError, location);
640 void XsdSchemaChecker::checkComplexTypeConstraints()
642 // check all global types...
643 SchemaType::List types = m_schema->types();
645 // .. and anonymous types
646 types << m_schema->anonymousTypes();
648 for (int i = 0; i < types.count(); ++i) {
649 const SchemaType::Ptr type = types.at(i);
651 if (!type->isComplexType() || !type->isDefinedBySchema())
654 const XsdComplexType::Ptr complexType = type;
656 const QSourceLocation location = sourceLocation(complexType);
658 if (complexType->contentType()->particle()) {
659 XsdElement::Ptr duplicatedElement;
660 if (XsdParticleChecker::hasDuplicatedElements(complexType->contentType()->particle(), m_namePool, duplicatedElement)) {
661 m_context->error(QtXmlPatterns::tr("Complex type %1 has duplicated element %2 in its content model.")
662 .arg(formatType(m_namePool, complexType))
663 .arg(formatKeyword(duplicatedElement->displayName(m_namePool))),
664 XsdSchemaContext::XSDError, location);
668 if (!XsdParticleChecker::isUPAConform(complexType->contentType()->particle(), m_namePool)) {
669 m_context->error(QtXmlPatterns::tr("Complex type %1 has non-deterministic content.")
670 .arg(formatType(m_namePool, complexType)),
671 XsdSchemaContext::XSDError, location);
676 // check inheritance restrictions of complex type defined by schema constraints
677 const SchemaType::Ptr baseType = complexType->wxsSuperType();
679 // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-extends
680 if (complexType->derivationMethod() == XsdComplexType::DerivationExtension) {
681 if (baseType->isComplexType() && baseType->isDefinedBySchema()) {
682 const XsdComplexType::Ptr complexBaseType = baseType;
684 // we can skip 1.1 here, as it is tested in checkInheritanceRestrictions() already
688 if (!XsdSchemaHelper::isValidAttributeUsesExtension(complexType->attributeUses(), complexBaseType->attributeUses(),
689 complexType->attributeWildcard(), complexBaseType->attributeWildcard(), m_context, errorMsg)) {
690 m_context->error(QtXmlPatterns::tr("Attributes of complex type %1 are not a valid extension of the attributes of base type %2: %3.")
691 .arg(formatType(m_namePool, complexType))
692 .arg(formatType(m_namePool, baseType))
694 XsdSchemaContext::XSDError, location);
699 bool validContentType = false;
700 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
701 if (complexType->contentType()->simpleType() == complexBaseType->contentType()->simpleType()) {
702 validContentType = true; // 1.4.1
704 } else if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
705 validContentType = true; // 1.4.2
707 if (complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed) { // 1.4.3.1
708 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
709 validContentType = true; // 1.4.3.2.1
710 } else { // 1.4.3.2.2
711 if (complexType->contentType()->particle()) { // our own check
712 if ((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) ||
713 (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) { // 1.4.3.2.2.1
714 if (isValidParticleExtension(complexType->contentType()->particle(), complexBaseType->contentType()->particle())) {
715 validContentType = true; // 1.4.3.2.2.2
719 // 1.4.3.2.2.3 and 1.4.3.2.2.4 handle 'open content' that we do not support yet
726 if (!validContentType) {
727 m_context->error(QtXmlPatterns::tr("Content model of complex type %1 is not a valid extension of content model of %2.")
728 .arg(formatType(m_namePool, complexType))
729 .arg(formatType(m_namePool, complexBaseType)),
730 XsdSchemaContext::XSDError, location);
734 } else if (baseType->isSimpleType()) {
736 if (complexType->contentType()->variety() != XsdComplexType::ContentType::Simple) {
737 m_context->error(QtXmlPatterns::tr("Complex type %1 must have simple content.")
738 .arg(formatType(m_namePool, complexType)),
739 XsdSchemaContext::XSDError, location);
743 if (complexType->contentType()->simpleType() != baseType) {
744 m_context->error(QtXmlPatterns::tr("Complex type %1 must have the same simple type as its base class %2.")
745 .arg(formatType(m_namePool, complexType))
746 .arg(formatType(m_namePool, baseType)),
747 XsdSchemaContext::XSDError, location);
751 // 2.2 tested in checkInheritanceRestrictions() already
753 } else if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) {
754 // @see http://www.w3.org/TR/xmlschema11-1/#d0e21402
755 const SchemaType::Ptr baseType(complexType->wxsSuperType());
757 bool derivationOk = false;
760 // we can partly skip 1 here, as it is tested in checkInheritanceRestrictions() already
761 if (baseType->isComplexType()) {
764 if (baseType->name(m_namePool) == BuiltinTypes::xsAnyType->name(m_namePool)) {
768 if (baseType->isDefinedBySchema()) {
769 const XsdComplexType::Ptr complexBaseType(baseType);
772 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
774 if (XsdSchemaHelper::isSimpleDerivationOk(complexType->contentType()->simpleType(), complexBaseType->contentType()->simpleType(), SchemaType::DerivationConstraints()))
778 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) {
779 if (XsdSchemaHelper::isParticleEmptiable(complexBaseType->contentType()->particle()))
785 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
787 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty)
791 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) {
792 if (XsdSchemaHelper::isParticleEmptiable(complexBaseType->contentType()->particle()))
798 if (((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) &&
799 (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) ||
801 (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) {
804 if (XsdParticleChecker::subsumes(complexBaseType->contentType()->particle(), complexType->contentType()->particle(), m_context, errorMsg))
811 m_context->error(QtXmlPatterns::tr("Complex type %1 cannot be derived from base type %2%3.")
812 .arg(formatType(m_namePool, complexType))
813 .arg(formatType(m_namePool, baseType))
814 .arg(errorMsg.isEmpty() ? QString() : QLatin1String(": ") + errorMsg),
815 XsdSchemaContext::XSDError, location);
819 if (baseType->isDefinedBySchema()) {
820 const XsdComplexType::Ptr complexBaseType(baseType);
823 if (!XsdSchemaHelper::isValidAttributeUsesRestriction(complexType->attributeUses(), complexBaseType->attributeUses(),
824 complexType->attributeWildcard(), complexBaseType->attributeWildcard(), m_context, errorMsg)) {
825 m_context->error(QtXmlPatterns::tr("Attributes of complex type %1 are not a valid restriction from the attributes of base type %2: %3.")
826 .arg(formatType(m_namePool, complexType))
827 .arg(formatType(m_namePool, baseType))
829 XsdSchemaContext::XSDError, location);
835 // check that complex type with simple content is not allowed to inherit from
836 // built in complex type xs:AnyType
837 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
838 if (baseType->name(m_namePool) == BuiltinTypes::xsAnyType->name(m_namePool)) {
839 m_context->error(QtXmlPatterns::tr("Complex type %1 with simple content cannot be derived from complex base type %2.")
840 .arg(formatType(m_namePool, complexType))
841 .arg(formatType(m_namePool, baseType)),
842 XsdSchemaContext::XSDError, location);
849 void XsdSchemaChecker::checkSimpleDerivationRestrictions()
851 // check all global types...
852 SchemaType::List types = m_schema->types();
854 // .. and anonymous types
855 types << m_schema->anonymousTypes();
857 for (int i = 0; i < types.count(); ++i) {
858 const SchemaType::Ptr type = types.at(i);
860 if (type->isComplexType())
863 if (type->category() != SchemaType::SimpleTypeList && type->category() != SchemaType::SimpleTypeUnion)
866 const XsdSimpleType::Ptr simpleType = type;
867 const QSourceLocation location = sourceLocation(simpleType);
869 // check all simple types derived by list
870 if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
871 const AnySimpleType::Ptr itemType = simpleType->itemType();
873 if (itemType->isComplexType()) {
874 m_context->error(QtXmlPatterns::tr("Item type of simple type %1 cannot be a complex type.")
875 .arg(formatType(m_namePool, simpleType)),
876 XsdSchemaContext::XSDError, location);
881 if (itemType->isSimpleType() && itemType->isDefinedBySchema()) {
882 const XsdSimpleType::Ptr simpleItemType = itemType;
883 if (simpleItemType->derivationConstraints() & XsdSimpleType::ListConstraint) {
884 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by list as the latter defines it as final.")
885 .arg(formatType(m_namePool, simpleType))
886 .arg(formatType(m_namePool, simpleItemType)),
887 XsdSchemaContext::XSDError, location);
892 // @see http://www.w3.org/TR/xmlschema-2/#cos-list-of-atomic
893 if (itemType->category() != SchemaType::SimpleTypeAtomic && itemType->category() != SchemaType::SimpleTypeUnion) {
894 m_context->error(QtXmlPatterns::tr("Variety of item type of %1 must be either atomic or union.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
898 if (itemType->category() == SchemaType::SimpleTypeUnion && itemType->isDefinedBySchema()) {
899 const XsdSimpleType::Ptr simpleItemType = itemType;
900 const AnySimpleType::List memberTypes = simpleItemType->memberTypes();
901 for (int j = 0; j < memberTypes.count(); ++j) {
902 if (memberTypes.at(j)->category() != SchemaType::SimpleTypeAtomic) {
903 m_context->error(QtXmlPatterns::tr("Variety of member types of %1 must be atomic.").arg(formatType(m_namePool, simpleItemType)), XsdSchemaContext::XSDError, location);
910 // check all simple types derived by union
911 if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
912 const AnySimpleType::List memberTypes = simpleType->memberTypes();
914 for (int i = 0; i < memberTypes.count(); ++i) {
915 const AnySimpleType::Ptr memberType = memberTypes.at(i);
917 if (memberType->isComplexType()) {
918 m_context->error(QtXmlPatterns::tr("Member type of simple type %1 cannot be a complex type.")
919 .arg(formatType(m_namePool, simpleType)),
920 XsdSchemaContext::XSDError, location);
924 // @see http://www.w3.org/TR/xmlschema-2/#cos-no-circular-unions
925 if (simpleType->name(m_namePool) == memberType->name(m_namePool)) {
926 m_context->error(QtXmlPatterns::tr("%1 is not allowed to have a member type with the same name as itself.")
927 .arg(formatType(m_namePool, simpleType)),
928 XsdSchemaContext::XSDError, location);
932 if (memberType->isSimpleType() && memberType->isDefinedBySchema()) {
933 const XsdSimpleType::Ptr simpleMemberType = memberType;
934 if (simpleMemberType->derivationConstraints() & XsdSimpleType::UnionConstraint) {
935 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by union as the latter defines it as final.")
936 .arg(formatType(m_namePool, simpleType))
937 .arg(formatType(m_namePool, simpleMemberType)),
938 XsdSchemaContext::XSDError, location);
947 void XsdSchemaChecker::checkConstrainingFacets()
949 // first the global simple types
950 const SchemaType::List types = m_schema->types();
951 for (int i = 0; i < types.count(); ++i) {
952 if (!(types.at(i)->isSimpleType()) || !(types.at(i)->isDefinedBySchema()))
955 const XsdSimpleType::Ptr simpleType = types.at(i);
956 checkConstrainingFacets(simpleType->facets(), simpleType);
959 // and afterwards all anonymous simple types
960 const SchemaType::List anonymousTypes = m_schema->anonymousTypes();
961 for (int i = 0; i < anonymousTypes.count(); ++i) {
962 if (!(anonymousTypes.at(i)->isSimpleType()) || !(anonymousTypes.at(i)->isDefinedBySchema()))
965 const XsdSimpleType::Ptr simpleType = anonymousTypes.at(i);
966 checkConstrainingFacets(simpleType->facets(), simpleType);
970 void XsdSchemaChecker::checkConstrainingFacets(const XsdFacet::Hash &facets, const XsdSimpleType::Ptr &simpleType)
972 if (facets.isEmpty())
975 SchemaType::Ptr comparableBaseType;
976 if (!simpleType->wxsSuperType()->isDefinedBySchema())
977 comparableBaseType = simpleType->wxsSuperType();
979 comparableBaseType = simpleType->primitiveType();
981 const XsdSchemaSourceLocationReflection reflection(sourceLocation(simpleType));
984 if (facets.contains(XsdFacet::Length)) {
985 const XsdFacet::Ptr lengthFacet = facets.value(XsdFacet::Length);
986 const DerivedInteger<TypeNonNegativeInteger>::Ptr lengthValue = lengthFacet->value();
988 // @see http://www.w3.org/TR/xmlschema-2/#length-minLength-maxLength
989 if (facets.contains(XsdFacet::MinimumLength)) {
990 const XsdFacet::Ptr minLengthFacet = facets.value(XsdFacet::MinimumLength);
991 const DerivedInteger<TypeNonNegativeInteger>::Ptr minLengthValue = minLengthFacet->value();
993 bool foundSuperMinimumLength = false;
994 SchemaType::Ptr baseType = simpleType->wxsSuperType();
996 const XsdFacet::Hash baseFacets = m_context->facetsForType(baseType);
997 if (baseFacets.contains(XsdFacet::MinimumLength) && !baseFacets.contains(XsdFacet::Length)) {
998 const DerivedInteger<TypeNonNegativeInteger>::Ptr superValue(baseFacets.value(XsdFacet::MinimumLength)->value());
999 if (minLengthValue->toInteger() == superValue->toInteger()) {
1000 foundSuperMinimumLength = true;
1005 baseType = baseType->wxsSuperType();
1008 if ((minLengthValue->toInteger() > lengthValue->toInteger()) || !foundSuperMinimumLength) {
1009 m_context->error(QtXmlPatterns::tr("%1 facet collides with %2 facet.")
1010 .arg(formatKeyword("length"))
1011 .arg(formatKeyword("minLength")),
1012 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1017 // @see http://www.w3.org/TR/xmlschema-2/#length-minLength-maxLength
1018 if (facets.contains(XsdFacet::MaximumLength)) {
1019 const XsdFacet::Ptr maxLengthFacet = facets.value(XsdFacet::MaximumLength);
1020 const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value();
1022 bool foundSuperMaximumLength = false;
1023 SchemaType::Ptr baseType = simpleType->wxsSuperType();
1025 const XsdFacet::Hash baseFacets = m_context->facetsForType(baseType);
1026 if (baseFacets.contains(XsdFacet::MaximumLength) && !baseFacets.contains(XsdFacet::Length)) {
1027 const DerivedInteger<TypeNonNegativeInteger>::Ptr superValue(baseFacets.value(XsdFacet::MaximumLength)->value());
1028 if (maxLengthValue->toInteger() == superValue->toInteger()) {
1029 foundSuperMaximumLength = true;
1034 baseType = baseType->wxsSuperType();
1037 if ((maxLengthValue->toInteger() < lengthValue->toInteger()) || !foundSuperMaximumLength) {
1038 m_context->error(QtXmlPatterns::tr("%1 facet collides with %2 facet.")
1039 .arg(formatKeyword("length"))
1040 .arg(formatKeyword("maxLength")),
1041 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1046 // @see http://www.w3.org/TR/xmlschema-2/#length-valid-restriction
1047 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1048 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1049 if (baseFacets.contains(XsdFacet::Length)) {
1050 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacets.value(XsdFacet::Length)->value();
1051 if (lengthValue->toInteger() != baseValue->toInteger()) {
1052 m_context->error(QtXmlPatterns::tr("%1 facet must have the same value as %2 facet of base type.")
1053 .arg(formatKeyword("length"))
1054 .arg(formatKeyword("length")),
1055 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1062 if (facets.contains(XsdFacet::MinimumLength)) {
1063 const XsdFacet::Ptr minLengthFacet = facets.value(XsdFacet::MinimumLength);
1064 const DerivedInteger<TypeNonNegativeInteger>::Ptr minLengthValue = minLengthFacet->value();
1066 if (facets.contains(XsdFacet::MaximumLength)) {
1067 const XsdFacet::Ptr maxLengthFacet = facets.value(XsdFacet::MaximumLength);
1068 const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value();
1070 // @see http://www.w3.org/TR/xmlschema-2/#minLength-less-than-equal-to-maxLength
1071 if (maxLengthValue->toInteger() < minLengthValue->toInteger()) {
1072 m_context->error(QtXmlPatterns::tr("%1 facet collides with %2 facet.")
1073 .arg(formatKeyword("minLength"))
1074 .arg(formatKeyword("maxLength")),
1075 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1079 // @see http://www.w3.org/TR/xmlschema-2/#minLength-valid-restriction
1080 //TODO: check parent facets
1083 // @see http://www.w3.org/TR/xmlschema-2/#minLength-valid-restriction
1084 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1085 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1086 if (baseFacets.contains(XsdFacet::MinimumLength)) {
1087 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacets.value(XsdFacet::MinimumLength)->value();
1088 if (minLengthValue->toInteger() < baseValue->toInteger()) {
1089 m_context->error(QtXmlPatterns::tr("%1 facet must be equal or greater than %2 facet of base type.")
1090 .arg(formatKeyword("minLength"))
1091 .arg(formatKeyword("minLength")),
1092 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1098 if (facets.contains(XsdFacet::MaximumLength)) {
1099 const XsdFacet::Ptr maxLengthFacet = facets.value(XsdFacet::MaximumLength);
1100 const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value();
1102 // @see http://www.w3.org/TR/xmlschema-2/#maxLength-valid-restriction
1103 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1104 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1105 if (baseFacets.contains(XsdFacet::MaximumLength)) {
1106 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue(baseFacets.value(XsdFacet::MaximumLength)->value());
1107 if (maxLengthValue->toInteger() > baseValue->toInteger()) {
1108 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type.")
1109 .arg(formatKeyword("maxLength"))
1110 .arg(formatKeyword("maxLength")),
1111 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1117 if (facets.contains(XsdFacet::Pattern)) {
1118 // we keep the patterns in separated facets
1119 // @see http://www.w3.org/TR/xmlschema-2/#src-multiple-patterns
1121 // @see http://www.w3.org/TR/xmlschema-2/#cvc-pattern-valid
1122 const XsdFacet::Ptr patternFacet = facets.value(XsdFacet::Pattern);
1123 const AtomicValue::List multiValue = patternFacet->multiValue();
1125 for (int i = 0; i < multiValue.count(); ++i) {
1126 const DerivedString<TypeString>::Ptr value = multiValue.at(i);
1127 QRegExp exp = PatternPlatform::parsePattern(value->stringValue(), m_context, &reflection);
1128 if (!exp.isValid()) {
1129 m_context->error(QtXmlPatterns::tr("%1 facet contains invalid regular expression").arg(formatKeyword("pattern.")), XsdSchemaContext::XSDError, sourceLocation(simpleType));
1134 if (facets.contains(XsdFacet::Enumeration)) {
1135 // @see http://www.w3.org/TR/xmlschema-2/#src-multiple-enumerations
1137 const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration);
1139 if (BuiltinTypes::xsNOTATION->wxsTypeMatches(simpleType)) {
1140 const AtomicValue::List notationNames = facet->multiValue();
1141 for (int k = 0; k < notationNames.count(); ++k) {
1142 const QNameValue::Ptr notationName = notationNames.at(k);
1143 if (!m_schema->notation(notationName->qName())) {
1144 m_context->error(QtXmlPatterns::tr("Unknown notation %1 used in %2 facet.")
1145 .arg(formatKeyword(m_namePool, notationName->qName()))
1146 .arg(formatKeyword("enumeration")),
1147 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1150 } else if (BuiltinTypes::xsQName->wxsTypeMatches(simpleType)) {
1152 const XsdTypeChecker checker(m_context, QVector<QXmlName>(), sourceLocation(simpleType));
1154 const AnySimpleType::Ptr baseType = simpleType->wxsSuperType();
1155 const XsdFacet::Hash baseFacets = XsdTypeChecker::mergedFacetsForType(baseType, m_context);
1157 const AtomicValue::List multiValue = facet->multiValue();
1158 for (int k = 0; k < multiValue.count(); ++k) {
1159 const QString stringValue = multiValue.at(k)->as<DerivedString<TypeString> >()->stringValue();
1160 const QString actualValue = XsdTypeChecker::normalizedValue(stringValue, baseFacets);
1163 if (!checker.isValidString(actualValue, baseType, errorMsg)) {
1164 m_context->error(QtXmlPatterns::tr("%1 facet contains invalid value %2: %3.")
1165 .arg(formatKeyword("enumeration"))
1166 .arg(formatData(stringValue))
1168 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1174 if (facets.contains(XsdFacet::WhiteSpace)) {
1175 const XsdFacet::Ptr whiteSpaceFacet = facets.value(XsdFacet::WhiteSpace);
1176 const DerivedString<TypeString>::Ptr whiteSpaceValue = whiteSpaceFacet->value();
1178 // @see http://www.w3.org/TR/xmlschema-2/#whiteSpace-valid-restriction
1179 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1180 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1181 if (baseFacets.contains(XsdFacet::WhiteSpace)) {
1182 const QString value = whiteSpaceValue->stringValue();
1183 const QString baseValue = DerivedString<TypeString>::Ptr(baseFacets.value(XsdFacet::WhiteSpace)->value())->stringValue();
1184 if (value == XsdSchemaToken::toString(XsdSchemaToken::Replace) || value == XsdSchemaToken::toString(XsdSchemaToken::Preserve)) {
1185 if (baseValue == XsdSchemaToken::toString(XsdSchemaToken::Collapse)) {
1186 m_context->error(QtXmlPatterns::tr("%1 facet cannot be %2 or %3 if %4 facet of base type is %5.")
1187 .arg(formatKeyword("whiteSpace"))
1188 .arg(formatData("replace"))
1189 .arg(formatData("preserve"))
1190 .arg(formatKeyword("whiteSpace"))
1191 .arg(formatData("collapse")),
1192 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1196 if (value == XsdSchemaToken::toString(XsdSchemaToken::Preserve) && baseValue == XsdSchemaToken::toString(XsdSchemaToken::Replace)) {
1197 m_context->error(QtXmlPatterns::tr("%1 facet cannot be %2 if %3 facet of base type is %4.")
1198 .arg(formatKeyword("whiteSpace"))
1199 .arg(formatData("preserve"))
1200 .arg(formatKeyword("whiteSpace"))
1201 .arg(formatData("replace")),
1202 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1208 if (facets.contains(XsdFacet::MaximumInclusive)) {
1209 const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumInclusive);
1211 // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-less-than-equal-to-maxInclusive
1212 if (facets.contains(XsdFacet::MinimumInclusive)) {
1213 const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumInclusive);
1215 if (comparableBaseType) {
1216 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterThan, maxFacet->value(), comparableBaseType, m_context, &reflection)) {
1217 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet.")
1218 .arg(formatKeyword("minInclusive"))
1219 .arg(formatKeyword("maxInclusive")),
1220 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1226 // @see http://www.w3.org/TR/xmlschema-2/#maxInclusive-valid-restriction
1227 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1228 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1229 if (baseFacets.contains(XsdFacet::MaximumInclusive)) {
1230 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumInclusive);
1231 if (comparableBaseType) {
1232 if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1233 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type.")
1234 .arg(formatKeyword("maxInclusive"))
1235 .arg(formatKeyword("maxInclusive")),
1236 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1241 if (baseFacets.contains(XsdFacet::MaximumExclusive)) {
1242 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumExclusive);
1243 if (comparableBaseType) {
1244 if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorGreaterOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1245 m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet of base type.")
1246 .arg(formatKeyword("maxInclusive"))
1247 .arg(formatKeyword("maxExclusive")),
1248 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1255 if (facets.contains(XsdFacet::MaximumExclusive)) {
1256 const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumExclusive);
1258 // @see http://www.w3.org/TR/xmlschema-2/#maxInclusive-maxExclusive
1259 if (facets.contains(XsdFacet::MaximumInclusive)) {
1260 m_context->error(QtXmlPatterns::tr("%1 facet and %2 facet cannot appear together.")
1261 .arg(formatKeyword("maxExclusive"))
1262 .arg(formatKeyword("maxInclusive")),
1263 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1267 // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-less-than-equal-to-maxExclusive
1268 if (facets.contains(XsdFacet::MinimumExclusive)) {
1269 const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumExclusive);
1270 if (comparableBaseType) {
1271 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterThan, maxFacet->value(), comparableBaseType, m_context, &reflection)) {
1272 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet.")
1273 .arg(formatKeyword("minExclusive"))
1274 .arg(formatKeyword("maxExclusive")),
1275 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1281 // @see http://www.w3.org/TR/xmlschema-2/#maxExclusive-valid-restriction
1282 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1283 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1284 if (baseFacets.contains(XsdFacet::MaximumExclusive)) {
1285 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumExclusive);
1286 if (comparableBaseType) {
1287 if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1288 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type.")
1289 .arg(formatKeyword("maxExclusive"))
1290 .arg(formatKeyword("maxExclusive")),
1291 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1296 if (baseFacets.contains(XsdFacet::MaximumInclusive)) {
1297 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumInclusive);
1298 if (comparableBaseType) {
1299 if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1300 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type.")
1301 .arg(formatKeyword("maxExclusive"))
1302 .arg(formatKeyword("maxInclusive")),
1303 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1308 if (baseFacets.contains(XsdFacet::MinimumInclusive)) {
1309 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumInclusive);
1310 if (comparableBaseType) {
1311 if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorLessOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1312 m_context->error(QtXmlPatterns::tr("%1 facet must be greater than %2 facet of base type.")
1313 .arg(formatKeyword("maxExclusive"))
1314 .arg(formatKeyword("minInclusive")),
1315 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1320 if (baseFacets.contains(XsdFacet::MinimumExclusive)) {
1321 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumExclusive);
1322 if (comparableBaseType) {
1323 if (XsdSchemaHelper::constructAndCompare(maxFacet->value(), AtomicComparator::OperatorLessOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1324 m_context->error(QtXmlPatterns::tr("%1 facet must be greater than %2 facet of base type.")
1325 .arg(formatKeyword("maxExclusive"))
1326 .arg(formatKeyword("minExclusive")),
1327 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1334 if (facets.contains(XsdFacet::MinimumExclusive)) {
1335 const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumExclusive);
1337 // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-minExclusive
1338 if (facets.contains(XsdFacet::MinimumInclusive)) {
1339 m_context->error(QtXmlPatterns::tr("%1 facet and %2 facet cannot appear together.")
1340 .arg(formatKeyword("minExclusive"))
1341 .arg(formatKeyword("minInclusive")),
1342 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1346 // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-less-than-maxInclusive
1347 if (facets.contains(XsdFacet::MaximumInclusive)) {
1348 const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumInclusive);
1349 if (comparableBaseType) {
1350 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterOrEqual, maxFacet->value(), comparableBaseType, m_context, &reflection)) {
1351 m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet.")
1352 .arg(formatKeyword("minExclusive"))
1353 .arg(formatKeyword("maxInclusive")),
1354 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1360 // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-valid-restriction
1361 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1362 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1363 if (baseFacets.contains(XsdFacet::MinimumExclusive)) {
1364 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumExclusive);
1365 if (comparableBaseType) {
1366 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorLessThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1367 m_context->error(QtXmlPatterns::tr("%1 facet must be greater than or equal to %2 facet of base type.")
1368 .arg(formatKeyword("minExclusive"))
1369 .arg(formatKeyword("minExclusive")),
1370 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1375 if (baseFacets.contains(XsdFacet::MaximumExclusive)) {
1376 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumExclusive);
1377 if (comparableBaseType) {
1378 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1379 m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet of base type.")
1380 .arg(formatKeyword("minExclusive"))
1381 .arg(formatKeyword("maxExclusive")),
1382 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1387 if (baseFacets.contains(XsdFacet::MaximumInclusive)) {
1388 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumInclusive);
1389 if (comparableBaseType) {
1390 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1391 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type.")
1392 .arg(formatKeyword("minExclusive"))
1393 .arg(formatKeyword("maxInclusive")),
1394 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1401 if (facets.contains(XsdFacet::MinimumInclusive)) {
1402 const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumInclusive);
1404 // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-less-than-maxExclusive
1405 if (facets.contains(XsdFacet::MaximumExclusive)) {
1406 const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumExclusive);
1407 if (comparableBaseType) {
1408 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterOrEqual, maxFacet->value(), comparableBaseType, m_context, &reflection)) {
1409 m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet.")
1410 .arg(formatKeyword("minInclusive"))
1411 .arg(formatKeyword("maxExclusive")),
1412 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1418 // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-valid-restriction
1419 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1420 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1421 if (baseFacets.contains(XsdFacet::MinimumInclusive)) {
1422 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumInclusive);
1423 if (comparableBaseType) {
1424 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorLessThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1425 m_context->error(QtXmlPatterns::tr("%1 facet must be greater than or equal to %2 facet of base type.")
1426 .arg(formatKeyword("minInclusive"))
1427 .arg(formatKeyword("minInclusive")),
1428 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1433 if (baseFacets.contains(XsdFacet::MinimumExclusive)) {
1434 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MinimumExclusive);
1435 if (comparableBaseType) {
1436 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorLessOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1437 m_context->error(QtXmlPatterns::tr("%1 facet must be greater than %2 facet of base type.")
1438 .arg(formatKeyword("minInclusive"))
1439 .arg(formatKeyword("minExclusive")),
1440 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1445 if (baseFacets.contains(XsdFacet::MaximumInclusive)) {
1446 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumInclusive);
1447 if (comparableBaseType) {
1448 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterThan, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1449 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type.")
1450 .arg(formatKeyword("minInclusive"))
1451 .arg(formatKeyword("maxInclusive")),
1452 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1457 if (baseFacets.contains(XsdFacet::MaximumExclusive)) {
1458 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::MaximumExclusive);
1459 if (comparableBaseType) {
1460 if (XsdSchemaHelper::constructAndCompare(minFacet->value(), AtomicComparator::OperatorGreaterOrEqual, baseFacet->value(), comparableBaseType, m_context, &reflection)) {
1461 m_context->error(QtXmlPatterns::tr("%1 facet must be less than %2 facet of base type.")
1462 .arg(formatKeyword("minInclusive"))
1463 .arg(formatKeyword("maxExclusive")),
1464 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1471 if (facets.contains(XsdFacet::TotalDigits)) {
1472 const XsdFacet::Ptr totalDigitsFacet = facets.value(XsdFacet::TotalDigits);
1473 const DerivedInteger<TypeNonNegativeInteger>::Ptr totalDigitsValue = totalDigitsFacet->value();
1475 // @see http://www.w3.org/TR/xmlschema-2/#totalDigits-valid-restriction
1476 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1477 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1478 if (baseFacets.contains(XsdFacet::TotalDigits)) {
1479 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::TotalDigits);
1480 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacet->value();
1482 if (totalDigitsValue->toInteger() > baseValue->toInteger()) {
1483 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type.")
1484 .arg(formatKeyword("totalDigits"))
1485 .arg(formatKeyword("totalDigits")),
1486 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1492 if (facets.contains(XsdFacet::FractionDigits)) {
1493 const XsdFacet::Ptr fractionDigitsFacet = facets.value(XsdFacet::FractionDigits);
1494 const DerivedInteger<TypeNonNegativeInteger>::Ptr fractionDigitsValue = fractionDigitsFacet->value();
1496 // http://www.w3.org/TR/xmlschema-2/#fractionDigits-totalDigits
1497 if (facets.contains(XsdFacet::TotalDigits)) {
1498 const XsdFacet::Ptr totalDigitsFacet = facets.value(XsdFacet::TotalDigits);
1499 const DerivedInteger<TypeNonNegativeInteger>::Ptr totalDigitsValue = totalDigitsFacet->value();
1501 if (fractionDigitsValue->toInteger() > totalDigitsValue->toInteger()) {
1502 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet.")
1503 .arg(formatKeyword("fractionDigits"))
1504 .arg(formatKeyword("totalDigits")),
1505 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1510 // @see http://www.w3.org/TR/xmlschema-2/#fractionDigits-valid-restriction
1511 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1512 const XsdFacet::Hash baseFacets = m_context->facetsForType(simpleType->wxsSuperType());
1513 if (baseFacets.contains(XsdFacet::FractionDigits)) {
1514 const XsdFacet::Ptr baseFacet = baseFacets.value(XsdFacet::FractionDigits);
1515 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacet->value();
1517 if (fractionDigitsValue->toInteger() > baseValue->toInteger()) {
1518 m_context->error(QtXmlPatterns::tr("%1 facet must be less than or equal to %2 facet of base type.")
1519 .arg(formatKeyword("fractionDigits"))
1520 .arg(formatKeyword("fractionDigits")),
1521 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1529 // check whether facets are allowed for simple types variety
1530 if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeAtomic) {
1531 if (simpleType->primitiveType()) {
1532 const QXmlName primitiveTypeName = simpleType->primitiveType()->name(m_namePool);
1533 if (m_allowedAtomicFacets.contains(primitiveTypeName)) {
1534 const QSet<XsdFacet::Type> allowedFacets = m_allowedAtomicFacets.value(primitiveTypeName);
1535 QSet<XsdFacet::Type> availableFacets = facets.keys().toSet();
1537 if (!availableFacets.subtract(allowedFacets).isEmpty()) {
1538 m_context->error(QtXmlPatterns::tr("Simple type contains not allowed facet %1.")
1539 .arg(formatKeyword(XsdFacet::typeName(availableFacets.toList().first()))),
1540 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1545 } else if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeList) {
1546 if (facets.contains(XsdFacet::MaximumInclusive) || facets.contains(XsdFacet::MinimumInclusive) ||
1547 facets.contains(XsdFacet::MaximumExclusive) || facets.contains(XsdFacet::MinimumExclusive) ||
1548 facets.contains(XsdFacet::TotalDigits) || facets.contains(XsdFacet::FractionDigits))
1550 m_context->error(QtXmlPatterns::tr("%1, %2, %3, %4, %5 and %6 facets are not allowed when derived by list.")
1551 .arg(formatKeyword("maxInclusive"))
1552 .arg(formatKeyword("maxExclusive"))
1553 .arg(formatKeyword("minInclusive"))
1554 .arg(formatKeyword("minExclusive"))
1555 .arg(formatKeyword("totalDigits"))
1556 .arg(formatKeyword("fractionDigits")),
1557 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1559 } else if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeUnion) {
1560 if (facets.contains(XsdFacet::MaximumInclusive) || facets.contains(XsdFacet::MinimumInclusive) ||
1561 facets.contains(XsdFacet::MaximumExclusive) || facets.contains(XsdFacet::MinimumExclusive) ||
1562 facets.contains(XsdFacet::TotalDigits) || facets.contains(XsdFacet::FractionDigits) ||
1563 facets.contains(XsdFacet::MinimumLength) || facets.contains(XsdFacet::MaximumLength) ||
1564 facets.contains(XsdFacet::Length) || facets.contains(XsdFacet::WhiteSpace))
1566 m_context->error(QtXmlPatterns::tr("Only %1 and %2 facets are allowed when derived by union.")
1567 .arg(formatKeyword("pattern"))
1568 .arg(formatKeyword("enumeration")),
1569 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1573 // check whether value of facet matches the value space of the simple types base type
1574 const SchemaType::Ptr baseType = simpleType->wxsSuperType();
1575 if (!baseType->isDefinedBySchema()) {
1576 const XsdSchemaSourceLocationReflection reflection(sourceLocation(simpleType));
1578 XsdFacet::HashIterator it(facets);
1579 while (it.hasNext()) {
1581 const XsdFacet::Ptr facet = it.value();
1582 if (facet->type() == XsdFacet::MaximumInclusive ||
1583 facet->type() == XsdFacet::MaximumExclusive ||
1584 facet->type() == XsdFacet::MinimumInclusive ||
1585 facet->type() == XsdFacet::MinimumExclusive) {
1586 const DerivedString<TypeString>::Ptr stringValue = facet->value();
1587 const AtomicValue::Ptr value = ValueFactory::fromLexical(stringValue->stringValue(), baseType, m_context, &reflection);
1588 if (value->hasError()) {
1589 m_context->error(QtXmlPatterns::tr("%1 contains %2 facet with invalid data: %3.")
1590 .arg(formatType(m_namePool, simpleType))
1591 .arg(formatKeyword(XsdFacet::typeName(facet->type())))
1592 .arg(formatData(stringValue->stringValue())),
1593 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1598 // @see http://www.w3.org/TR/xmlschema-2/#enumeration-valid-restriction
1599 if (facet->type() == XsdFacet::Enumeration && baseType != BuiltinTypes::xsNOTATION) {
1600 const AtomicValue::List multiValue = facet->multiValue();
1601 for (int j = 0; j < multiValue.count(); ++j) {
1602 const QString stringValue = DerivedString<TypeString>::Ptr(multiValue.at(j))->stringValue();
1603 const AtomicValue::Ptr value = ValueFactory::fromLexical(stringValue, baseType, m_context, &reflection);
1604 if (value->hasError()) {
1605 m_context->error(QtXmlPatterns::tr("%1 contains %2 facet with invalid data: %3.")
1606 .arg(formatType(m_namePool, simpleType))
1607 .arg(formatKeyword(XsdFacet::typeName(XsdFacet::Enumeration)))
1608 .arg(formatData(stringValue)),
1609 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1618 void XsdSchemaChecker::checkDuplicatedAttributeUses()
1620 // first all global attribute groups
1621 const XsdAttributeGroup::List attributeGroups = m_schema->attributeGroups();
1622 for (int i = 0; i < attributeGroups.count(); ++i) {
1623 const XsdAttributeGroup::Ptr attributeGroup = attributeGroups.at(i);
1624 const XsdAttributeUse::List uses = attributeGroup->attributeUses();
1626 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 4)
1627 XsdAttribute::Ptr conflictingAttribute;
1628 if (hasDuplicatedAttributeUses(uses, conflictingAttribute)) {
1629 m_context->error(QtXmlPatterns::tr("Attribute group %1 contains attribute %2 twice.")
1630 .arg(formatKeyword(attributeGroup->displayName(m_namePool)))
1631 .arg(formatKeyword(conflictingAttribute->displayName(m_namePool))),
1632 XsdSchemaContext::XSDError, sourceLocation(attributeGroup));
1636 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 5)
1637 if (hasMultipleIDAttributeUses(uses)) {
1638 m_context->error(QtXmlPatterns::tr("Attribute group %1 contains two different attributes that both have types derived from %2.")
1639 .arg(formatKeyword(attributeGroup->displayName(m_namePool)))
1640 .arg(formatType(m_namePool, BuiltinTypes::xsID)),
1641 XsdSchemaContext::XSDError, sourceLocation(attributeGroup));
1645 if (hasConstraintIDAttributeUse(uses, conflictingAttribute)) {
1646 m_context->error(QtXmlPatterns::tr("Attribute group %1 contains attribute %2 that has value constraint but type that inherits from %3.")
1647 .arg(formatKeyword(attributeGroup->displayName(m_namePool)))
1648 .arg(formatKeyword(conflictingAttribute->displayName(m_namePool)))
1649 .arg(formatType(m_namePool, BuiltinTypes::xsID)),
1650 XsdSchemaContext::XSDError, sourceLocation(attributeGroup));
1655 // then the global and anonymous complex types
1656 SchemaType::List types = m_schema->types();
1657 types << m_schema->anonymousTypes();
1659 for (int i = 0; i < types.count(); ++i) {
1660 if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema())
1663 const XsdComplexType::Ptr complexType = types.at(i);
1664 const XsdAttributeUse::List attributeUses = complexType->attributeUses();
1666 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 4)
1667 XsdAttribute::Ptr conflictingAttribute;
1668 if (hasDuplicatedAttributeUses(attributeUses, conflictingAttribute)) {
1669 m_context->error(QtXmlPatterns::tr("Complex type %1 contains attribute %2 twice.")
1670 .arg(formatType(m_namePool, complexType))
1671 .arg(formatKeyword(conflictingAttribute->displayName(m_namePool))),
1672 XsdSchemaContext::XSDError, sourceLocation(complexType));
1676 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 5)
1677 if (hasMultipleIDAttributeUses(attributeUses)) {
1678 m_context->error(QtXmlPatterns::tr("Complex type %1 contains two different attributes that both have types derived from %2.")
1679 .arg(formatType(m_namePool, complexType))
1680 .arg(formatType(m_namePool, BuiltinTypes::xsID)),
1681 XsdSchemaContext::XSDError, sourceLocation(complexType));
1685 if (hasConstraintIDAttributeUse(attributeUses, conflictingAttribute)) {
1686 m_context->error(QtXmlPatterns::tr("Complex type %1 contains attribute %2 that has value constraint but type that inherits from %3.")
1687 .arg(formatType(m_namePool, complexType))
1688 .arg(formatKeyword(conflictingAttribute->displayName(m_namePool)))
1689 .arg(formatType(m_namePool, BuiltinTypes::xsID)),
1690 XsdSchemaContext::XSDError, sourceLocation(complexType));
1696 void XsdSchemaChecker::checkElementConstraints()
1698 const QSet<XsdElement::Ptr> elements = collectAllElements(m_schema);
1699 QSetIterator<XsdElement::Ptr> it(elements);
1700 while (it.hasNext()) {
1701 const XsdElement::Ptr element = it.next();
1703 // @see http://www.w3.org/TR/xmlschema11-1/#e-props-correct
1705 // 2 and xs:ID check
1706 if (element->valueConstraint()) {
1707 const SchemaType::Ptr type = element->type();
1709 AnySimpleType::Ptr targetType;
1710 if (type->isSimpleType() && type->category() == SchemaType::SimpleTypeAtomic) {
1713 // if it is a XsdSimpleType, use its primitive type as target type
1714 if (type->isDefinedBySchema())
1715 targetType = XsdSimpleType::Ptr(type)->primitiveType();
1717 } else if (type->isComplexType() && type->isDefinedBySchema()) {
1718 const XsdComplexType::Ptr complexType(type);
1720 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
1721 const AnySimpleType::Ptr simpleType = complexType->contentType()->simpleType();
1722 if (simpleType->category() == AnySimpleType::SimpleTypeAtomic) {
1723 targetType = simpleType;
1725 if (simpleType->isDefinedBySchema())
1726 targetType = XsdSimpleType::Ptr(simpleType)->primitiveType();
1728 } else if (complexType->contentType()->variety() != XsdComplexType::ContentType::Mixed) {
1729 m_context->error(QtXmlPatterns::tr("Element %1 is not allowed to have a value constraint if its base type is complex.")
1730 .arg(formatKeyword(element->displayName(m_namePool))),
1731 XsdSchemaContext::XSDError, sourceLocation(element));
1735 if ((targetType == BuiltinTypes::xsID) || BuiltinTypes::xsID->wxsTypeMatches(type)) {
1736 m_context->error(QtXmlPatterns::tr("Element %1 is not allowed to have a value constraint if its type is derived from %2.")
1737 .arg(formatKeyword(element->displayName(m_namePool)))
1738 .arg(formatType(m_namePool, BuiltinTypes::xsID)),
1739 XsdSchemaContext::XSDError, sourceLocation(element));
1743 if (type->isSimpleType()) {
1745 if (!isValidValue(element->valueConstraint()->value(), type, errorMsg)) {
1746 m_context->error(QtXmlPatterns::tr("Value constraint of element %1 is not of elements type: %2.")
1747 .arg(formatKeyword(element->displayName(m_namePool)))
1749 XsdSchemaContext::XSDError, sourceLocation(element));
1752 } else if (type->isComplexType() && type->isDefinedBySchema()) {
1753 const XsdComplexType::Ptr complexType(type);
1754 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
1756 if (!isValidValue(element->valueConstraint()->value(), complexType->contentType()->simpleType(), errorMsg)) {
1757 m_context->error(QtXmlPatterns::tr("Value constraint of element %1 is not of elements type: %2.")
1758 .arg(formatKeyword(element->displayName(m_namePool)))
1760 XsdSchemaContext::XSDError, sourceLocation(element));
1767 if (!element->substitutionGroupAffiliations().isEmpty()) {
1769 if (!element->scope() || element->scope()->variety() != XsdElement::Scope::Global) {
1770 m_context->error(QtXmlPatterns::tr("Element %1 is not allowed to have substitution group affiliation as it is no global element.").arg(formatKeyword(element->displayName(m_namePool))),
1771 XsdSchemaContext::XSDError, sourceLocation(element));
1776 const XsdElement::List affiliations = element->substitutionGroupAffiliations();
1777 for (int i = 0; i < affiliations.count(); ++i) {
1778 const XsdElement::Ptr affiliation = affiliations.at(i);
1780 bool derivationOk = false;
1781 if (element->type()->isComplexType() && affiliation->type()->isComplexType()) {
1782 if (XsdSchemaHelper::isComplexDerivationOk(element->type(), affiliation->type(), affiliation->substitutionGroupExclusions())) {
1783 derivationOk = true;
1786 if (element->type()->isComplexType() && affiliation->type()->isSimpleType()) {
1787 if (XsdSchemaHelper::isComplexDerivationOk(element->type(), affiliation->type(), affiliation->substitutionGroupExclusions())) {
1788 derivationOk = true;
1791 if (element->type()->isSimpleType()) {
1792 if (XsdSchemaHelper::isSimpleDerivationOk(element->type(), affiliation->type(), affiliation->substitutionGroupExclusions())) {
1793 derivationOk = true;
1797 if (!derivationOk) {
1798 m_context->error(QtXmlPatterns::tr("Type of element %1 cannot be derived from type of substitution group affiliation.").arg(formatKeyword(element->displayName(m_namePool))),
1799 XsdSchemaContext::XSDError, sourceLocation(element));
1804 // 5 was checked in XsdSchemaResolver::resolveSubstitutionGroupAffiliations() already
1809 void XsdSchemaChecker::checkAttributeConstraints()
1811 // all global attributes
1812 XsdAttribute::List attributes = m_schema->attributes();
1814 // and all local attributes
1815 SchemaType::List types = m_schema->types();
1816 types << m_schema->anonymousTypes();
1818 for (int i = 0; i < types.count(); ++i) {
1819 if (!types.at(i)->isComplexType() || !types.at(i)->isDefinedBySchema())
1822 const XsdComplexType::Ptr complexType(types.at(i));
1823 const XsdAttributeUse::List uses = complexType->attributeUses();
1824 for (int j = 0; j < uses.count(); ++j)
1825 attributes.append(uses.at(j)->attribute());
1828 for (int i = 0; i < attributes.count(); ++i) {
1829 const XsdAttribute::Ptr attribute = attributes.at(i);
1831 if (!attribute->valueConstraint())
1834 if (attribute->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Default || attribute->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Fixed) {
1835 const SchemaType::Ptr type = attribute->type();
1838 if (!isValidValue(attribute->valueConstraint()->value(), attribute->type(), errorMsg)) {
1839 m_context->error(QtXmlPatterns::tr("Value constraint of attribute %1 is not of attributes type: %2.")
1840 .arg(formatKeyword(attribute->displayName(m_namePool)))
1842 XsdSchemaContext::XSDError, sourceLocation(attribute));
1847 if (BuiltinTypes::xsID->wxsTypeMatches(attribute->type())) {
1848 m_context->error(QtXmlPatterns::tr("Attribute %1 has value constraint but has type derived from %2.")
1849 .arg(formatKeyword(attribute->displayName(m_namePool)))
1850 .arg(formatType(m_namePool, BuiltinTypes::xsID)),
1851 XsdSchemaContext::XSDError, sourceLocation(attribute));
1857 bool XsdSchemaChecker::isValidValue(const QString &stringValue, const AnySimpleType::Ptr &type, QString &errorMsg) const
1859 if (BuiltinTypes::xsAnySimpleType->name(m_namePool) == type->name(m_namePool))
1860 return true; // no need to check xs:anyType content
1862 const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(type, m_context);
1863 const QString actualValue = XsdTypeChecker::normalizedValue(stringValue, facets);
1865 const XsdTypeChecker checker(m_context, QVector<QXmlName>(), QSourceLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1));
1866 return checker.isValidString(actualValue, type, errorMsg);
1869 void XsdSchemaChecker::checkAttributeUseConstraints()
1871 XsdComplexType::List complexTypes;
1873 SchemaType::List types = m_schema->types();
1874 types << m_schema->anonymousTypes();
1876 for (int i = 0; i < types.count(); ++i) {
1877 const SchemaType::Ptr type = types.at(i);
1878 if (type->isComplexType() && type->isDefinedBySchema())
1879 complexTypes.append(XsdComplexType::Ptr(type));
1882 for (int i = 0; i < complexTypes.count(); ++i) {
1883 const XsdComplexType::Ptr complexType(complexTypes.at(i));
1884 const SchemaType::Ptr baseType = complexType->wxsSuperType();
1885 if (!baseType || !baseType->isComplexType() || !baseType->isDefinedBySchema())
1888 const XsdComplexType::Ptr complexBaseType(baseType);
1890 const XsdAttributeUse::List attributeUses = complexType->attributeUses();
1891 QHash<QXmlName, XsdAttributeUse::Ptr> lookupHash;
1892 for (int j = 0; j < attributeUses.count(); ++j)
1893 lookupHash.insert(attributeUses.at(j)->attribute()->name(m_namePool), attributeUses.at(j));
1895 const XsdAttributeUse::List baseAttributeUses = complexBaseType->attributeUses();
1896 for (int j = 0; j < baseAttributeUses.count(); ++j) {
1897 const XsdAttributeUse::Ptr baseAttributeUse = baseAttributeUses.at(j);
1899 if (lookupHash.contains(baseAttributeUse->attribute()->name(m_namePool))) {
1900 const XsdAttributeUse::Ptr attributeUse = lookupHash.value(baseAttributeUse->attribute()->name(m_namePool));
1902 if (baseAttributeUse->useType() == XsdAttributeUse::RequiredUse) {
1903 if (attributeUse->useType() == XsdAttributeUse::OptionalUse || attributeUse->useType() == XsdAttributeUse::ProhibitedUse) {
1904 m_context->error(QtXmlPatterns::tr("%1 attribute in derived complex type must be %2 like in base type.")
1905 .arg(formatAttribute("use"))
1906 .arg(formatData("required")),
1907 XsdSchemaContext::XSDError, sourceLocation(complexType));
1912 if (baseAttributeUse->valueConstraint()) {
1913 if (baseAttributeUse->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Fixed) {
1914 if (!attributeUse->valueConstraint()) {
1915 m_context->error(QtXmlPatterns::tr("Attribute %1 in derived complex type must have %2 value constraint like in base type.")
1916 .arg(formatKeyword(attributeUse->attribute()->displayName(m_namePool)))
1917 .arg(formatData("fixed")),
1918 XsdSchemaContext::XSDError, sourceLocation(complexType));
1921 if (attributeUse->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Fixed) {
1922 const XsdTypeChecker checker(m_context, QVector<QXmlName>(), sourceLocation(complexType));
1923 if (!checker.valuesAreEqual(attributeUse->valueConstraint()->value(), baseAttributeUse->valueConstraint()->value(), attributeUse->attribute()->type())) {
1924 m_context->error(QtXmlPatterns::tr("Attribute %1 in derived complex type must have the same %2 value constraint like in base type.")
1925 .arg(formatKeyword(attributeUse->attribute()->displayName(m_namePool)))
1926 .arg(formatData("fixed")),
1927 XsdSchemaContext::XSDError, sourceLocation(complexType));
1931 m_context->error(QtXmlPatterns::tr("Attribute %1 in derived complex type must have %2 value constraint.")
1932 .arg(formatKeyword(attributeUse->attribute()->displayName(m_namePool)))
1933 .arg(formatData("fixed")),
1934 XsdSchemaContext::XSDError, sourceLocation(complexType));
1943 // additional check that process content property of attribute wildcard in derived type is
1944 // not weaker than the wildcard in base type
1945 const XsdWildcard::Ptr baseWildcard(complexBaseType->attributeWildcard());
1946 const XsdWildcard::Ptr derivedWildcard(complexType->attributeWildcard());
1947 if (baseWildcard && derivedWildcard) {
1948 if (!XsdSchemaHelper::checkWildcardProcessContents(baseWildcard, derivedWildcard)) {
1949 m_context->error(QtXmlPatterns::tr("processContent of base wildcard must be weaker than derived wildcard."), XsdSchemaContext::XSDError, sourceLocation(complexType));
1956 void XsdSchemaChecker::checkElementDuplicates()
1958 // check all global types...
1959 SchemaType::List types = m_schema->types();
1961 // .. and anonymous types
1962 types << m_schema->anonymousTypes();
1964 for (int i = 0; i < types.count(); ++i) {
1965 const SchemaType::Ptr type = types.at(i);
1967 if (!type->isComplexType() || !type->isDefinedBySchema())
1970 const XsdComplexType::Ptr complexType(type);
1972 if ((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) || (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) {
1973 DuplicatedElementMap elementMap;
1974 DuplicatedWildcardMap wildcardMap;
1976 checkElementDuplicates(complexType->contentType()->particle(), elementMap, wildcardMap);
1981 void XsdSchemaChecker::checkElementDuplicates(const XsdParticle::Ptr &particle, DuplicatedElementMap &elementMap, DuplicatedWildcardMap &wildcardMap)
1983 if (particle->term()->isElement()) {
1984 const XsdElement::Ptr element(particle->term());
1986 if (elementMap.contains(element->name(m_namePool))) {
1987 if (element->type() != elementMap.value(element->name(m_namePool))) {
1988 m_context->error(QtXmlPatterns::tr("Element %1 exists twice with different types.")
1989 .arg(formatKeyword(element->displayName(m_namePool))),
1990 XsdSchemaContext::XSDError, sourceLocation(element));
1994 elementMap.insert(element->name(m_namePool), element->type());
1997 // check substitution group affiliation
1998 const XsdElement::List substElements = element->substitutionGroupAffiliations();
1999 for (int i = 0; i < substElements.count(); ++i) {
2000 const XsdElement::Ptr substElement = substElements.at(i);
2001 if (elementMap.contains(substElement->name(m_namePool))) {
2002 if (substElement->type() != elementMap.value(substElement->name(m_namePool))) {
2003 m_context->error(QtXmlPatterns::tr("Element %1 exists twice with different types.")
2004 .arg(formatKeyword(substElement->displayName(m_namePool))),
2005 XsdSchemaContext::XSDError, sourceLocation(element));
2009 elementMap.insert(substElement->name(m_namePool), substElement->type());
2012 } else if (particle->term()->isModelGroup()) {
2013 const XsdModelGroup::Ptr group(particle->term());
2014 const XsdParticle::List particles = group->particles();
2015 for (int i = 0; i < particles.count(); ++i)
2016 checkElementDuplicates(particles.at(i), elementMap, wildcardMap);
2017 } else if (particle->term()->isWildcard()) {
2018 const XsdWildcard::Ptr wildcard(particle->term());
2021 if (!wildcardMap.contains(wildcard->namespaceConstraint()->variety())) {
2022 if (!wildcardMap.isEmpty())
2025 const XsdWildcard::Ptr otherWildcard = wildcardMap.value(wildcard->namespaceConstraint()->variety());
2026 if ((wildcard->processContents() != otherWildcard->processContents()) || (wildcard->namespaceConstraint()->namespaces() != otherWildcard->namespaceConstraint()->namespaces()))
2031 m_context->error(QtXmlPatterns::tr("Particle contains non-deterministic wildcards."), XsdSchemaContext::XSDError, sourceLocation(wildcard));
2034 wildcardMap.insert(wildcard->namespaceConstraint()->variety(), wildcard);
2039 QSourceLocation XsdSchemaChecker::sourceLocation(const NamedSchemaComponent::Ptr &component) const
2041 if (m_componentLocationHash.contains(component)) {
2042 return m_componentLocationHash.value(component);
2044 QSourceLocation location;
2045 location.setLine(1);
2046 location.setColumn(1);
2047 location.setUri(QString::fromLatin1("dummyUri"));
2053 QSourceLocation XsdSchemaChecker::sourceLocationForType(const SchemaType::Ptr &type) const
2055 if (type->isSimpleType())
2056 return sourceLocation(XsdSimpleType::Ptr(type));
2058 return sourceLocation(XsdComplexType::Ptr(type));