1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qxsdschemachecker_p.h"
41
42#include "qderivedinteger_p.h"
43#include "qderivedstring_p.h"
44#include "qpatternplatform_p.h"
45#include "qqnamevalue_p.h"
46#include "qsourcelocationreflection_p.h"
47#include "qvaluefactory_p.h"
48#include "qxsdattributereference_p.h"
49#include "qxsdparticlechecker_p.h"
50#include "qxsdreference_p.h"
51#include "qxsdschemacontext_p.h"
52#include "qxsdschemahelper_p.h"
53#include "qxsdschemaparsercontext_p.h"
54#include "qxsdschematypesfactory_p.h"
55#include "qxsdtypechecker_p.h"
56
57#include "qxsdschemachecker_helper.cpp"
58
59QT_BEGIN_NAMESPACE
60
61using namespace QPatternist;
62
63XsdSchemaChecker::XsdSchemaChecker(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext)
64 : m_context(context)
65 , m_namePool(parserContext->namePool())
66 , m_schema(parserContext->schema())
67{
68 setupAllowedAtomicFacets();
69}
70
71XsdSchemaChecker::~XsdSchemaChecker()
72{
73}
74
75/*
76 * This method is called after the resolver has set the base type for every
77 * type and information about deriavtion and 'is simple type vs. is complex type'
78 * are available.
79 */
80void XsdSchemaChecker::basicCheck()
81{
82 // first check that there is no circular inheritance, only the
83 // wxsSuperType is used here
84 checkBasicCircularInheritances();
85
86 // check the basic constraints like simple type can not inherit from complex type etc.
87 checkBasicSimpleTypeConstraints();
88 checkBasicComplexTypeConstraints();
89}
90
91void XsdSchemaChecker::check()
92{
93 checkCircularInheritances();
94 checkInheritanceRestrictions();
95 checkSimpleDerivationRestrictions();
96 checkSimpleTypeConstraints();
97 checkComplexTypeConstraints();
98 checkDuplicatedAttributeUses();
99
100 checkElementConstraints();
101 checkAttributeConstraints();
102 checkAttributeUseConstraints();
103// checkElementDuplicates();
104}
105
106void XsdSchemaChecker::addComponentLocationHash(const ComponentLocationHash &hash)
107{
108 m_componentLocationHash.insert(hash);
109}
110
111/**
112 * Checks whether the @p otherType is the same as @p myType or if one of its
113 * ancestors is the same as @p myType.
114 */
115static bool matchesType(const SchemaType::Ptr &myType, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> visitedTypes)
116{
117 bool retval = false;
118
119 if (otherType) {
120 if (visitedTypes.contains(value: otherType)) {
121 return true;
122 } else {
123 visitedTypes.insert(value: otherType);
124 }
125 // simple types can have different varieties, so we have to check each of them
126 if (otherType->isSimpleType()) {
127 const XsdSimpleType::Ptr simpleType = otherType;
128 if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) {
129 // for atomic type we use the same test as in SchemaType::wxsTypeMatches
130 retval = (myType == simpleType ? true : matchesType(myType, otherType: simpleType->wxsSuperType(), visitedTypes));
131 } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
132 // for list type we test against the itemType property
133 retval = (myType == simpleType->itemType() ? true : matchesType(myType, otherType: simpleType->itemType()->wxsSuperType(), visitedTypes));
134 } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
135 // for union type we test against each member type
136 const XsdSimpleType::List members = simpleType->memberTypes();
137 for (int i = 0; i < members.count(); ++i) {
138 if (myType == members.at(i) ? true : matchesType(myType, otherType: members.at(i)->wxsSuperType(), visitedTypes)) {
139 retval = true;
140 break;
141 }
142 }
143 } else {
144 // reached xsAnySimple type whichs category is None
145 retval = false;
146 }
147 } else {
148 // if no simple type we handle it like in SchemaType::wxsTypeMatches
149 retval = (myType == otherType ? true : matchesType(myType, otherType: otherType->wxsSuperType(), visitedTypes));
150 }
151 } else // if otherType is null it doesn't match
152 retval = false;
153
154 return retval;
155}
156
157/**
158 * Checks whether there is a circular inheritance for the union inheritance.
159 */
160static bool hasCircularUnionInheritance(const XsdSimpleType::Ptr &type, const SchemaType::Ptr &otherType, NamePool::Ptr &namePool)
161{
162 if (type == otherType) {
163 return true;
164 }
165
166 if (!otherType->isSimpleType() || !otherType->isDefinedBySchema()) {
167 return false;
168 }
169
170 const XsdSimpleType::Ptr simpleOtherType = otherType;
171
172 if (simpleOtherType->category() == XsdSimpleType::SimpleTypeUnion) {
173 const XsdSimpleType::List memberTypes = simpleOtherType->memberTypes();
174 for (int i = 0; i < memberTypes.count(); ++i) {
175 if (otherType->wxsSuperType() == type) {
176 return true;
177 }
178 if (hasCircularUnionInheritance(type, otherType: memberTypes.at(i), namePool)) {
179 return true;
180 }
181 }
182 }
183
184 return false;
185}
186
187static inline bool wxsTypeMatches(const SchemaType::Ptr &type, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> &visitedTypes, SchemaType::Ptr &conflictingType)
188{
189 if (!otherType)
190 return false;
191
192 if (visitedTypes.contains(value: otherType)) { // inheritance loop detected
193 conflictingType = otherType;
194 return true;
195 } else {
196 visitedTypes.insert(value: otherType);
197 }
198
199 if (type == otherType)
200 return true;
201
202 return wxsTypeMatches(type, otherType: otherType->wxsSuperType(), visitedTypes, conflictingType);
203}
204
205void XsdSchemaChecker::checkBasicCircularInheritances()
206{
207 // check all global types...
208 SchemaType::List types = m_schema->types();
209
210 // .. and anonymous types
211 types << m_schema->anonymousTypes();
212
213 for (int i = 0; i < types.count(); ++i) {
214 const SchemaType::Ptr type = types.at(i);
215 const QSourceLocation location = sourceLocationForType(type);
216
217 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3)
218
219 // check normal base type inheritance
220 QSet<SchemaType::Ptr> visitedTypes;
221 SchemaType::Ptr conflictingType;
222
223 if (wxsTypeMatches(type, otherType: type->wxsSuperType(), visitedTypes, conflictingType)) {
224 if (conflictingType)
225 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 has inheritance loop in its base type %2.")
226 .arg(a: formatType(np: m_namePool, type))
227 .arg(a: formatType(np: m_namePool, type: conflictingType)),
228 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
229 else
230 m_context->error(message: QtXmlPatterns::tr(sourceText: "Circular inheritance of base type %1.").arg(a: formatType(np: m_namePool, type)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
231
232 return;
233 }
234 }
235}
236
237void XsdSchemaChecker::checkCircularInheritances()
238{
239 // check all global types...
240 SchemaType::List types = m_schema->types();
241
242 // .. and anonymous types
243 types << m_schema->anonymousTypes();
244
245 for (int i = 0; i < types.count(); ++i) {
246 const SchemaType::Ptr type = types.at(i);
247 const QSourceLocation location = sourceLocationForType(type);
248
249 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3)
250
251 // check normal base type inheritance
252 QSet<SchemaType::Ptr> visitedTypes;
253 if (matchesType(myType: type, otherType: type->wxsSuperType(), visitedTypes)) {
254 m_context->error(message: QtXmlPatterns::tr(sourceText: "Circular inheritance of base type %1.").arg(a: formatType(np: m_namePool, type)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
255 return;
256 }
257
258 // check union member inheritance
259 if (type->isSimpleType() && type->isDefinedBySchema()) {
260 const XsdSimpleType::Ptr simpleType = type;
261 if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
262 const XsdSimpleType::List memberTypes = simpleType->memberTypes();
263 for (int j = 0; j < memberTypes.count(); ++j) {
264 if (hasCircularUnionInheritance(type: simpleType, otherType: memberTypes.at(i: j), namePool&: m_namePool)) {
265 m_context->error(message: QtXmlPatterns::tr(sourceText: "Circular inheritance of union %1.").arg(a: formatType(np: m_namePool, type)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
266 return;
267 }
268 }
269 }
270 }
271 }
272}
273
274void XsdSchemaChecker::checkInheritanceRestrictions()
275{
276 // check all global types...
277 SchemaType::List types = m_schema->types();
278
279 // .. and anonymous types
280 types << m_schema->anonymousTypes();
281
282 for (int i = 0; i < types.count(); ++i) {
283 const SchemaType::Ptr type = types.at(i);
284 const QSourceLocation location = sourceLocationForType(type);
285
286 // check inheritance restrictions given by final property of base class
287 const SchemaType::Ptr baseType = type->wxsSuperType();
288 if (baseType->isDefinedBySchema()) {
289 if ((type->derivationMethod() == SchemaType::DerivationRestriction) && (baseType->derivationConstraints() & SchemaType::RestrictionConstraint)) {
290 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 is not allowed to derive from %2 by restriction as the latter defines it as final.")
291 .arg(a: formatType(np: m_namePool, type))
292 .arg(a: formatType(np: m_namePool, type: baseType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
293 return;
294 } else if ((type->derivationMethod() == SchemaType::DerivationExtension) && (baseType->derivationConstraints() & SchemaType::ExtensionConstraint)) {
295 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 is not allowed to derive from %2 by extension as the latter defines it as final.")
296 .arg(a: formatType(np: m_namePool, type))
297 .arg(a: formatType(np: m_namePool, type: baseType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
298 return;
299 }
300 }
301 }
302}
303
304void XsdSchemaChecker::checkBasicSimpleTypeConstraints()
305{
306 // check all global types...
307 SchemaType::List types = m_schema->types();
308
309 // .. and anonymous types
310 types << m_schema->anonymousTypes();
311
312 for (int i = 0; i < types.count(); ++i) {
313 const SchemaType::Ptr type = types.at(i);
314
315 if (!type->isSimpleType())
316 continue;
317
318 const XsdSimpleType::Ptr simpleType = type;
319
320 const QSourceLocation location = sourceLocation(component: simpleType);
321
322 // check inheritance restrictions of simple type defined by schema constraints
323 const SchemaType::Ptr baseType = simpleType->wxsSuperType();
324
325 if (baseType->isComplexType() && (simpleType->name(m_namePool) != BuiltinTypes::xsAnySimpleType->name(np: m_namePool))) {
326 m_context->error(message: QtXmlPatterns::tr(sourceText: "Base type of simple type %1 cannot be complex type %2.")
327 .arg(a: formatType(np: m_namePool, type: simpleType))
328 .arg(a: formatType(np: m_namePool, type: baseType)),
329 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
330 return;
331 }
332
333 if (baseType == BuiltinTypes::xsAnyType) {
334 if (type->name(np: m_namePool) != BuiltinTypes::xsAnySimpleType->name(np: m_namePool)) {
335 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type %1 cannot have direct base type %2.")
336 .arg(a: formatType(np: m_namePool, type: simpleType))
337 .arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsAnyType)),
338 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
339 return;
340 }
341 }
342 }
343}
344
345void XsdSchemaChecker::checkSimpleTypeConstraints()
346{
347 // check all global types...
348 SchemaType::List types = m_schema->types();
349
350 // .. and anonymous types
351 types << m_schema->anonymousTypes();
352
353 for (int i = 0; i < types.count(); ++i) {
354 const SchemaType::Ptr type = types.at(i);
355
356 if (!type->isSimpleType())
357 continue;
358
359 const XsdSimpleType::Ptr simpleType = type;
360
361 const QSourceLocation location = sourceLocation(component: simpleType);
362
363 if (simpleType->category() == XsdSimpleType::None) {
364 // additional checks
365 // check that no user defined type has xs:AnySimpleType as base type (except xs:AnyAtomicType)
366 if (simpleType->wxsSuperType()->name(np: m_namePool) == BuiltinTypes::xsAnySimpleType->name(np: m_namePool)) {
367 if (simpleType->name(m_namePool) != BuiltinTypes::xsAnyAtomicType->name(np: m_namePool)) {
368 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type %1 is not allowed to have base type %2.")
369 .arg(a: formatType(np: m_namePool, type: simpleType))
370 .arg(a: formatType(np: m_namePool, type: simpleType->wxsSuperType())),
371 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
372 return;
373 }
374 }
375 // check that no user defined type has xs:AnyAtomicType as base type
376 if (simpleType->wxsSuperType()->name(np: m_namePool) == BuiltinTypes::xsAnyAtomicType->name(np: m_namePool)) {
377 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type %1 is not allowed to have base type %2.")
378 .arg(a: formatType(np: m_namePool, type: simpleType))
379 .arg(a: formatType(np: m_namePool, type: simpleType->wxsSuperType())),
380 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
381 return;
382 }
383 }
384
385 // @see http://www.w3.org/TR/xmlschema11-1/#d0e37310
386 if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) {
387 // 1.1
388 if ((simpleType->wxsSuperType()->category() != XsdSimpleType::SimpleTypeAtomic) && (simpleType->name(m_namePool) != BuiltinTypes::xsAnyAtomicType->name(np: m_namePool))) {
389 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type %1 can only have simple atomic type as base type.")
390 .arg(a: formatType(np: m_namePool, type: simpleType)),
391 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
392 }
393 // 1.2
394 if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) {
395 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type %1 cannot derive from %2 as the latter defines restriction as final.")
396 .arg(a: formatType(np: m_namePool, type: simpleType->wxsSuperType()))
397 .arg(a: formatType(np: m_namePool, type: simpleType)),
398 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
399 }
400
401 // 1.3
402 // checked by checkConstrainingFacets already
403 } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
404 const AnySimpleType::Ptr itemType = simpleType->itemType();
405
406 // 2.1 or @see http://www.w3.org/TR/xmlschema-2/#cos-list-of-atomic
407 if (itemType->category() != SchemaType::SimpleTypeAtomic && itemType->category() != SchemaType::SimpleTypeUnion) {
408 m_context->error(message: QtXmlPatterns::tr(sourceText: "Variety of item type of %1 must be either atomic or union.").arg(a: formatType(np: m_namePool, type: simpleType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
409 return;
410 }
411
412 // 2.1 second part
413 if (itemType->category() == SchemaType::SimpleTypeUnion && itemType->isDefinedBySchema()) {
414 const XsdSimpleType::Ptr simpleItemType = itemType;
415 const AnySimpleType::List memberTypes = simpleItemType->memberTypes();
416 for (int j = 0; j < memberTypes.count(); ++j) {
417 if (memberTypes.at(i: j)->category() != SchemaType::SimpleTypeAtomic && memberTypes.at(i: j)->category() != SchemaType::SimpleTypeUnion) {
418 m_context->error(message: QtXmlPatterns::tr(sourceText: "Variety of member types of %1 must be atomic or union.").arg(a: formatType(np: m_namePool, type: simpleItemType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
419 return;
420 }
421 }
422 }
423
424 // 2.2.1
425 if (simpleType->wxsSuperType()->name(np: m_namePool) == BuiltinTypes::xsAnySimpleType->name(np: m_namePool)) {
426 if (itemType->isSimpleType() && itemType->isDefinedBySchema()) {
427 const XsdSimpleType::Ptr simpleItemType = itemType;
428
429 // 2.2.1.1
430 if (simpleItemType->derivationConstraints() & XsdSimpleType::ListConstraint) {
431 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 is not allowed to derive from %2 by list as the latter defines it as final.")
432 .arg(a: formatType(np: m_namePool, type: simpleType))
433 .arg(a: formatType(np: m_namePool, type: simpleItemType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
434 return;
435 }
436
437 // 2.2.1.2
438 const XsdFacet::Hash facets = simpleType->facets();
439
440 bool invalidFacetFound = false;
441 for (auto it = facets.cbegin(), end = facets.cend(); it != end; ++it) {
442 if (it.key() != XsdFacet::WhiteSpace) {
443 invalidFacetFound = true;
444 break;
445 }
446 }
447
448 if (invalidFacetFound) {
449 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type %1 is only allowed to have %2 facet.")
450 .arg(a: formatType(np: m_namePool, type: simpleType))
451 .arg(a: formatKeyword(keyword: "whiteSpace")),
452 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
453 return;
454 }
455 }
456 } else { // 2.2.2
457 // 2.2.2.1
458 if (simpleType->wxsSuperType()->category() != XsdSimpleType::SimpleTypeList) {
459 m_context->error(message: QtXmlPatterns::tr(sourceText: "Base type of simple type %1 must have variety of type list.").arg(a: formatType(np: m_namePool, type: simpleType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
460 return;
461 }
462
463 // 2.2.2.2
464 if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) {
465 m_context->error(message: QtXmlPatterns::tr(sourceText: "Base type of simple type %1 has defined derivation by restriction as final.").arg(a: formatType(np: m_namePool, type: simpleType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
466 return;
467 }
468
469 // 2.2.2.3
470 if (!XsdSchemaHelper::isSimpleDerivationOk(derivedType: itemType, baseType: XsdSimpleType::Ptr(simpleType->wxsSuperType())->itemType(), constraints: SchemaType::DerivationConstraints())) {
471 m_context->error(message: QtXmlPatterns::tr(sourceText: "Item type of base type does not match item type of %1.").arg(a: formatType(np: m_namePool, type: simpleType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
472 return;
473 }
474
475 // 2.2.2.4
476 const XsdFacet::Hash facets = simpleType->facets();
477
478 bool invalidFacetFound = false;
479 XsdFacet::Type invalidFacetType = XsdFacet::None;
480 for (auto it = facets.cbegin(), end = facets.cend(); it != end; ++it) {
481 const XsdFacet::Type facetType = it.key();
482 if (facetType != XsdFacet::Length &&
483 facetType != XsdFacet::MinimumLength &&
484 facetType != XsdFacet::MaximumLength &&
485 facetType != XsdFacet::WhiteSpace &&
486 facetType != XsdFacet::Pattern &&
487 facetType != XsdFacet::Enumeration) {
488 invalidFacetType = facetType;
489 invalidFacetFound = true;
490 break;
491 }
492 }
493
494 if (invalidFacetFound) {
495 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type %1 contains not allowed facet type %2.")
496 .arg(a: formatType(np: m_namePool, type: simpleType))
497 .arg(a: formatKeyword(keyword: XsdFacet::typeName(type: invalidFacetType))),
498 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
499 return;
500 }
501
502 // 2.2.2.5
503 // TODO: check value constraints
504 }
505
506
507 } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
508 const AnySimpleType::List memberTypes = simpleType->memberTypes();
509
510 if (simpleType->wxsSuperType()->name(np: m_namePool) == BuiltinTypes::xsAnySimpleType->name(np: m_namePool)) { // 3.1.1
511 // 3.3.1.1
512 for (int i = 0; i < memberTypes.count(); ++i) {
513 const AnySimpleType::Ptr memberType = memberTypes.at(i);
514
515 if (memberType->derivationConstraints() & XsdSimpleType::UnionConstraint) {
516 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 is not allowed to derive from %2 by union as the latter defines it as final.")
517 .arg(a: formatType(np: m_namePool, type: simpleType))
518 .arg(a: formatType(np: m_namePool, type: memberType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
519 return;
520 }
521 }
522
523 // 3.3.1.2
524 if (!simpleType->facets().isEmpty()) {
525 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 is not allowed to have any facets.")
526 .arg(a: formatType(np: m_namePool, type: simpleType)),
527 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
528 return;
529 }
530 } else {
531 // 3.1.2.1
532 if (simpleType->wxsSuperType()->category() != SchemaType::SimpleTypeUnion) {
533 m_context->error(message: QtXmlPatterns::tr(sourceText: "Base type %1 of simple type %2 must have variety of union.")
534 .arg(a: formatType(np: m_namePool, type: simpleType->wxsSuperType()))
535 .arg(a: formatType(np: m_namePool, type: simpleType)),
536 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
537 return;
538 }
539
540 // 3.1.2.2
541 if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::DerivationRestriction) {
542 m_context->error(message: QtXmlPatterns::tr(sourceText: "Base type %1 of simple type %2 is not allowed to have restriction in %3 attribute.")
543 .arg(a: formatType(np: m_namePool, type: simpleType->wxsSuperType()))
544 .arg(a: formatType(np: m_namePool, type: simpleType))
545 .arg(a: formatAttribute(attribute: "final")),
546 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
547 return;
548 }
549
550 //3.1.2.3
551 if (simpleType->wxsSuperType()->isDefinedBySchema()) {
552 const XsdSimpleType::Ptr simpleBaseType(simpleType->wxsSuperType());
553
554 AnySimpleType::List baseMemberTypes = simpleBaseType->memberTypes();
555 for (int i = 0; i < memberTypes.count(); ++i) {
556 const AnySimpleType::Ptr memberType = memberTypes.at(i);
557 const AnySimpleType::Ptr baseMemberType = baseMemberTypes.at(i);
558
559 if (!XsdSchemaHelper::isSimpleDerivationOk(derivedType: memberType, baseType: baseMemberType, constraints: SchemaType::DerivationConstraints())) {
560 m_context->error(message: QtXmlPatterns::tr(sourceText: "Member type %1 cannot be derived from member type %2 of %3's base type %4.")
561 .arg(a: formatType(np: m_namePool, type: memberType))
562 .arg(a: formatType(np: m_namePool, type: baseMemberType))
563 .arg(a: formatType(np: m_namePool, type: simpleType))
564 .arg(a: formatType(np: m_namePool, type: simpleBaseType)),
565 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
566 }
567 }
568 }
569
570 // 3.1.2.4
571 const XsdFacet::Hash facets = simpleType->facets();
572
573 bool invalidFacetFound = false;
574 XsdFacet::Type invalidFacetType = XsdFacet::None;
575 for (auto it = facets.cbegin(), end = facets.cend(); it != end; ++it) {
576 const XsdFacet::Type facetType = it.key();
577 if (facetType != XsdFacet::Pattern &&
578 facetType != XsdFacet::Enumeration) {
579 invalidFacetType = facetType;
580 invalidFacetFound = true;
581 break;
582 }
583 }
584
585 if (invalidFacetFound) {
586 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type %1 contains not allowed facet type %2.")
587 .arg(a: formatType(np: m_namePool, type: simpleType))
588 .arg(a: formatKeyword(keyword: XsdFacet::typeName(type: invalidFacetType))),
589 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
590 return;
591 }
592
593 // 3.1.2.5
594 // TODO: check value constraints
595 }
596 }
597 }
598}
599
600void XsdSchemaChecker::checkBasicComplexTypeConstraints()
601{
602 // check all global types...
603 SchemaType::List types = m_schema->types();
604
605 // .. and anonymous types
606 types << m_schema->anonymousTypes();
607
608 for (int i = 0; i < types.count(); ++i) {
609 const SchemaType::Ptr type = types.at(i);
610
611 if (!type->isComplexType() || !type->isDefinedBySchema())
612 continue;
613
614 const XsdComplexType::Ptr complexType = type;
615
616 const QSourceLocation location = sourceLocation(component: complexType);
617
618 // check inheritance restrictions of complex type defined by schema constraints
619 const SchemaType::Ptr baseType = complexType->wxsSuperType();
620
621 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 2)
622 if (baseType->isSimpleType() && (complexType->derivationMethod() != XsdComplexType::DerivationExtension)) {
623 m_context->error(message: QtXmlPatterns::tr(sourceText: "Derivation method of %1 must be extension because the base type %2 is a simple type.")
624 .arg(a: formatType(np: m_namePool, type: complexType))
625 .arg(a: formatType(np: m_namePool, type: baseType)),
626 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
627 return;
628 }
629 }
630}
631
632void XsdSchemaChecker::checkComplexTypeConstraints()
633{
634 // check all global types...
635 SchemaType::List types = m_schema->types();
636
637 // .. and anonymous types
638 types << m_schema->anonymousTypes();
639
640 for (int i = 0; i < types.count(); ++i) {
641 const SchemaType::Ptr type = types.at(i);
642
643 if (!type->isComplexType() || !type->isDefinedBySchema())
644 continue;
645
646 const XsdComplexType::Ptr complexType = type;
647
648 const QSourceLocation location = sourceLocation(component: complexType);
649
650 if (complexType->contentType()->particle()) {
651 XsdElement::Ptr duplicatedElement;
652 if (XsdParticleChecker::hasDuplicatedElements(particle: complexType->contentType()->particle(), namePool: m_namePool, conflictingElement&: duplicatedElement)) {
653 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 has duplicated element %2 in its content model.")
654 .arg(a: formatType(np: m_namePool, type: complexType))
655 .arg(a: formatKeyword(keyword: duplicatedElement->displayName(namePool: m_namePool))),
656 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
657 return;
658 }
659
660 if (!XsdParticleChecker::isUPAConform(particle: complexType->contentType()->particle(), namePool: m_namePool)) {
661 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 has non-deterministic content.")
662 .arg(a: formatType(np: m_namePool, type: complexType)),
663 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
664 return;
665 }
666 }
667
668 // check inheritance restrictions of complex type defined by schema constraints
669 const SchemaType::Ptr baseType = complexType->wxsSuperType();
670
671 // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-extends
672 if (complexType->derivationMethod() == XsdComplexType::DerivationExtension) {
673 if (baseType->isComplexType() && baseType->isDefinedBySchema()) {
674 const XsdComplexType::Ptr complexBaseType = baseType;
675
676 // we can skip 1.1 here, as it is tested in checkInheritanceRestrictions() already
677
678 // 1.2 and 1.3
679 QString errorMsg;
680 if (!XsdSchemaHelper::isValidAttributeUsesExtension(derivedAttributeUses: complexType->attributeUses(), attributeUses: complexBaseType->attributeUses(),
681 derivedWildcard: complexType->attributeWildcard(), wildcard: complexBaseType->attributeWildcard(), context: m_context, errorMsg)) {
682 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attributes of complex type %1 are not a valid extension of the attributes of base type %2: %3.")
683 .arg(a: formatType(np: m_namePool, type: complexType))
684 .arg(a: formatType(np: m_namePool, type: baseType))
685 .arg(a: errorMsg),
686 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
687 return;
688 }
689
690 // 1.4
691 bool validContentType = false;
692 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
693 if (complexType->contentType()->simpleType() == complexBaseType->contentType()->simpleType()) {
694 validContentType = true; // 1.4.1
695 }
696 } else if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
697 validContentType = true; // 1.4.2
698 } else { // 1.4.3
699 if (complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed) { // 1.4.3.1
700 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
701 validContentType = true; // 1.4.3.2.1
702 } else { // 1.4.3.2.2
703 if (complexType->contentType()->particle()) { // our own check
704 if ((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) ||
705 (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) { // 1.4.3.2.2.1
706 if (isValidParticleExtension(extension: complexType->contentType()->particle(), base: complexBaseType->contentType()->particle())) {
707 validContentType = true; // 1.4.3.2.2.2
708 }
709 }
710 }
711 // 1.4.3.2.2.3 and 1.4.3.2.2.4 handle 'open content' that we do not support yet
712 }
713 }
714 }
715
716 // 1.5 WTF?!?
717
718 if (!validContentType) {
719 m_context->error(message: QtXmlPatterns::tr(sourceText: "Content model of complex type %1 is not a valid extension of content model of %2.")
720 .arg(a: formatType(np: m_namePool, type: complexType))
721 .arg(a: formatType(np: m_namePool, type: complexBaseType)),
722 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
723 return;
724 }
725
726 } else if (baseType->isSimpleType()) {
727 // 2.1
728 if (complexType->contentType()->variety() != XsdComplexType::ContentType::Simple) {
729 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 must have simple content.")
730 .arg(a: formatType(np: m_namePool, type: complexType)),
731 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
732 return;
733 }
734
735 if (complexType->contentType()->simpleType() != baseType) {
736 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 must have the same simple type as its base class %2.")
737 .arg(a: formatType(np: m_namePool, type: complexType))
738 .arg(a: formatType(np: m_namePool, type: baseType)),
739 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
740 return;
741 }
742
743 // 2.2 tested in checkInheritanceRestrictions() already
744 }
745 } else if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) {
746 // @see http://www.w3.org/TR/xmlschema11-1/#d0e21402
747 const SchemaType::Ptr baseType(complexType->wxsSuperType());
748
749 bool derivationOk = false;
750 QString errorMsg;
751
752 // we can partly skip 1 here, as it is tested in checkInheritanceRestrictions() already
753 if (baseType->isComplexType()) {
754
755 // 2.1
756 if (baseType->name(np: m_namePool) == BuiltinTypes::xsAnyType->name(np: m_namePool)) {
757 derivationOk = true;
758 }
759
760 if (baseType->isDefinedBySchema()) {
761 const XsdComplexType::Ptr complexBaseType(baseType);
762
763 // 2.2.1
764 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
765 // 2.2.2.1
766 if (XsdSchemaHelper::isSimpleDerivationOk(derivedType: complexType->contentType()->simpleType(), baseType: complexBaseType->contentType()->simpleType(), constraints: SchemaType::DerivationConstraints()))
767 derivationOk = true;
768
769 // 2.2.2.2
770 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) {
771 if (XsdSchemaHelper::isParticleEmptiable(particle: complexBaseType->contentType()->particle()))
772 derivationOk = true;
773 }
774 }
775
776 // 2.3.1
777 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
778 // 2.3.2.1
779 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Empty)
780 derivationOk = true;
781
782 // 2.3.2.2
783 if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) {
784 if (XsdSchemaHelper::isParticleEmptiable(particle: complexBaseType->contentType()->particle()))
785 derivationOk = true;
786 }
787 }
788
789 // 2.4.1.1
790 if (((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) &&
791 (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) ||
792 // 2.4.1.2
793 (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed && complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) {
794
795 // 2.4.2
796 if (XsdParticleChecker::subsumes(particle: complexBaseType->contentType()->particle(), derivedParticle: complexType->contentType()->particle(), context: m_context, errorMsg))
797 derivationOk = true;
798 }
799 }
800 }
801
802 if (!derivationOk) {
803 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 cannot be derived from base type %2%3.")
804 .arg(a: formatType(np: m_namePool, type: complexType))
805 .arg(a: formatType(np: m_namePool, type: baseType))
806 .arg(a: errorMsg.isEmpty() ? QString() : QLatin1String(": ") + errorMsg),
807 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
808 return;
809 }
810
811 if (baseType->isDefinedBySchema()) {
812 const XsdComplexType::Ptr complexBaseType(baseType);
813
814 QString errorMsg;
815 if (!XsdSchemaHelper::isValidAttributeUsesRestriction(derivedAttributeUses: complexType->attributeUses(), attributeUses: complexBaseType->attributeUses(),
816 derivedWildcard: complexType->attributeWildcard(), wildcard: complexBaseType->attributeWildcard(), context: m_context, errorMsg)) {
817 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attributes of complex type %1 are not a valid restriction from the attributes of base type %2: %3.")
818 .arg(a: formatType(np: m_namePool, type: complexType))
819 .arg(a: formatType(np: m_namePool, type: baseType))
820 .arg(a: errorMsg),
821 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
822 return;
823 }
824 }
825 }
826
827 // check that complex type with simple content is not allowed to inherit from
828 // built in complex type xs:AnyType
829 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
830 if (baseType->name(np: m_namePool) == BuiltinTypes::xsAnyType->name(np: m_namePool)) {
831 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 with simple content cannot be derived from complex base type %2.")
832 .arg(a: formatType(np: m_namePool, type: complexType))
833 .arg(a: formatType(np: m_namePool, type: baseType)),
834 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
835 return;
836 }
837 }
838 }
839}
840
841void XsdSchemaChecker::checkSimpleDerivationRestrictions()
842{
843 // check all global types...
844 SchemaType::List types = m_schema->types();
845
846 // .. and anonymous types
847 types << m_schema->anonymousTypes();
848
849 for (int i = 0; i < types.count(); ++i) {
850 const SchemaType::Ptr type = types.at(i);
851
852 if (type->isComplexType())
853 continue;
854
855 if (type->category() != SchemaType::SimpleTypeList && type->category() != SchemaType::SimpleTypeUnion)
856 continue;
857
858 const XsdSimpleType::Ptr simpleType = type;
859 const QSourceLocation location = sourceLocation(component: simpleType);
860
861 // check all simple types derived by list
862 if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
863 const AnySimpleType::Ptr itemType = simpleType->itemType();
864
865 if (itemType->isComplexType()) {
866 m_context->error(message: QtXmlPatterns::tr(sourceText: "Item type of simple type %1 cannot be a complex type.")
867 .arg(a: formatType(np: m_namePool, type: simpleType)),
868 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
869 return;
870 }
871
872
873 if (itemType->isSimpleType() && itemType->isDefinedBySchema()) {
874 const XsdSimpleType::Ptr simpleItemType = itemType;
875 if (simpleItemType->derivationConstraints() & XsdSimpleType::ListConstraint) {
876 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 is not allowed to derive from %2 by list as the latter defines it as final.")
877 .arg(a: formatType(np: m_namePool, type: simpleType))
878 .arg(a: formatType(np: m_namePool, type: simpleItemType)),
879 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
880 return;
881 }
882 }
883
884 // @see http://www.w3.org/TR/xmlschema-2/#cos-list-of-atomic
885 if (itemType->category() != SchemaType::SimpleTypeAtomic && itemType->category() != SchemaType::SimpleTypeUnion) {
886 m_context->error(message: QtXmlPatterns::tr(sourceText: "Variety of item type of %1 must be either atomic or union.").arg(a: formatType(np: m_namePool, type: simpleType)), errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
887 return;
888 }
889
890 if (itemType->category() == SchemaType::SimpleTypeUnion && itemType->isDefinedBySchema()) {
891 const XsdSimpleType::Ptr simpleItemType = itemType;
892 const AnySimpleType::List memberTypes = simpleItemType->memberTypes();
893 for (int j = 0; j < memberTypes.count(); ++j) {
894 if (memberTypes.at(i: j)->category() != SchemaType::SimpleTypeAtomic && memberTypes.at(i: j)->category() != SchemaType::SimpleTypeUnion) {
895 m_context->error(message: QtXmlPatterns::tr(sourceText: "Variety of member types of %1 must be atomic or union.").arg(a: formatType(np: m_namePool, type: simpleItemType)),
896 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
897 return;
898 }
899 }
900 }
901 }
902
903 // check all simple types derived by union
904 if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
905 const AnySimpleType::List memberTypes = simpleType->memberTypes();
906
907 for (int i = 0; i < memberTypes.count(); ++i) {
908 const AnySimpleType::Ptr memberType = memberTypes.at(i);
909
910 if (memberType->isComplexType()) {
911 m_context->error(message: QtXmlPatterns::tr(sourceText: "Member type of simple type %1 cannot be a complex type.")
912 .arg(a: formatType(np: m_namePool, type: simpleType)),
913 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
914 return;
915 }
916
917 // @see http://www.w3.org/TR/xmlschema-2/#cos-no-circular-unions
918 if (simpleType->name(m_namePool) == memberType->name(np: m_namePool)) {
919 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 is not allowed to have a member type with the same name as itself.")
920 .arg(a: formatType(np: m_namePool, type: simpleType)),
921 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
922 return;
923 }
924
925 if (memberType->isSimpleType() && memberType->isDefinedBySchema()) {
926 const XsdSimpleType::Ptr simpleMemberType = memberType;
927 if (simpleMemberType->derivationConstraints() & XsdSimpleType::UnionConstraint) {
928 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 is not allowed to derive from %2 by union as the latter defines it as final.")
929 .arg(a: formatType(np: m_namePool, type: simpleType))
930 .arg(a: formatType(np: m_namePool, type: simpleMemberType)),
931 errorCode: XsdSchemaContext::XSDError, sourceLocation: location);
932 return;
933 }
934 }
935 }
936 }
937 }
938}
939
940void XsdSchemaChecker::checkConstrainingFacets()
941{
942 // first the global simple types
943 const SchemaType::List types = m_schema->types();
944 for (int i = 0; i < types.count(); ++i) {
945 if (!(types.at(i)->isSimpleType()) || !(types.at(i)->isDefinedBySchema()))
946 continue;
947
948 const XsdSimpleType::Ptr simpleType = types.at(i);
949 checkConstrainingFacets(facets: simpleType->facets(), simpleType);
950 }
951
952 // and afterwards all anonymous simple types
953 const SchemaType::List anonymousTypes = m_schema->anonymousTypes();
954 for (int i = 0; i < anonymousTypes.count(); ++i) {
955 if (!(anonymousTypes.at(i)->isSimpleType()) || !(anonymousTypes.at(i)->isDefinedBySchema()))
956 continue;
957
958 const XsdSimpleType::Ptr simpleType = anonymousTypes.at(i);
959 checkConstrainingFacets(facets: simpleType->facets(), simpleType);
960 }
961}
962
963void XsdSchemaChecker::checkConstrainingFacets(const XsdFacet::Hash &facets, const XsdSimpleType::Ptr &simpleType)
964{
965 if (facets.isEmpty())
966 return;
967
968 SchemaType::Ptr comparableBaseType;
969 if (!simpleType->wxsSuperType()->isDefinedBySchema())
970 comparableBaseType = simpleType->wxsSuperType();
971 else
972 comparableBaseType = simpleType->primitiveType();
973
974 const XsdSchemaSourceLocationReflection reflection(sourceLocation(component: simpleType));
975
976 // start checks
977 if (facets.contains(akey: XsdFacet::Length)) {
978 const XsdFacet::Ptr lengthFacet = facets.value(akey: XsdFacet::Length);
979 const DerivedInteger<TypeNonNegativeInteger>::Ptr lengthValue = lengthFacet->value();
980
981 // @see http://www.w3.org/TR/xmlschema-2/#length-minLength-maxLength
982 if (facets.contains(akey: XsdFacet::MinimumLength)) {
983 const XsdFacet::Ptr minLengthFacet = facets.value(akey: XsdFacet::MinimumLength);
984 const DerivedInteger<TypeNonNegativeInteger>::Ptr minLengthValue = minLengthFacet->value();
985
986 bool foundSuperMinimumLength = false;
987 SchemaType::Ptr baseType = simpleType->wxsSuperType();
988 while (baseType) {
989 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: baseType);
990 if (baseFacets.contains(akey: XsdFacet::MinimumLength) && !baseFacets.contains(akey: XsdFacet::Length)) {
991 const DerivedInteger<TypeNonNegativeInteger>::Ptr superValue(baseFacets.value(akey: XsdFacet::MinimumLength)->value());
992 if (minLengthValue->toInteger() == superValue->toInteger()) {
993 foundSuperMinimumLength = true;
994 break;
995 }
996 }
997
998 baseType = baseType->wxsSuperType();
999 }
1000
1001 if ((minLengthValue->toInteger() > lengthValue->toInteger()) || !foundSuperMinimumLength) {
1002 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet collides with %2 facet.")
1003 .arg(a: formatKeyword(keyword: "length"))
1004 .arg(a: formatKeyword(keyword: "minLength")),
1005 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1006 return;
1007 }
1008 }
1009
1010 // @see http://www.w3.org/TR/xmlschema-2/#length-minLength-maxLength
1011 if (facets.contains(akey: XsdFacet::MaximumLength)) {
1012 const XsdFacet::Ptr maxLengthFacet = facets.value(akey: XsdFacet::MaximumLength);
1013 const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value();
1014
1015 bool foundSuperMaximumLength = false;
1016 SchemaType::Ptr baseType = simpleType->wxsSuperType();
1017 while (baseType) {
1018 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: baseType);
1019 if (baseFacets.contains(akey: XsdFacet::MaximumLength) && !baseFacets.contains(akey: XsdFacet::Length)) {
1020 const DerivedInteger<TypeNonNegativeInteger>::Ptr superValue(baseFacets.value(akey: XsdFacet::MaximumLength)->value());
1021 if (maxLengthValue->toInteger() == superValue->toInteger()) {
1022 foundSuperMaximumLength = true;
1023 break;
1024 }
1025 }
1026
1027 baseType = baseType->wxsSuperType();
1028 }
1029
1030 if ((maxLengthValue->toInteger() < lengthValue->toInteger()) || !foundSuperMaximumLength) {
1031 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet collides with %2 facet.")
1032 .arg(a: formatKeyword(keyword: "length"))
1033 .arg(a: formatKeyword(keyword: "maxLength")),
1034 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1035 return;
1036 }
1037 }
1038
1039 // @see http://www.w3.org/TR/xmlschema-2/#length-valid-restriction
1040 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1041 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1042 if (baseFacets.contains(akey: XsdFacet::Length)) {
1043 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacets.value(akey: XsdFacet::Length)->value();
1044 if (lengthValue->toInteger() != baseValue->toInteger()) {
1045 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must have the same value as %2 facet of base type.")
1046 .arg(a: formatKeyword(keyword: "length"))
1047 .arg(a: formatKeyword(keyword: "length")),
1048 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1049 return;
1050 }
1051 }
1052 }
1053 }
1054
1055 if (facets.contains(akey: XsdFacet::MinimumLength)) {
1056 const XsdFacet::Ptr minLengthFacet = facets.value(akey: XsdFacet::MinimumLength);
1057 const DerivedInteger<TypeNonNegativeInteger>::Ptr minLengthValue = minLengthFacet->value();
1058
1059 if (facets.contains(akey: XsdFacet::MaximumLength)) {
1060 const XsdFacet::Ptr maxLengthFacet = facets.value(akey: XsdFacet::MaximumLength);
1061 const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value();
1062
1063 // @see http://www.w3.org/TR/xmlschema-2/#minLength-less-than-equal-to-maxLength
1064 if (maxLengthValue->toInteger() < minLengthValue->toInteger()) {
1065 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet collides with %2 facet.")
1066 .arg(a: formatKeyword(keyword: "minLength"))
1067 .arg(a: formatKeyword(keyword: "maxLength")),
1068 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1069 return;
1070 }
1071
1072 // @see http://www.w3.org/TR/xmlschema-2/#minLength-valid-restriction
1073 //TODO: check parent facets
1074 }
1075
1076 // @see http://www.w3.org/TR/xmlschema-2/#minLength-valid-restriction
1077 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1078 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1079 if (baseFacets.contains(akey: XsdFacet::MinimumLength)) {
1080 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacets.value(akey: XsdFacet::MinimumLength)->value();
1081 if (minLengthValue->toInteger() < baseValue->toInteger()) {
1082 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be equal or greater than %2 facet of base type.")
1083 .arg(a: formatKeyword(keyword: "minLength"))
1084 .arg(a: formatKeyword(keyword: "minLength")),
1085 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1086 return;
1087 }
1088 }
1089 }
1090 }
1091 if (facets.contains(akey: XsdFacet::MaximumLength)) {
1092 const XsdFacet::Ptr maxLengthFacet = facets.value(akey: XsdFacet::MaximumLength);
1093 const DerivedInteger<TypeNonNegativeInteger>::Ptr maxLengthValue = maxLengthFacet->value();
1094
1095 // @see http://www.w3.org/TR/xmlschema-2/#maxLength-valid-restriction
1096 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1097 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1098 if (baseFacets.contains(akey: XsdFacet::MaximumLength)) {
1099 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue(baseFacets.value(akey: XsdFacet::MaximumLength)->value());
1100 if (maxLengthValue->toInteger() > baseValue->toInteger()) {
1101 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet of base type.")
1102 .arg(a: formatKeyword(keyword: "maxLength"))
1103 .arg(a: formatKeyword(keyword: "maxLength")),
1104 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1105 return;
1106 }
1107 }
1108 }
1109 }
1110 if (facets.contains(akey: XsdFacet::Pattern)) {
1111 // we keep the patterns in separated facets
1112 // @see http://www.w3.org/TR/xmlschema-2/#src-multiple-patterns
1113
1114 // @see http://www.w3.org/TR/xmlschema-2/#cvc-pattern-valid
1115 const XsdFacet::Ptr patternFacet = facets.value(akey: XsdFacet::Pattern);
1116 const AtomicValue::List multiValue = patternFacet->multiValue();
1117
1118 for (int i = 0; i < multiValue.count(); ++i) {
1119 const DerivedString<TypeString>::Ptr value = multiValue.at(i);
1120 QRegExp exp = PatternPlatform::parsePattern(pattern: value->stringValue(), context: m_context, location: &reflection);
1121 if (!exp.isValid()) {
1122 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet contains invalid regular expression").arg(a: formatKeyword(keyword: "pattern.")), errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1123 return;
1124 }
1125 }
1126 }
1127 if (facets.contains(akey: XsdFacet::Enumeration)) {
1128 // @see http://www.w3.org/TR/xmlschema-2/#src-multiple-enumerations
1129
1130 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
1131
1132 if (BuiltinTypes::xsNOTATION->wxsTypeMatches(other: simpleType)) {
1133 const AtomicValue::List notationNames = facet->multiValue();
1134 for (int k = 0; k < notationNames.count(); ++k) {
1135 const QNameValue::Ptr notationName = notationNames.at(i: k);
1136 if (!m_schema->notation(name: notationName->qName())) {
1137 m_context->error(message: QtXmlPatterns::tr(sourceText: "Unknown notation %1 used in %2 facet.")
1138 .arg(a: formatKeyword(np: m_namePool, name: notationName->qName()))
1139 .arg(a: formatKeyword(keyword: "enumeration")),
1140 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1141 }
1142 }
1143 } else if (BuiltinTypes::xsQName->wxsTypeMatches(other: simpleType)) {
1144 } else {
1145 const XsdTypeChecker checker(m_context, QVector<QXmlName>(), sourceLocation(component: simpleType));
1146
1147 const AnySimpleType::Ptr baseType = simpleType->wxsSuperType();
1148 const XsdFacet::Hash baseFacets = XsdTypeChecker::mergedFacetsForType(type: baseType, context: m_context);
1149
1150 const AtomicValue::List multiValue = facet->multiValue();
1151 for (int k = 0; k < multiValue.count(); ++k) {
1152 const QString stringValue = multiValue.at(i: k)->as<DerivedString<TypeString> >()->stringValue();
1153 const QString actualValue = XsdTypeChecker::normalizedValue(value: stringValue, facets: baseFacets);
1154
1155 QString errorMsg;
1156 if (!checker.isValidString(normalizedString: actualValue, type: baseType, errorMsg)) {
1157 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet contains invalid value %2: %3.")
1158 .arg(a: formatKeyword(keyword: "enumeration"))
1159 .arg(a: formatData(data: stringValue))
1160 .arg(a: errorMsg),
1161 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1162 return;
1163 }
1164 }
1165 }
1166 }
1167 if (facets.contains(akey: XsdFacet::WhiteSpace)) {
1168 const XsdFacet::Ptr whiteSpaceFacet = facets.value(akey: XsdFacet::WhiteSpace);
1169 const DerivedString<TypeString>::Ptr whiteSpaceValue = whiteSpaceFacet->value();
1170
1171 // @see http://www.w3.org/TR/xmlschema-2/#whiteSpace-valid-restriction
1172 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1173 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1174 if (baseFacets.contains(akey: XsdFacet::WhiteSpace)) {
1175 const QString value = whiteSpaceValue->stringValue();
1176 const QString baseValue = DerivedString<TypeString>::Ptr(baseFacets.value(akey: XsdFacet::WhiteSpace)->value())->stringValue();
1177 if (value == XsdSchemaToken::toString(token: XsdSchemaToken::Replace) || value == XsdSchemaToken::toString(token: XsdSchemaToken::Preserve)) {
1178 if (baseValue == XsdSchemaToken::toString(token: XsdSchemaToken::Collapse)) {
1179 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet cannot be %2 or %3 if %4 facet of base type is %5.")
1180 .arg(a: formatKeyword(keyword: "whiteSpace"))
1181 .arg(a: formatData(data: "replace"))
1182 .arg(a: formatData(data: "preserve"))
1183 .arg(a: formatKeyword(keyword: "whiteSpace"))
1184 .arg(a: formatData(data: "collapse")),
1185 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1186 return;
1187 }
1188 }
1189 if (value == XsdSchemaToken::toString(token: XsdSchemaToken::Preserve) && baseValue == XsdSchemaToken::toString(token: XsdSchemaToken::Replace)) {
1190 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet cannot be %2 if %3 facet of base type is %4.")
1191 .arg(a: formatKeyword(keyword: "whiteSpace"))
1192 .arg(a: formatData(data: "preserve"))
1193 .arg(a: formatKeyword(keyword: "whiteSpace"))
1194 .arg(a: formatData(data: "replace")),
1195 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1196 return;
1197 }
1198 }
1199 }
1200 }
1201 if (facets.contains(akey: XsdFacet::MaximumInclusive)) {
1202 const XsdFacet::Ptr maxFacet = facets.value(akey: XsdFacet::MaximumInclusive);
1203
1204 // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-less-than-equal-to-maxInclusive
1205 if (facets.contains(akey: XsdFacet::MinimumInclusive)) {
1206 const XsdFacet::Ptr minFacet = facets.value(akey: XsdFacet::MinimumInclusive);
1207
1208 if (comparableBaseType) {
1209 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorGreaterThan, operand2: maxFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1210 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet.")
1211 .arg(a: formatKeyword(keyword: "minInclusive"))
1212 .arg(a: formatKeyword(keyword: "maxInclusive")),
1213 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1214 return;
1215 }
1216 }
1217 }
1218
1219 // @see http://www.w3.org/TR/xmlschema-2/#maxInclusive-valid-restriction
1220 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1221 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1222 if (baseFacets.contains(akey: XsdFacet::MaximumInclusive)) {
1223 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MaximumInclusive);
1224 if (comparableBaseType) {
1225 if (XsdSchemaHelper::constructAndCompare(operand1: maxFacet->value(), op: AtomicComparator::OperatorGreaterThan, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1226 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet of base type.")
1227 .arg(a: formatKeyword(keyword: "maxInclusive"))
1228 .arg(a: formatKeyword(keyword: "maxInclusive")),
1229 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1230 return;
1231 }
1232 }
1233 }
1234 if (baseFacets.contains(akey: XsdFacet::MaximumExclusive)) {
1235 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MaximumExclusive);
1236 if (comparableBaseType) {
1237 if (XsdSchemaHelper::constructAndCompare(operand1: maxFacet->value(), op: AtomicComparator::OperatorGreaterOrEqual, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1238 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than %2 facet of base type.")
1239 .arg(a: formatKeyword(keyword: "maxInclusive"))
1240 .arg(a: formatKeyword(keyword: "maxExclusive")),
1241 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1242 return;
1243 }
1244 }
1245 }
1246 }
1247 }
1248 if (facets.contains(akey: XsdFacet::MaximumExclusive)) {
1249 const XsdFacet::Ptr maxFacet = facets.value(akey: XsdFacet::MaximumExclusive);
1250
1251 // @see http://www.w3.org/TR/xmlschema-2/#maxInclusive-maxExclusive
1252 if (facets.contains(akey: XsdFacet::MaximumInclusive)) {
1253 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet and %2 facet cannot appear together.")
1254 .arg(a: formatKeyword(keyword: "maxExclusive"))
1255 .arg(a: formatKeyword(keyword: "maxInclusive")),
1256 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1257 return;
1258 }
1259
1260 // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-less-than-equal-to-maxExclusive
1261 if (facets.contains(akey: XsdFacet::MinimumExclusive)) {
1262 const XsdFacet::Ptr minFacet = facets.value(akey: XsdFacet::MinimumExclusive);
1263 if (comparableBaseType) {
1264 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorGreaterThan, operand2: maxFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1265 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet.")
1266 .arg(a: formatKeyword(keyword: "minExclusive"))
1267 .arg(a: formatKeyword(keyword: "maxExclusive")),
1268 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1269 return;
1270 }
1271 }
1272 }
1273
1274 // @see http://www.w3.org/TR/xmlschema-2/#maxExclusive-valid-restriction
1275 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1276 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1277 if (baseFacets.contains(akey: XsdFacet::MaximumExclusive)) {
1278 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MaximumExclusive);
1279 if (comparableBaseType) {
1280 if (XsdSchemaHelper::constructAndCompare(operand1: maxFacet->value(), op: AtomicComparator::OperatorGreaterThan, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1281 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet of base type.")
1282 .arg(a: formatKeyword(keyword: "maxExclusive"))
1283 .arg(a: formatKeyword(keyword: "maxExclusive")),
1284 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1285 return;
1286 }
1287 }
1288 }
1289 if (baseFacets.contains(akey: XsdFacet::MaximumInclusive)) {
1290 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MaximumInclusive);
1291 if (comparableBaseType) {
1292 if (XsdSchemaHelper::constructAndCompare(operand1: maxFacet->value(), op: AtomicComparator::OperatorGreaterThan, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1293 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet of base type.")
1294 .arg(a: formatKeyword(keyword: "maxExclusive"))
1295 .arg(a: formatKeyword(keyword: "maxInclusive")),
1296 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1297 return;
1298 }
1299 }
1300 }
1301 if (baseFacets.contains(akey: XsdFacet::MinimumInclusive)) {
1302 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MinimumInclusive);
1303 if (comparableBaseType) {
1304 if (XsdSchemaHelper::constructAndCompare(operand1: maxFacet->value(), op: AtomicComparator::OperatorLessOrEqual, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1305 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be greater than %2 facet of base type.")
1306 .arg(a: formatKeyword(keyword: "maxExclusive"))
1307 .arg(a: formatKeyword(keyword: "minInclusive")),
1308 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1309 return;
1310 }
1311 }
1312 }
1313 if (baseFacets.contains(akey: XsdFacet::MinimumExclusive)) {
1314 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MinimumExclusive);
1315 if (comparableBaseType) {
1316 if (XsdSchemaHelper::constructAndCompare(operand1: maxFacet->value(), op: AtomicComparator::OperatorLessOrEqual, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1317 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be greater than %2 facet of base type.")
1318 .arg(a: formatKeyword(keyword: "maxExclusive"))
1319 .arg(a: formatKeyword(keyword: "minExclusive")),
1320 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1321 return;
1322 }
1323 }
1324 }
1325 }
1326 }
1327 if (facets.contains(akey: XsdFacet::MinimumExclusive)) {
1328 const XsdFacet::Ptr minFacet = facets.value(akey: XsdFacet::MinimumExclusive);
1329
1330 // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-minExclusive
1331 if (facets.contains(akey: XsdFacet::MinimumInclusive)) {
1332 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet and %2 facet cannot appear together.")
1333 .arg(a: formatKeyword(keyword: "minExclusive"))
1334 .arg(a: formatKeyword(keyword: "minInclusive")),
1335 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1336 return;
1337 }
1338
1339 // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-less-than-maxInclusive
1340 if (facets.contains(akey: XsdFacet::MaximumInclusive)) {
1341 const XsdFacet::Ptr maxFacet = facets.value(akey: XsdFacet::MaximumInclusive);
1342 if (comparableBaseType) {
1343 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorGreaterOrEqual, operand2: maxFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1344 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than %2 facet.")
1345 .arg(a: formatKeyword(keyword: "minExclusive"))
1346 .arg(a: formatKeyword(keyword: "maxInclusive")),
1347 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1348 return;
1349 }
1350 }
1351 }
1352
1353 // @see http://www.w3.org/TR/xmlschema-2/#minExclusive-valid-restriction
1354 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1355 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1356 if (baseFacets.contains(akey: XsdFacet::MinimumExclusive)) {
1357 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MinimumExclusive);
1358 if (comparableBaseType) {
1359 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorLessThan, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1360 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be greater than or equal to %2 facet of base type.")
1361 .arg(a: formatKeyword(keyword: "minExclusive"))
1362 .arg(a: formatKeyword(keyword: "minExclusive")),
1363 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1364 return;
1365 }
1366 }
1367 }
1368 if (baseFacets.contains(akey: XsdFacet::MaximumExclusive)) {
1369 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MaximumExclusive);
1370 if (comparableBaseType) {
1371 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorGreaterOrEqual, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1372 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than %2 facet of base type.")
1373 .arg(a: formatKeyword(keyword: "minExclusive"))
1374 .arg(a: formatKeyword(keyword: "maxExclusive")),
1375 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1376 return;
1377 }
1378 }
1379 }
1380 if (baseFacets.contains(akey: XsdFacet::MaximumInclusive)) {
1381 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MaximumInclusive);
1382 if (comparableBaseType) {
1383 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorGreaterThan, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1384 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet of base type.")
1385 .arg(a: formatKeyword(keyword: "minExclusive"))
1386 .arg(a: formatKeyword(keyword: "maxInclusive")),
1387 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1388 return;
1389 }
1390 }
1391 }
1392 }
1393 }
1394 if (facets.contains(akey: XsdFacet::MinimumInclusive)) {
1395 const XsdFacet::Ptr minFacet = facets.value(akey: XsdFacet::MinimumInclusive);
1396
1397 // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-less-than-maxExclusive
1398 if (facets.contains(akey: XsdFacet::MaximumExclusive)) {
1399 const XsdFacet::Ptr maxFacet = facets.value(akey: XsdFacet::MaximumExclusive);
1400 if (comparableBaseType) {
1401 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorGreaterOrEqual, operand2: maxFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1402 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than %2 facet.")
1403 .arg(a: formatKeyword(keyword: "minInclusive"))
1404 .arg(a: formatKeyword(keyword: "maxExclusive")),
1405 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1406 return;
1407 }
1408 }
1409 }
1410
1411 // @see http://www.w3.org/TR/xmlschema-2/#minInclusive-valid-restriction
1412 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1413 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1414 if (baseFacets.contains(akey: XsdFacet::MinimumInclusive)) {
1415 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MinimumInclusive);
1416 if (comparableBaseType) {
1417 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorLessThan, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1418 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be greater than or equal to %2 facet of base type.")
1419 .arg(a: formatKeyword(keyword: "minInclusive"))
1420 .arg(a: formatKeyword(keyword: "minInclusive")),
1421 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1422 return;
1423 }
1424 }
1425 }
1426 if (baseFacets.contains(akey: XsdFacet::MinimumExclusive)) {
1427 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MinimumExclusive);
1428 if (comparableBaseType) {
1429 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorLessOrEqual, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1430 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be greater than %2 facet of base type.")
1431 .arg(a: formatKeyword(keyword: "minInclusive"))
1432 .arg(a: formatKeyword(keyword: "minExclusive")),
1433 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1434 return;
1435 }
1436 }
1437 }
1438 if (baseFacets.contains(akey: XsdFacet::MaximumInclusive)) {
1439 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MaximumInclusive);
1440 if (comparableBaseType) {
1441 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorGreaterThan, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1442 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet of base type.")
1443 .arg(a: formatKeyword(keyword: "minInclusive"))
1444 .arg(a: formatKeyword(keyword: "maxInclusive")),
1445 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1446 return;
1447 }
1448 }
1449 }
1450 if (baseFacets.contains(akey: XsdFacet::MaximumExclusive)) {
1451 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::MaximumExclusive);
1452 if (comparableBaseType) {
1453 if (XsdSchemaHelper::constructAndCompare(operand1: minFacet->value(), op: AtomicComparator::OperatorGreaterOrEqual, operand2: baseFacet->value(), type: comparableBaseType, context: m_context, sourceLocationReflection: &reflection)) {
1454 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than %2 facet of base type.")
1455 .arg(a: formatKeyword(keyword: "minInclusive"))
1456 .arg(a: formatKeyword(keyword: "maxExclusive")),
1457 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1458 return;
1459 }
1460 }
1461 }
1462 }
1463 }
1464 if (facets.contains(akey: XsdFacet::TotalDigits)) {
1465 const XsdFacet::Ptr totalDigitsFacet = facets.value(akey: XsdFacet::TotalDigits);
1466 const DerivedInteger<TypeNonNegativeInteger>::Ptr totalDigitsValue = totalDigitsFacet->value();
1467
1468 // @see http://www.w3.org/TR/xmlschema-2/#totalDigits-valid-restriction
1469 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1470 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1471 if (baseFacets.contains(akey: XsdFacet::TotalDigits)) {
1472 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::TotalDigits);
1473 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacet->value();
1474
1475 if (totalDigitsValue->toInteger() > baseValue->toInteger()) {
1476 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet of base type.")
1477 .arg(a: formatKeyword(keyword: "totalDigits"))
1478 .arg(a: formatKeyword(keyword: "totalDigits")),
1479 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1480 return;
1481 }
1482 }
1483 }
1484 }
1485 if (facets.contains(akey: XsdFacet::FractionDigits)) {
1486 const XsdFacet::Ptr fractionDigitsFacet = facets.value(akey: XsdFacet::FractionDigits);
1487 const DerivedInteger<TypeNonNegativeInteger>::Ptr fractionDigitsValue = fractionDigitsFacet->value();
1488
1489 // http://www.w3.org/TR/xmlschema-2/#fractionDigits-totalDigits
1490 if (facets.contains(akey: XsdFacet::TotalDigits)) {
1491 const XsdFacet::Ptr totalDigitsFacet = facets.value(akey: XsdFacet::TotalDigits);
1492 const DerivedInteger<TypeNonNegativeInteger>::Ptr totalDigitsValue = totalDigitsFacet->value();
1493
1494 if (fractionDigitsValue->toInteger() > totalDigitsValue->toInteger()) {
1495 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet.")
1496 .arg(a: formatKeyword(keyword: "fractionDigits"))
1497 .arg(a: formatKeyword(keyword: "totalDigits")),
1498 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1499 return;
1500 }
1501 }
1502
1503 // @see http://www.w3.org/TR/xmlschema-2/#fractionDigits-valid-restriction
1504 if (simpleType->derivationMethod() == XsdSimpleType::DerivationRestriction) {
1505 const XsdFacet::Hash baseFacets = m_context->facetsForType(type: simpleType->wxsSuperType());
1506 if (baseFacets.contains(akey: XsdFacet::FractionDigits)) {
1507 const XsdFacet::Ptr baseFacet = baseFacets.value(akey: XsdFacet::FractionDigits);
1508 const DerivedInteger<TypeNonNegativeInteger>::Ptr baseValue = baseFacet->value();
1509
1510 if (fractionDigitsValue->toInteger() > baseValue->toInteger()) {
1511 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 facet must be less than or equal to %2 facet of base type.")
1512 .arg(a: formatKeyword(keyword: "fractionDigits"))
1513 .arg(a: formatKeyword(keyword: "fractionDigits")),
1514 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1515 return;
1516 }
1517 }
1518 }
1519 }
1520
1521
1522 // check whether facets are allowed for simple types variety
1523 if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeAtomic) {
1524 if (simpleType->primitiveType()) {
1525 const QXmlName primitiveTypeName = simpleType->primitiveType()->name(np: m_namePool);
1526 if (m_allowedAtomicFacets.contains(akey: primitiveTypeName)) {
1527 const QSet<XsdFacet::Type> allowedFacets = m_allowedAtomicFacets.value(akey: primitiveTypeName);
1528
1529 QSet<XsdFacet::Type> availableFacets;
1530 for (auto it = facets.cbegin(), end = facets.cend(); it != end; ++it)
1531 availableFacets.insert(value: it.key());
1532
1533 if (!availableFacets.subtract(other: allowedFacets).isEmpty()) {
1534 m_context->error(message: QtXmlPatterns::tr(sourceText: "Simple type contains not allowed facet %1.")
1535 .arg(a: formatKeyword(keyword: XsdFacet::typeName(type: availableFacets.values().constFirst()))),
1536 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1537 return;
1538 }
1539 }
1540 }
1541 } else if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeList) {
1542 if (facets.contains(akey: XsdFacet::MaximumInclusive) || facets.contains(akey: XsdFacet::MinimumInclusive) ||
1543 facets.contains(akey: XsdFacet::MaximumExclusive) || facets.contains(akey: XsdFacet::MinimumExclusive) ||
1544 facets.contains(akey: XsdFacet::TotalDigits) || facets.contains(akey: XsdFacet::FractionDigits))
1545 {
1546 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1, %2, %3, %4, %5 and %6 facets are not allowed when derived by list.")
1547 .arg(a: formatKeyword(keyword: "maxInclusive"))
1548 .arg(a: formatKeyword(keyword: "maxExclusive"))
1549 .arg(a: formatKeyword(keyword: "minInclusive"))
1550 .arg(a: formatKeyword(keyword: "minExclusive"))
1551 .arg(a: formatKeyword(keyword: "totalDigits"))
1552 .arg(a: formatKeyword(keyword: "fractionDigits")),
1553 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1554 }
1555 } else if (simpleType->wxsSuperType()->category() == SchemaType::SimpleTypeUnion) {
1556 if (facets.contains(akey: XsdFacet::MaximumInclusive) || facets.contains(akey: XsdFacet::MinimumInclusive) ||
1557 facets.contains(akey: XsdFacet::MaximumExclusive) || facets.contains(akey: XsdFacet::MinimumExclusive) ||
1558 facets.contains(akey: XsdFacet::TotalDigits) || facets.contains(akey: XsdFacet::FractionDigits) ||
1559 facets.contains(akey: XsdFacet::MinimumLength) || facets.contains(akey: XsdFacet::MaximumLength) ||
1560 facets.contains(akey: XsdFacet::Length) || facets.contains(akey: XsdFacet::WhiteSpace))
1561 {
1562 m_context->error(message: QtXmlPatterns::tr(sourceText: "Only %1 and %2 facets are allowed when derived by union.")
1563 .arg(a: formatKeyword(keyword: "pattern"))
1564 .arg(a: formatKeyword(keyword: "enumeration")),
1565 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1566 }
1567 }
1568
1569 // check whether value of facet matches the value space of the simple types base type
1570 const SchemaType::Ptr baseType = simpleType->wxsSuperType();
1571 if (!baseType->isDefinedBySchema()) {
1572 const XsdSchemaSourceLocationReflection reflection(sourceLocation(component: simpleType));
1573
1574 for (auto it = facets.cbegin(), end = facets.cend(); it != end; ++it) {
1575 const XsdFacet::Ptr facet = it.value();
1576 if (facet->type() == XsdFacet::MaximumInclusive ||
1577 facet->type() == XsdFacet::MaximumExclusive ||
1578 facet->type() == XsdFacet::MinimumInclusive ||
1579 facet->type() == XsdFacet::MinimumExclusive) {
1580 const DerivedString<TypeString>::Ptr stringValue = facet->value();
1581 const AtomicValue::Ptr value = ValueFactory::fromLexical(lexicalValue: stringValue->stringValue(), type: baseType, context: m_context, sourceLocationReflection: &reflection);
1582 if (value->hasError()) {
1583 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 contains %2 facet with invalid data: %3.")
1584 .arg(a: formatType(np: m_namePool, type: simpleType))
1585 .arg(a: formatKeyword(keyword: XsdFacet::typeName(type: facet->type())))
1586 .arg(a: formatData(data: stringValue->stringValue())),
1587 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1588 return;
1589 }
1590 }
1591
1592 // @see http://www.w3.org/TR/xmlschema-2/#enumeration-valid-restriction
1593 if (facet->type() == XsdFacet::Enumeration && baseType != BuiltinTypes::xsNOTATION) {
1594 const AtomicValue::List multiValue = facet->multiValue();
1595 for (int j = 0; j < multiValue.count(); ++j) {
1596 const QString stringValue = DerivedString<TypeString>::Ptr(multiValue.at(i: j))->stringValue();
1597 const AtomicValue::Ptr value = ValueFactory::fromLexical(lexicalValue: stringValue, type: baseType, context: m_context, sourceLocationReflection: &reflection);
1598 if (value->hasError()) {
1599 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 contains %2 facet with invalid data: %3.")
1600 .arg(a: formatType(np: m_namePool, type: simpleType))
1601 .arg(a: formatKeyword(keyword: XsdFacet::typeName(type: XsdFacet::Enumeration)))
1602 .arg(a: formatData(data: stringValue)),
1603 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType));
1604 return;
1605 }
1606 }
1607 }
1608 }
1609 }
1610}
1611
1612void XsdSchemaChecker::checkDuplicatedAttributeUses()
1613{
1614 // first all global attribute groups
1615 const XsdAttributeGroup::List attributeGroups = m_schema->attributeGroups();
1616 for (int i = 0; i < attributeGroups.count(); ++i) {
1617 const XsdAttributeGroup::Ptr attributeGroup = attributeGroups.at(i);
1618 const XsdAttributeUse::List uses = attributeGroup->attributeUses();
1619
1620 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 4)
1621 XsdAttribute::Ptr conflictingAttribute;
1622 if (hasDuplicatedAttributeUses(list: uses, conflictingAttribute)) {
1623 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute group %1 contains attribute %2 twice.")
1624 .arg(a: formatKeyword(keyword: attributeGroup->displayName(namePool: m_namePool)))
1625 .arg(a: formatKeyword(keyword: conflictingAttribute->displayName(namePool: m_namePool))),
1626 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: attributeGroup));
1627 return;
1628 }
1629
1630 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 5)
1631 if (hasMultipleIDAttributeUses(list: uses)) {
1632 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute group %1 contains two different attributes that both have types derived from %2.")
1633 .arg(a: formatKeyword(keyword: attributeGroup->displayName(namePool: m_namePool)))
1634 .arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsID)),
1635 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: attributeGroup));
1636 return;
1637 }
1638
1639 if (hasConstraintIDAttributeUse(list: uses, conflictingAttribute)) {
1640 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute group %1 contains attribute %2 that has value constraint but type that inherits from %3.")
1641 .arg(a: formatKeyword(keyword: attributeGroup->displayName(namePool: m_namePool)))
1642 .arg(a: formatKeyword(keyword: conflictingAttribute->displayName(namePool: m_namePool)))
1643 .arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsID)),
1644 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: attributeGroup));
1645 return;
1646 }
1647 }
1648
1649 // then the global and anonymous complex types
1650 SchemaType::List types = m_schema->types();
1651 types << m_schema->anonymousTypes();
1652
1653 for (int i = 0; i < types.count(); ++i) {
1654 if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema())
1655 continue;
1656
1657 const XsdComplexType::Ptr complexType = types.at(i);
1658 const XsdAttributeUse::List attributeUses = complexType->attributeUses();
1659
1660 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 4)
1661 XsdAttribute::Ptr conflictingAttribute;
1662 if (hasDuplicatedAttributeUses(list: attributeUses, conflictingAttribute)) {
1663 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 contains attribute %2 twice.")
1664 .arg(a: formatType(np: m_namePool, type: complexType))
1665 .arg(a: formatKeyword(keyword: conflictingAttribute->displayName(namePool: m_namePool))),
1666 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType));
1667 return;
1668 }
1669
1670 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 5)
1671 if (hasMultipleIDAttributeUses(list: attributeUses)) {
1672 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 contains two different attributes that both have types derived from %2.")
1673 .arg(a: formatType(np: m_namePool, type: complexType))
1674 .arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsID)),
1675 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType));
1676 return;
1677 }
1678
1679 if (hasConstraintIDAttributeUse(list: attributeUses, conflictingAttribute)) {
1680 m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 contains attribute %2 that has value constraint but type that inherits from %3.")
1681 .arg(a: formatType(np: m_namePool, type: complexType))
1682 .arg(a: formatKeyword(keyword: conflictingAttribute->displayName(namePool: m_namePool)))
1683 .arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsID)),
1684 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType));
1685 return;
1686 }
1687 }
1688}
1689
1690void XsdSchemaChecker::checkElementConstraints()
1691{
1692 const QSet<XsdElement::Ptr> elements = collectAllElements(schema: m_schema);
1693
1694 for (const XsdElement::Ptr &element : elements) {
1695
1696 // @see http://www.w3.org/TR/xmlschema11-1/#e-props-correct
1697
1698 // 2 and xs:ID check
1699 if (element->valueConstraint()) {
1700 const SchemaType::Ptr type = element->type();
1701
1702 AnySimpleType::Ptr targetType;
1703 if (type->isSimpleType() && type->category() == SchemaType::SimpleTypeAtomic) {
1704 targetType = type;
1705
1706 // if it is a XsdSimpleType, use its primitive type as target type
1707 if (type->isDefinedBySchema())
1708 targetType = XsdSimpleType::Ptr(type)->primitiveType();
1709
1710 } else if (type->isComplexType() && type->isDefinedBySchema()) {
1711 const XsdComplexType::Ptr complexType(type);
1712
1713 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
1714 const AnySimpleType::Ptr simpleType = complexType->contentType()->simpleType();
1715 if (simpleType->category() == AnySimpleType::SimpleTypeAtomic) {
1716 targetType = simpleType;
1717
1718 if (simpleType->isDefinedBySchema())
1719 targetType = XsdSimpleType::Ptr(simpleType)->primitiveType();
1720 }
1721 } else if (complexType->contentType()->variety() != XsdComplexType::ContentType::Mixed) {
1722 m_context->error(message: QtXmlPatterns::tr(sourceText: "Element %1 is not allowed to have a value constraint if its base type is complex.")
1723 .arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool))),
1724 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: element));
1725 return;
1726 }
1727 }
1728 if ((targetType == BuiltinTypes::xsID) || BuiltinTypes::xsID->wxsTypeMatches(other: type)) {
1729 m_context->error(message: QtXmlPatterns::tr(sourceText: "Element %1 is not allowed to have a value constraint if its type is derived from %2.")
1730 .arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool)))
1731 .arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsID)),
1732 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: element));
1733 return;
1734 }
1735
1736 if (type->isSimpleType()) {
1737 QString errorMsg;
1738 if (!isValidValue(value: element->valueConstraint()->value(), type, errorMsg)) {
1739 m_context->error(message: QtXmlPatterns::tr(sourceText: "Value constraint of element %1 is not of elements type: %2.")
1740 .arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool)))
1741 .arg(a: errorMsg),
1742 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: element));
1743 return;
1744 }
1745 } else if (type->isComplexType() && type->isDefinedBySchema()) {
1746 const XsdComplexType::Ptr complexType(type);
1747 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
1748 QString errorMsg;
1749 if (!isValidValue(value: element->valueConstraint()->value(), type: complexType->contentType()->simpleType(), errorMsg)) {
1750 m_context->error(message: QtXmlPatterns::tr(sourceText: "Value constraint of element %1 is not of elements type: %2.")
1751 .arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool)))
1752 .arg(a: errorMsg),
1753 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: element));
1754 return;
1755 }
1756 }
1757 }
1758 }
1759
1760 if (!element->substitutionGroupAffiliations().isEmpty()) {
1761 // 3
1762 if (!element->scope() || element->scope()->variety() != XsdElement::Scope::Global) {
1763 m_context->error(message: QtXmlPatterns::tr(sourceText: "Element %1 is not allowed to have substitution group affiliation as it is no global element.").arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool))),
1764 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: element));
1765 return;
1766 }
1767
1768 // 4
1769 const XsdElement::List affiliations = element->substitutionGroupAffiliations();
1770 for (int i = 0; i < affiliations.count(); ++i) {
1771 const XsdElement::Ptr affiliation = affiliations.at(i);
1772
1773 bool derivationOk = false;
1774 if (element->type()->isComplexType() && affiliation->type()->isComplexType()) {
1775 if (XsdSchemaHelper::isComplexDerivationOk(derivedType: element->type(), baseType: affiliation->type(), constraints: affiliation->substitutionGroupExclusions())) {
1776 derivationOk = true;
1777 }
1778 }
1779 if (element->type()->isComplexType() && affiliation->type()->isSimpleType()) {
1780 if (XsdSchemaHelper::isComplexDerivationOk(derivedType: element->type(), baseType: affiliation->type(), constraints: affiliation->substitutionGroupExclusions())) {
1781 derivationOk = true;
1782 }
1783 }
1784 if (element->type()->isSimpleType()) {
1785 if (XsdSchemaHelper::isSimpleDerivationOk(derivedType: element->type(), baseType: affiliation->type(), constraints: affiliation->substitutionGroupExclusions())) {
1786 derivationOk = true;
1787 }
1788 }
1789
1790 if (!derivationOk) {
1791 m_context->error(message: QtXmlPatterns::tr(sourceText: "Type of element %1 cannot be derived from type of substitution group affiliation.").arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool))),
1792 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: element));
1793 return;
1794 }
1795 }
1796
1797 // 5 was checked in XsdSchemaResolver::resolveSubstitutionGroupAffiliations() already
1798 }
1799 }
1800}
1801
1802void XsdSchemaChecker::checkAttributeConstraints()
1803{
1804 // all global attributes
1805 XsdAttribute::List attributes = m_schema->attributes();
1806
1807 // and all local attributes
1808 SchemaType::List types = m_schema->types();
1809 types << m_schema->anonymousTypes();
1810
1811 for (int i = 0; i < types.count(); ++i) {
1812 if (!types.at(i)->isComplexType() || !types.at(i)->isDefinedBySchema())
1813 continue;
1814
1815 const XsdComplexType::Ptr complexType(types.at(i));
1816 const XsdAttributeUse::List uses = complexType->attributeUses();
1817 for (int j = 0; j < uses.count(); ++j)
1818 attributes.append(t: uses.at(i: j)->attribute());
1819 }
1820
1821 for (int i = 0; i < attributes.count(); ++i) {
1822 const XsdAttribute::Ptr attribute = attributes.at(i);
1823
1824 if (!attribute->valueConstraint())
1825 continue;
1826
1827 if (attribute->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Default || attribute->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Fixed) {
1828 const SchemaType::Ptr type = attribute->type();
1829
1830 QString errorMsg;
1831 if (!isValidValue(value: attribute->valueConstraint()->value(), type: attribute->type(), errorMsg)) {
1832 m_context->error(message: QtXmlPatterns::tr(sourceText: "Value constraint of attribute %1 is not of attributes type: %2.")
1833 .arg(a: formatKeyword(keyword: attribute->displayName(namePool: m_namePool)))
1834 .arg(a: errorMsg),
1835 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: attribute));
1836 return;
1837 }
1838 }
1839
1840 if (BuiltinTypes::xsID->wxsTypeMatches(other: attribute->type())) {
1841 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute %1 has value constraint but has type derived from %2.")
1842 .arg(a: formatKeyword(keyword: attribute->displayName(namePool: m_namePool)))
1843 .arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsID)),
1844 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: attribute));
1845 return;
1846 }
1847 }
1848}
1849
1850bool XsdSchemaChecker::isValidValue(const QString &stringValue, const AnySimpleType::Ptr &type, QString &errorMsg) const
1851{
1852 if (BuiltinTypes::xsAnySimpleType->name(np: m_namePool) == type->name(np: m_namePool))
1853 return true; // no need to check xs:anyType content
1854
1855 const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(type, context: m_context);
1856 const QString actualValue = XsdTypeChecker::normalizedValue(value: stringValue, facets);
1857
1858 const XsdTypeChecker checker(m_context, QVector<QXmlName>(), QSourceLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1));
1859 return checker.isValidString(normalizedString: actualValue, type, errorMsg);
1860}
1861
1862void XsdSchemaChecker::checkAttributeUseConstraints()
1863{
1864 XsdComplexType::List complexTypes;
1865
1866 SchemaType::List types = m_schema->types();
1867 types << m_schema->anonymousTypes();
1868
1869 for (int i = 0; i < types.count(); ++i) {
1870 const SchemaType::Ptr type = types.at(i);
1871 if (type->isComplexType() && type->isDefinedBySchema())
1872 complexTypes.append(t: XsdComplexType::Ptr(type));
1873 }
1874
1875 for (int i = 0; i < complexTypes.count(); ++i) {
1876 const XsdComplexType::Ptr complexType(complexTypes.at(i));
1877 const SchemaType::Ptr baseType = complexType->wxsSuperType();
1878 if (!baseType || !baseType->isComplexType() || !baseType->isDefinedBySchema())
1879 continue;
1880
1881 const XsdComplexType::Ptr complexBaseType(baseType);
1882
1883 const XsdAttributeUse::List attributeUses = complexType->attributeUses();
1884 QHash<QXmlName, XsdAttributeUse::Ptr> lookupHash;
1885 for (int j = 0; j < attributeUses.count(); ++j)
1886 lookupHash.insert(akey: attributeUses.at(i: j)->attribute()->name(namePool: m_namePool), avalue: attributeUses.at(i: j));
1887
1888 const XsdAttributeUse::List baseAttributeUses = complexBaseType->attributeUses();
1889 for (int j = 0; j < baseAttributeUses.count(); ++j) {
1890 const XsdAttributeUse::Ptr baseAttributeUse = baseAttributeUses.at(i: j);
1891
1892 if (lookupHash.contains(akey: baseAttributeUse->attribute()->name(namePool: m_namePool))) {
1893 const XsdAttributeUse::Ptr attributeUse = lookupHash.value(akey: baseAttributeUse->attribute()->name(namePool: m_namePool));
1894
1895 if (baseAttributeUse->useType() == XsdAttributeUse::RequiredUse) {
1896 if (attributeUse->useType() == XsdAttributeUse::OptionalUse || attributeUse->useType() == XsdAttributeUse::ProhibitedUse) {
1897 m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 attribute in derived complex type must be %2 like in base type.")
1898 .arg(a: formatAttribute(attribute: "use"))
1899 .arg(a: formatData(data: "required")),
1900 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType));
1901 return;
1902 }
1903 }
1904
1905 if (baseAttributeUse->valueConstraint()) {
1906 if (baseAttributeUse->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Fixed) {
1907 if (!attributeUse->valueConstraint()) {
1908 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute %1 in derived complex type must have %2 value constraint like in base type.")
1909 .arg(a: formatKeyword(keyword: attributeUse->attribute()->displayName(namePool: m_namePool)))
1910 .arg(a: formatData(data: "fixed")),
1911 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType));
1912 return;
1913 } else {
1914 if (attributeUse->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Fixed) {
1915 const XsdTypeChecker checker(m_context, QVector<QXmlName>(), sourceLocation(component: complexType));
1916 if (!checker.valuesAreEqual(value: attributeUse->valueConstraint()->value(), otherValue: baseAttributeUse->valueConstraint()->value(), type: attributeUse->attribute()->type())) {
1917 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute %1 in derived complex type must have the same %2 value constraint like in base type.")
1918 .arg(a: formatKeyword(keyword: attributeUse->attribute()->displayName(namePool: m_namePool)))
1919 .arg(a: formatData(data: "fixed")),
1920 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType));
1921 return;
1922 }
1923 } else {
1924 m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute %1 in derived complex type must have %2 value constraint.")
1925 .arg(a: formatKeyword(keyword: attributeUse->attribute()->displayName(namePool: m_namePool)))
1926 .arg(a: formatData(data: "fixed")),
1927 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType));
1928 return;
1929 }
1930 }
1931 }
1932 }
1933 }
1934 }
1935
1936 // additional check that process content property of attribute wildcard in derived type is
1937 // not weaker than the wildcard in base type
1938 const XsdWildcard::Ptr baseWildcard(complexBaseType->attributeWildcard());
1939 const XsdWildcard::Ptr derivedWildcard(complexType->attributeWildcard());
1940 if (baseWildcard && derivedWildcard) {
1941 if (!XsdSchemaHelper::checkWildcardProcessContents(baseWildcard, derivedWildcard)) {
1942 m_context->error(message: QtXmlPatterns::tr(sourceText: "processContent of base wildcard must be weaker than derived wildcard."), errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType));
1943 return;
1944 }
1945 }
1946 }
1947}
1948
1949void XsdSchemaChecker::checkElementDuplicates()
1950{
1951 // check all global types...
1952 SchemaType::List types = m_schema->types();
1953
1954 // .. and anonymous types
1955 types << m_schema->anonymousTypes();
1956
1957 for (int i = 0; i < types.count(); ++i) {
1958 const SchemaType::Ptr type = types.at(i);
1959
1960 if (!type->isComplexType() || !type->isDefinedBySchema())
1961 continue;
1962
1963 const XsdComplexType::Ptr complexType(type);
1964
1965 if ((complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) || (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) {
1966 DuplicatedElementMap elementMap;
1967 DuplicatedWildcardMap wildcardMap;
1968
1969 checkElementDuplicates(particle: complexType->contentType()->particle(), elementMap, wildcardMap);
1970 }
1971 }
1972}
1973
1974void XsdSchemaChecker::checkElementDuplicates(const XsdParticle::Ptr &particle, DuplicatedElementMap &elementMap, DuplicatedWildcardMap &wildcardMap)
1975{
1976 if (particle->term()->isElement()) {
1977 const XsdElement::Ptr element(particle->term());
1978
1979 if (elementMap.contains(akey: element->name(namePool: m_namePool))) {
1980 if (element->type() != elementMap.value(akey: element->name(namePool: m_namePool))) {
1981 m_context->error(message: QtXmlPatterns::tr(sourceText: "Element %1 exists twice with different types.")
1982 .arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool))),
1983 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: element));
1984 return;
1985 }
1986 } else {
1987 elementMap.insert(akey: element->name(namePool: m_namePool), avalue: element->type());
1988 }
1989
1990 // check substitution group affiliation
1991 const XsdElement::List substElements = element->substitutionGroupAffiliations();
1992 for (int i = 0; i < substElements.count(); ++i) {
1993 const XsdElement::Ptr substElement = substElements.at(i);
1994 if (elementMap.contains(akey: substElement->name(namePool: m_namePool))) {
1995 if (substElement->type() != elementMap.value(akey: substElement->name(namePool: m_namePool))) {
1996 m_context->error(message: QtXmlPatterns::tr(sourceText: "Element %1 exists twice with different types.")
1997 .arg(a: formatKeyword(keyword: substElement->displayName(namePool: m_namePool))),
1998 errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: element));
1999 return;
2000 }
2001 } else {
2002 elementMap.insert(akey: substElement->name(namePool: m_namePool), avalue: substElement->type());
2003 }
2004 }
2005 } else if (particle->term()->isModelGroup()) {
2006 const XsdModelGroup::Ptr group(particle->term());
2007 const XsdParticle::List particles = group->particles();
2008 for (int i = 0; i < particles.count(); ++i)
2009 checkElementDuplicates(particle: particles.at(i), elementMap, wildcardMap);
2010 } else if (particle->term()->isWildcard()) {
2011 const XsdWildcard::Ptr wildcard(particle->term());
2012
2013 bool error = false;
2014 if (!wildcardMap.contains(akey: wildcard->namespaceConstraint()->variety())) {
2015 if (!wildcardMap.isEmpty())
2016 error = true;
2017 } else {
2018 const XsdWildcard::Ptr otherWildcard = wildcardMap.value(akey: wildcard->namespaceConstraint()->variety());
2019 if ((wildcard->processContents() != otherWildcard->processContents()) || (wildcard->namespaceConstraint()->namespaces() != otherWildcard->namespaceConstraint()->namespaces()))
2020 error = true;
2021 }
2022
2023 if (error) {
2024 m_context->error(message: QtXmlPatterns::tr(sourceText: "Particle contains non-deterministic wildcards."), errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: wildcard));
2025 return;
2026 } else {
2027 wildcardMap.insert(akey: wildcard->namespaceConstraint()->variety(), avalue: wildcard);
2028 }
2029 }
2030}
2031
2032QSourceLocation XsdSchemaChecker::sourceLocation(const NamedSchemaComponent::Ptr &component) const
2033{
2034 if (m_componentLocationHash.contains(akey: component)) {
2035 return m_componentLocationHash.value(akey: component);
2036 } else {
2037 QSourceLocation location;
2038 location.setLine(1);
2039 location.setColumn(1);
2040 location.setUri(QString::fromLatin1(str: "dummyUri"));
2041
2042 return location;
2043 }
2044}
2045
2046QSourceLocation XsdSchemaChecker::sourceLocationForType(const SchemaType::Ptr &type) const
2047{
2048 if (type->isSimpleType())
2049 return sourceLocation(component: XsdSimpleType::Ptr(type));
2050 else
2051 return sourceLocation(component: XsdComplexType::Ptr(type));
2052}
2053
2054QT_END_NAMESPACE
2055

source code of qtxmlpatterns/src/xmlpatterns/schema/qxsdschemachecker.cpp