source: trunk/src/xmlpatterns/schema/qxsdschemachecker.cpp@ 769

Last change on this file since 769 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 109.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qxsdschemachecker_p.h"
43
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"
58
59#include "qxsdschemachecker_helper.cpp"
60
61QT_BEGIN_NAMESPACE
62
63using namespace QPatternist;
64
65XsdSchemaChecker::XsdSchemaChecker(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext)
66 : m_context(context)
67 , m_namePool(parserContext->namePool())
68 , m_schema(parserContext->schema())
69{
70 setupAllowedAtomicFacets();
71}
72
73XsdSchemaChecker::~XsdSchemaChecker()
74{
75}
76
77/*
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'
80 * are available.
81 */
82void XsdSchemaChecker::basicCheck()
83{
84 // first check that there is no circular inheritance, only the
85 // wxsSuperType is used here
86 checkBasicCircularInheritances();
87
88 // check the basic constraints like simple type can not inherit from complex type etc.
89 checkBasicSimpleTypeConstraints();
90 checkBasicComplexTypeConstraints();
91}
92
93void XsdSchemaChecker::check()
94{
95 checkCircularInheritances();
96 checkInheritanceRestrictions();
97 checkSimpleDerivationRestrictions();
98 checkSimpleTypeConstraints();
99 checkComplexTypeConstraints();
100 checkDuplicatedAttributeUses();
101
102 checkElementConstraints();
103 checkAttributeConstraints();
104 checkAttributeUseConstraints();
105// checkElementDuplicates();
106}
107
108void XsdSchemaChecker::addComponentLocationHash(const ComponentLocationHash &hash)
109{
110 m_componentLocationHash.unite(hash);
111}
112
113/**
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.
116 */
117static bool matchesType(const SchemaType::Ptr &myType, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> visitedTypes)
118{
119 bool retval = false;
120
121 if (otherType) {
122 if (visitedTypes.contains(otherType)) {
123 return true;
124 } else {
125 visitedTypes.insert(otherType);
126 }
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)) {
141 retval = true;
142 break;
143 }
144 }
145 } else {
146 // reached xsAnySimple type whichs category is None
147 retval = false;
148 }
149 } else {
150 // if no simple type we handle it like in SchemaType::wxsTypeMatches
151 retval = (myType == otherType ? true : matchesType(myType, otherType->wxsSuperType(), visitedTypes));
152 }
153 } else // if otherType is null it doesn't match
154 retval = false;
155
156 return retval;
157}
158
159/**
160 * Checks whether there is a circular inheritance for the union inheritance.
161 */
162static bool hasCircularUnionInheritance(const XsdSimpleType::Ptr &type, const SchemaType::Ptr &otherType, NamePool::Ptr &namePool)
163{
164 if (type == otherType) {
165 return true;
166 }
167
168 if (!otherType->isSimpleType() || !otherType->isDefinedBySchema()) {
169 return false;
170 }
171
172 const XsdSimpleType::Ptr simpleOtherType = otherType;
173
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) {
178 return true;
179 }
180 if (hasCircularUnionInheritance(type, memberTypes.at(i), namePool)) {
181 return true;
182 }
183 }
184 }
185
186 return false;
187}
188
189static inline bool wxsTypeMatches(const SchemaType::Ptr &type, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> &visitedTypes, SchemaType::Ptr &conflictingType)
190{
191 if (!otherType)
192 return false;
193
194 if (visitedTypes.contains(otherType)) { // inheritance loop detected
195 conflictingType = otherType;
196 return true;
197 } else {
198 visitedTypes.insert(otherType);
199 }
200
201 if (type == otherType)
202 return true;
203
204 return wxsTypeMatches(type, otherType->wxsSuperType(), visitedTypes, conflictingType);
205}
206
207void XsdSchemaChecker::checkBasicCircularInheritances()
208{
209 // check all global types...
210 SchemaType::List types = m_schema->types();
211
212 // .. and anonymous types
213 types << m_schema->anonymousTypes();
214
215 for (int i = 0; i < types.count(); ++i) {
216 const SchemaType::Ptr type = types.at(i);
217 const QSourceLocation location = sourceLocationForType(type);
218
219 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3)
220
221 // check normal base type inheritance
222 QSet<SchemaType::Ptr> visitedTypes;
223 SchemaType::Ptr conflictingType;
224
225 if (wxsTypeMatches(type, type->wxsSuperType(), visitedTypes, conflictingType)) {
226 if (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);
231 else
232 m_context->error(QtXmlPatterns::tr("Circular inheritance of base type %1.").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location);
233
234 return;
235 }
236 }
237}
238
239void XsdSchemaChecker::checkCircularInheritances()
240{
241 // check all global types...
242 SchemaType::List types = m_schema->types();
243
244 // .. and anonymous types
245 types << m_schema->anonymousTypes();
246
247 for (int i = 0; i < types.count(); ++i) {
248 const SchemaType::Ptr type = types.at(i);
249 const QSourceLocation location = sourceLocationForType(type);
250
251 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3)
252
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);
257 return;
258 }
259
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);
268 return;
269 }
270 }
271 }
272 }
273 }
274}
275
276void XsdSchemaChecker::checkInheritanceRestrictions()
277{
278 // check all global types...
279 SchemaType::List types = m_schema->types();
280
281 // .. and anonymous types
282 types << m_schema->anonymousTypes();
283
284 for (int i = 0; i < types.count(); ++i) {
285 const SchemaType::Ptr type = types.at(i);
286 const QSourceLocation location = sourceLocationForType(type);
287
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);
295 return;
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);
300 return;
301 }
302 }
303 }
304}
305
306void XsdSchemaChecker::checkBasicSimpleTypeConstraints()
307{
308 // check all global types...
309 SchemaType::List types = m_schema->types();
310
311 // .. and anonymous types
312 types << m_schema->anonymousTypes();
313
314 for (int i = 0; i < types.count(); ++i) {
315 const SchemaType::Ptr type = types.at(i);
316
317 if (!type->isSimpleType())
318 continue;
319
320 const XsdSimpleType::Ptr simpleType = type;
321
322 const QSourceLocation location = sourceLocation(simpleType);
323
324 // check inheritance restrictions of simple type defined by schema constraints
325 const SchemaType::Ptr baseType = simpleType->wxsSuperType();
326
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);
332 return;
333 }
334
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);
341 return;
342 }
343 }
344 }
345}
346
347void XsdSchemaChecker::checkSimpleTypeConstraints()
348{
349 // check all global types...
350 SchemaType::List types = m_schema->types();
351
352 // .. and anonymous types
353 types << m_schema->anonymousTypes();
354
355 for (int i = 0; i < types.count(); ++i) {
356 const SchemaType::Ptr type = types.at(i);
357
358 if (!type->isSimpleType())
359 continue;
360
361 const XsdSimpleType::Ptr simpleType = type;
362
363 const QSourceLocation location = sourceLocation(simpleType);
364
365 if (simpleType->category() == XsdSimpleType::None) {
366 // additional checks
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);
374 return;
375 }
376 }
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);
383 return;
384 }
385 }
386
387 // @see http://www.w3.org/TR/xmlschema11-1/#d0e37310
388 if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) {
389 // 1.1
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);
394 }
395 // 1.2
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);
401 }
402
403 // 1.3
404 // checked by checkConstrainingFacets already
405 } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
406 const AnySimpleType::Ptr itemType = simpleType->itemType();
407
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);
411 return;
412 }
413
414 // 2.1 second part
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);
421 return;
422 }
423 }
424 }
425
426 // 2.2.1
427 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) {
428 if (itemType->isSimpleType() && itemType->isDefinedBySchema()) {
429 const XsdSimpleType::Ptr simpleItemType = itemType;
430
431 // 2.2.1.1
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);
436 return;
437 }
438
439 // 2.2.1.2
440 const XsdFacet::Hash facets = simpleType->facets();
441 XsdFacet::HashIterator it(facets);
442
443 bool invalidFacetFound = false;
444 while (it.hasNext()) {
445 it.next();
446 if (it.key() != XsdFacet::WhiteSpace) {
447 invalidFacetFound = true;
448 break;
449 }
450 }
451
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);
457 return;
458 }
459 }
460 } else { // 2.2.2
461 // 2.2.2.1
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);
464 return;
465 }
466
467 // 2.2.2.2
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);
470 return;
471 }
472
473 // 2.2.2.3
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);
476 return;
477 }
478
479 // 2.2.2.4
480 const XsdFacet::Hash facets = simpleType->facets();
481 XsdFacet::HashIterator it(facets);
482
483 bool invalidFacetFound = false;
484 XsdFacet::Type invalidFacetType = XsdFacet::None;
485 while (it.hasNext()) {
486 it.next();
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;
496 break;
497 }
498 }
499
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);
505 return;
506 }
507
508 // 2.2.2.5
509 // TODO: check value constraints
510 }
511
512
513 } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
514 const AnySimpleType::List memberTypes = simpleType->memberTypes();
515
516 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) { // 3.1.1
517 // 3.3.1.1
518 for (int i = 0; i < memberTypes.count(); ++i) {
519 const AnySimpleType::Ptr memberType = memberTypes.at(i);
520
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);
525 return;
526 }
527 }
528
529 // 3.3.1.2
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);
534 return;
535 }
536 } else {
537 // 3.1.2.1
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);
543 return;
544 }
545
546 // 3.1.2.2
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);
553 return;
554 }
555
556 //3.1.2.3
557 if (simpleType->wxsSuperType()->isDefinedBySchema()) {
558 const XsdSimpleType::Ptr simpleBaseType(simpleType->wxsSuperType());
559
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);
564
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);
572 }
573 }
574 }
575
576 // 3.1.2.4
577 const XsdFacet::Hash facets = simpleType->facets();
578 XsdFacet::HashIterator it(facets);
579
580 bool invalidFacetFound = false;
581 XsdFacet::Type invalidFacetType = XsdFacet::None;
582 while (it.hasNext()) {
583 it.next();
584 const XsdFacet::Type facetType = it.key();
585 if (facetType != XsdFacet::Pattern &&
586 facetType != XsdFacet::Enumeration) {
587 invalidFacetType = facetType;
588 invalidFacetFound = true;
589 break;
590 }
591 }
592
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);
598 return;
599 }
600
601 // 3.1.2.5
602 // TODO: check value constraints
603 }
604 }
605 }
606}
607
608void XsdSchemaChecker::checkBasicComplexTypeConstraints()
609{
610 // check all global types...
611 SchemaType::List types = m_schema->types();
612
613 // .. and anonymous types
614 types << m_schema->anonymousTypes();
615
616 for (int i = 0; i < types.count(); ++i) {
617 const SchemaType::Ptr type = types.at(i);
618
619 if (!type->isComplexType() || !type->isDefinedBySchema())
620 continue;
621
622 const XsdComplexType::Ptr complexType = type;
623
624 const QSourceLocation location = sourceLocation(complexType);
625
626 // check inheritance restrictions of complex type defined by schema constraints
627 const SchemaType::Ptr baseType = complexType->wxsSuperType();
628
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);
635 return;
636 }
637 }
638}
639
640void XsdSchemaChecker::checkComplexTypeConstraints()
641{
642 // check all global types...
643 SchemaType::List types = m_schema->types();
644
645 // .. and anonymous types
646 types << m_schema->anonymousTypes();
647
648 for (int i = 0; i < types.count(); ++i) {
649 const SchemaType::Ptr type = types.at(i);
650
651 if (!type->isComplexType() || !type->isDefinedBySchema())
652 continue;
653
654 const XsdComplexType::Ptr complexType = type;
655
656 const QSourceLocation location = sourceLocation(complexType);
657
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);
665 return;
666 }
667
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);
672 return;
673 }
674 }
675
676 // check inheritance restrictions of complex type defined by schema constraints
677 const SchemaType::Ptr baseType = complexType->wxsSuperType();
678
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;
683
684 // we can skip 1.1 here, as it is tested in checkInheritanceRestrictions() already
685
686 // 1.2 and 1.3
687 QString errorMsg;
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))
693 .arg(errorMsg),
694 XsdSchemaContext::XSDError, location);
695 return;
696 }
697
698 // 1.4
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
703 }
704 } else if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
705 validContentType = true; // 1.4.2
706 } else { // 1.4.3
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
716 }
717 }
718 }
719 // 1.4.3.2.2.3 and 1.4.3.2.2.4 handle 'open content' that we do not support yet
720 }
721 }
722 }
723
724 // 1.5 WTF?!?
725
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);
731 return;
732 }
733
734 } else if (baseType->isSimpleType()) {
735 // 2.1
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);
740 return;
741 }
742
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);
748 return;
749 }
750
751 // 2.2 tested in checkInheritanceRestrictions() already
752 }
753 } else if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) {
754 // @see http://www.w3.org/TR/xmlschema11-1/#d0e21402
755 const SchemaType::Ptr baseType(complexType->wxsSuperType());
756
757 bool derivationOk = false;
758 QString errorMsg;
759
760 // we can partly skip 1 here, as it is tested in checkInheritanceRestrictions() already
761 if (baseType->isComplexType()) {
762
763 // 2.1
764 if (baseType->name(m_namePool) == BuiltinTypes::xsAnyType->name(m_namePool)) {
765 derivationOk = true;
766 }
767
768 if (baseType->isDefinedBySchema()) {
769 const XsdComplexType::Ptr complexBaseType(baseType);
770
771 // 2.2.1
772 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
773 // 2.2.2.1
774 if (XsdSchemaHelper::isSimpleDerivationOk(complexType->contentType()->simpleType(), complexBaseType->contentType()->simpleType(), SchemaType::DerivationConstraints()))
775 derivationOk = true;
776
777 // 2.2.2.2
778 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) {
779 if (XsdSchemaHelper::isParticleEmptiable(complexBaseType->contentType()->particle()))
780 derivationOk = true;
781 }
782 }
783
784 // 2.3.1
785 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
786 // 2.3.2.1
787 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty)
788 derivationOk = true;
789
790 // 2.3.2.2
791 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) {
792 if (XsdSchemaHelper::isParticleEmptiable(complexBaseType->contentType()->particle()))
793 derivationOk = true;
794 }
795 }
796
797 // 2.4.1.1
798 if (((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) &&
799 (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) ||
800 // 2.4.1.2
801 (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) {
802
803 // 2.4.2
804 if (XsdParticleChecker::subsumes(complexBaseType->contentType()->particle(), complexType->contentType()->particle(), m_context, errorMsg))
805 derivationOk = true;
806 }
807 }
808 }
809
810 if (!derivationOk) {
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);
816 return;
817 }
818
819 if (baseType->isDefinedBySchema()) {
820 const XsdComplexType::Ptr complexBaseType(baseType);
821
822 QString errorMsg;
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))
828 .arg(errorMsg),
829 XsdSchemaContext::XSDError, location);
830 return;
831 }
832 }
833 }
834
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);
843 return;
844 }
845 }
846 }
847}
848
849void XsdSchemaChecker::checkSimpleDerivationRestrictions()
850{
851 // check all global types...
852 SchemaType::List types = m_schema->types();
853
854 // .. and anonymous types
855 types << m_schema->anonymousTypes();
856
857 for (int i = 0; i < types.count(); ++i) {
858 const SchemaType::Ptr type = types.at(i);
859
860 if (type->isComplexType())
861 continue;
862
863 if (type->category() != SchemaType::SimpleTypeList && type->category() != SchemaType::SimpleTypeUnion)
864 continue;
865
866 const XsdSimpleType::Ptr simpleType = type;
867 const QSourceLocation location = sourceLocation(simpleType);
868
869 // check all simple types derived by list
870 if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
871 const AnySimpleType::Ptr itemType = simpleType->itemType();
872
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);
877 return;
878 }
879
880
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);
888 return;
889 }
890 }
891
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);
895 return;
896 }
897
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);
904 return;
905 }
906 }
907 }
908 }
909
910 // check all simple types derived by union
911 if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
912 const AnySimpleType::List memberTypes = simpleType->memberTypes();
913
914 for (int i = 0; i < memberTypes.count(); ++i) {
915 const AnySimpleType::Ptr memberType = memberTypes.at(i);
916
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);
921 return;
922 }
923
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);
929 return;
930 }
931
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);
939 return;
940 }
941 }
942 }
943 }
944 }
945}
946
947void XsdSchemaChecker::checkConstrainingFacets()
948{
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()))
953 continue;
954
955 const XsdSimpleType::Ptr simpleType = types.at(i);
956 checkConstrainingFacets(simpleType->facets(), simpleType);
957 }
958
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()))
963 continue;
964
965 const XsdSimpleType::Ptr simpleType = anonymousTypes.at(i);
966 checkConstrainingFacets(simpleType->facets(), simpleType);
967 }
968}
969
970void XsdSchemaChecker::checkConstrainingFacets(const XsdFacet::Hash &facets, const XsdSimpleType::Ptr &simpleType)
971{
972 if (facets.isEmpty())
973 return;
974
975 SchemaType::Ptr comparableBaseType;
976 if (!simpleType->wxsSuperType()->isDefinedBySchema())
977 comparableBaseType = simpleType->wxsSuperType();
978 else
979 comparableBaseType = simpleType->primitiveType();
980
981 const XsdSchemaSourceLocationReflection reflection(sourceLocation(simpleType));
982
983 // start checks
984 if (facets.contains(XsdFacet::Length)) {
985 const XsdFacet::Ptr lengthFacet = facets.value(XsdFacet::Length);
986 const DerivedInteger<TypeNonNegativeInteger>::Ptr lengthValue = lengthFacet->value();
987
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();
992
993 bool foundSuperMinimumLength = false;
994 SchemaType::Ptr baseType = simpleType->wxsSuperType();
995 while (baseType) {
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;
1001 break;
1002 }
1003 }
1004
1005 baseType = baseType->wxsSuperType();
1006 }
1007
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));
1013 return;
1014 }
1015 }
1016
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();
1021
1022 bool foundSuperMaximumLength = false;
1023 SchemaType::Ptr baseType = simpleType->wxsSuperType();
1024 while (baseType) {
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;
1030 break;
1031 }
1032 }
1033
1034 baseType = baseType->wxsSuperType();
1035 }
1036
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));
1042 return;
1043 }
1044 }
1045
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));
1056 return;
1057 }
1058 }
1059 }
1060 }
1061
1062 if (facets.contains(XsdFacet::MinimumLength)) {
1063 const XsdFacet::Ptr minLengthFacet = facets.value(XsdFacet::MinimumLength);
1064 const DerivedInteger<TypeNonNegativeInteger>::Ptr minLengthValue = minLengthFacet->value();
1065
1066 if (facets.contains(XsdFacet::MaximumLength)) {
1067 const XsdFacet::Ptr maxLengthFacet = facets.value(XsdFacet::MaximumLength);
1068 const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value();
1069
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));
1076 return;
1077 }
1078
1079 // @see http://www.w3.org/TR/xmlschema-2/#minLength-valid-restriction
1080 //TODO: check parent facets
1081 }
1082
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));
1093 return;
1094 }
1095 }
1096 }
1097 }
1098 if (facets.contains(XsdFacet::MaximumLength)) {
1099 const XsdFacet::Ptr maxLengthFacet = facets.value(XsdFacet::MaximumLength);
1100 const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value();
1101
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));
1112 return;
1113 }
1114 }
1115 }
1116 }
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
1120
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();
1124
1125 for (int i = 0; i < multiValue.count(); ++i) {
1126 const DerivedString<TypeString>::Ptr value = multiValue.at(i);
1127 const 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));
1130 return;
1131 }
1132 }
1133 }
1134 if (facets.contains(XsdFacet::Enumeration)) {
1135 // @see http://www.w3.org/TR/xmlschema-2/#src-multiple-enumerations
1136
1137 const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration);
1138
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));
1148 }
1149 }
1150 } else if (BuiltinTypes::xsQName->wxsTypeMatches(simpleType)) {
1151 } else {
1152 const XsdTypeChecker checker(m_context, QVector<QXmlName>(), sourceLocation(simpleType));
1153
1154 const AnySimpleType::Ptr baseType = simpleType->wxsSuperType();
1155 const XsdFacet::Hash baseFacets = XsdTypeChecker::mergedFacetsForType(baseType, m_context);
1156
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);
1161
1162 QString errorMsg;
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))
1167 .arg(errorMsg),
1168 XsdSchemaContext::XSDError, sourceLocation(simpleType));
1169 return;
1170 }
1171 }
1172 }
1173 }
1174 if (facets.contains(XsdFacet::WhiteSpace)) {
1175 const XsdFacet::Ptr whiteSpaceFacet = facets.value(XsdFacet::WhiteSpace);
1176 const DerivedString<TypeString>::Ptr whiteSpaceValue = whiteSpaceFacet->value();
1177
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));
1193 return;
1194 }
1195 }
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));
1203 return;
1204 }
1205 }
1206 }
1207 }
1208 if (facets.contains(XsdFacet::MaximumInclusive)) {
1209 const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumInclusive);
1210
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);
1214
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));
1221 return;
1222 }
1223 }
1224 }
1225
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));
1237 return;
1238 }
1239 }
1240 }
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));
1249 return;
1250 }
1251 }
1252 }
1253 }
1254 }
1255 if (facets.contains(XsdFacet::MaximumExclusive)) {
1256 const XsdFacet::Ptr maxFacet = facets.value(XsdFacet::MaximumExclusive);
1257
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));
1264 return;
1265 }
1266
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));
1276 return;
1277 }
1278 }
1279 }
1280
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));
1292 return;
1293 }
1294 }
1295 }
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));
1304 return;
1305 }
1306 }
1307 }
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));
1316 return;
1317 }
1318 }
1319 }
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));
1328 return;
1329 }
1330 }
1331 }
1332 }
1333 }
1334 if (facets.contains(XsdFacet::MinimumExclusive)) {
1335 const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumExclusive);
1336
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));
1343 return;
1344 }
1345
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));
1355 return;
1356 }
1357 }
1358 }
1359
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));
1371 return;
1372 }
1373 }
1374 }
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));
1383 return;
1384 }
1385 }
1386 }
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));
1395 return;
1396 }
1397 }
1398 }
1399 }
1400 }
1401 if (facets.contains(XsdFacet::MinimumInclusive)) {
1402 const XsdFacet::Ptr minFacet = facets.value(XsdFacet::MinimumInclusive);
1403
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));
1413 return;
1414 }
1415 }
1416 }
1417
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));
1429 return;
1430 }
1431 }
1432 }
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));
1441 return;
1442 }
1443 }
1444 }
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));
1453 return;
1454 }
1455 }
1456 }
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));
1465 return;
1466 }
1467 }
1468 }
1469 }
1470 }
1471 if (facets.contains(XsdFacet::TotalDigits)) {
1472 const XsdFacet::Ptr totalDigitsFacet = facets.value(XsdFacet::TotalDigits);
1473 const DerivedInteger<TypeNonNegativeInteger>::Ptr totalDigitsValue = totalDigitsFacet->value();
1474
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();
1481
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));
1487 return;
1488 }
1489 }
1490 }
1491 }
1492 if (facets.contains(XsdFacet::FractionDigits)) {
1493 const XsdFacet::Ptr fractionDigitsFacet = facets.value(XsdFacet::FractionDigits);
1494 const DerivedInteger<TypeNonNegativeInteger>::Ptr fractionDigitsValue = fractionDigitsFacet->value();
1495
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();
1500
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));
1506 return;
1507 }
1508 }
1509
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();
1516
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));
1522 return;
1523 }
1524 }
1525 }
1526 }
1527
1528
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();
1536
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));
1541 return;
1542 }
1543 }
1544 }
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))
1549 {
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));
1558 }
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))
1565 {
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));
1570 }
1571 }
1572
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));
1577
1578 XsdFacet::HashIterator it(facets);
1579 while (it.hasNext()) {
1580 it.next();
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));
1594 return;
1595 }
1596 }
1597
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));
1610 return;
1611 }
1612 }
1613 }
1614 }
1615 }
1616}
1617
1618void XsdSchemaChecker::checkDuplicatedAttributeUses()
1619{
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();
1625
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));
1633 return;
1634 }
1635
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));
1642 return;
1643 }
1644
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));
1651 return;
1652 }
1653 }
1654
1655 // then the global and anonymous complex types
1656 SchemaType::List types = m_schema->types();
1657 types << m_schema->anonymousTypes();
1658
1659 for (int i = 0; i < types.count(); ++i) {
1660 if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema())
1661 continue;
1662
1663 const XsdComplexType::Ptr complexType = types.at(i);
1664 const XsdAttributeUse::List attributeUses = complexType->attributeUses();
1665
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));
1673 return;
1674 }
1675
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));
1682 return;
1683 }
1684
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));
1691 return;
1692 }
1693 }
1694}
1695
1696void XsdSchemaChecker::checkElementConstraints()
1697{
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();
1702
1703 // @see http://www.w3.org/TR/xmlschema11-1/#e-props-correct
1704
1705 // 2 and xs:ID check
1706 if (element->valueConstraint()) {
1707 const SchemaType::Ptr type = element->type();
1708
1709 AnySimpleType::Ptr targetType;
1710 if (type->isSimpleType() && type->category() == SchemaType::SimpleTypeAtomic) {
1711 targetType = type;
1712
1713 // if it is a XsdSimpleType, use its primitive type as target type
1714 if (type->isDefinedBySchema())
1715 targetType = XsdSimpleType::Ptr(type)->primitiveType();
1716
1717 } else if (type->isComplexType() && type->isDefinedBySchema()) {
1718 const XsdComplexType::Ptr complexType(type);
1719
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;
1724
1725 if (simpleType->isDefinedBySchema())
1726 targetType = XsdSimpleType::Ptr(simpleType)->primitiveType();
1727 }
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));
1732 return;
1733 }
1734 }
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));
1740 return;
1741 }
1742
1743 if (type->isSimpleType()) {
1744 QString errorMsg;
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)))
1748 .arg(errorMsg),
1749 XsdSchemaContext::XSDError, sourceLocation(element));
1750 return;
1751 }
1752 } else if (type->isComplexType() && type->isDefinedBySchema()) {
1753 const XsdComplexType::Ptr complexType(type);
1754 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
1755 QString errorMsg;
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)))
1759 .arg(errorMsg),
1760 XsdSchemaContext::XSDError, sourceLocation(element));
1761 return;
1762 }
1763 }
1764 }
1765 }
1766
1767 if (!element->substitutionGroupAffiliations().isEmpty()) {
1768 // 3
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));
1772 return;
1773 }
1774
1775 // 4
1776 const XsdElement::List affiliations = element->substitutionGroupAffiliations();
1777 for (int i = 0; i < affiliations.count(); ++i) {
1778 const XsdElement::Ptr affiliation = affiliations.at(i);
1779
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;
1784 }
1785 }
1786 if (element->type()->isComplexType() && affiliation->type()->isSimpleType()) {
1787 if (XsdSchemaHelper::isComplexDerivationOk(element->type(), affiliation->type(), affiliation->substitutionGroupExclusions())) {
1788 derivationOk = true;
1789 }
1790 }
1791 if (element->type()->isSimpleType()) {
1792 if (XsdSchemaHelper::isSimpleDerivationOk(element->type(), affiliation->type(), affiliation->substitutionGroupExclusions())) {
1793 derivationOk = true;
1794 }
1795 }
1796
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));
1800 return;
1801 }
1802 }
1803
1804 // 5 was checked in XsdSchemaResolver::resolveSubstitutionGroupAffiliations() already
1805 }
1806 }
1807}
1808
1809void XsdSchemaChecker::checkAttributeConstraints()
1810{
1811 // all global attributes
1812 XsdAttribute::List attributes = m_schema->attributes();
1813
1814 // and all local attributes
1815 SchemaType::List types = m_schema->types();
1816 types << m_schema->anonymousTypes();
1817
1818 for (int i = 0; i < types.count(); ++i) {
1819 if (!types.at(i)->isComplexType() || !types.at(i)->isDefinedBySchema())
1820 continue;
1821
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());
1826 }
1827
1828 for (int i = 0; i < attributes.count(); ++i) {
1829 const XsdAttribute::Ptr attribute = attributes.at(i);
1830
1831 if (!attribute->valueConstraint())
1832 continue;
1833
1834 if (attribute->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Default || attribute->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Fixed) {
1835 const SchemaType::Ptr type = attribute->type();
1836
1837 QString errorMsg;
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)))
1841 .arg(errorMsg),
1842 XsdSchemaContext::XSDError, sourceLocation(attribute));
1843 return;
1844 }
1845 }
1846
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));
1852 return;
1853 }
1854 }
1855}
1856
1857bool XsdSchemaChecker::isValidValue(const QString &stringValue, const AnySimpleType::Ptr &type, QString &errorMsg) const
1858{
1859 if (BuiltinTypes::xsAnySimpleType->name(m_namePool) == type->name(m_namePool))
1860 return true; // no need to check xs:anyType content
1861
1862 const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(type, m_context);
1863 const QString actualValue = XsdTypeChecker::normalizedValue(stringValue, facets);
1864
1865 const XsdTypeChecker checker(m_context, QVector<QXmlName>(), QSourceLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1));
1866 return checker.isValidString(actualValue, type, errorMsg);
1867}
1868
1869void XsdSchemaChecker::checkAttributeUseConstraints()
1870{
1871 XsdComplexType::List complexTypes;
1872
1873 SchemaType::List types = m_schema->types();
1874 types << m_schema->anonymousTypes();
1875
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));
1880 }
1881
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())
1886 continue;
1887
1888 const XsdComplexType::Ptr complexBaseType(baseType);
1889
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));
1894
1895 const XsdAttributeUse::List baseAttributeUses = complexBaseType->attributeUses();
1896 for (int j = 0; j < baseAttributeUses.count(); ++j) {
1897 const XsdAttributeUse::Ptr baseAttributeUse = baseAttributeUses.at(j);
1898
1899 if (lookupHash.contains(baseAttributeUse->attribute()->name(m_namePool))) {
1900 const XsdAttributeUse::Ptr attributeUse = lookupHash.value(baseAttributeUse->attribute()->name(m_namePool));
1901
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));
1908 return;
1909 }
1910 }
1911
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));
1919 return;
1920 } else {
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));
1928 return;
1929 }
1930 } else {
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));
1935 return;
1936 }
1937 }
1938 }
1939 }
1940 }
1941 }
1942
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));
1950 return;
1951 }
1952 }
1953 }
1954}
1955
1956void XsdSchemaChecker::checkElementDuplicates()
1957{
1958 // check all global types...
1959 SchemaType::List types = m_schema->types();
1960
1961 // .. and anonymous types
1962 types << m_schema->anonymousTypes();
1963
1964 for (int i = 0; i < types.count(); ++i) {
1965 const SchemaType::Ptr type = types.at(i);
1966
1967 if (!type->isComplexType() || !type->isDefinedBySchema())
1968 continue;
1969
1970 const XsdComplexType::Ptr complexType(type);
1971
1972 if ((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) || (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) {
1973 DuplicatedElementMap elementMap;
1974 DuplicatedWildcardMap wildcardMap;
1975
1976 checkElementDuplicates(complexType->contentType()->particle(), elementMap, wildcardMap);
1977 }
1978 }
1979}
1980
1981void XsdSchemaChecker::checkElementDuplicates(const XsdParticle::Ptr &particle, DuplicatedElementMap &elementMap, DuplicatedWildcardMap &wildcardMap)
1982{
1983 if (particle->term()->isElement()) {
1984 const XsdElement::Ptr element(particle->term());
1985
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));
1991 return;
1992 }
1993 } else {
1994 elementMap.insert(element->name(m_namePool), element->type());
1995 }
1996
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));
2006 return;
2007 }
2008 } else {
2009 elementMap.insert(substElement->name(m_namePool), substElement->type());
2010 }
2011 }
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());
2019
2020 bool error = false;
2021 if (!wildcardMap.contains(wildcard->namespaceConstraint()->variety())) {
2022 if (!wildcardMap.isEmpty())
2023 error = true;
2024 } else {
2025 const XsdWildcard::Ptr otherWildcard = wildcardMap.value(wildcard->namespaceConstraint()->variety());
2026 if ((wildcard->processContents() != otherWildcard->processContents()) || (wildcard->namespaceConstraint()->namespaces() != otherWildcard->namespaceConstraint()->namespaces()))
2027 error = true;
2028 }
2029
2030 if (error) {
2031 m_context->error(QtXmlPatterns::tr("Particle contains non-deterministic wildcards."), XsdSchemaContext::XSDError, sourceLocation(wildcard));
2032 return;
2033 } else {
2034 wildcardMap.insert(wildcard->namespaceConstraint()->variety(), wildcard);
2035 }
2036 }
2037}
2038
2039QSourceLocation XsdSchemaChecker::sourceLocation(const NamedSchemaComponent::Ptr &component) const
2040{
2041 if (m_componentLocationHash.contains(component)) {
2042 return m_componentLocationHash.value(component);
2043 } else {
2044 QSourceLocation location;
2045 location.setLine(1);
2046 location.setColumn(1);
2047 location.setUri(QString::fromLatin1("dummyUri"));
2048
2049 return location;
2050 }
2051}
2052
2053QSourceLocation XsdSchemaChecker::sourceLocationForType(const SchemaType::Ptr &type) const
2054{
2055 if (type->isSimpleType())
2056 return sourceLocation(XsdSimpleType::Ptr(type));
2057 else
2058 return sourceLocation(XsdComplexType::Ptr(type));
2059}
2060
2061QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.