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 | |
59 | QT_BEGIN_NAMESPACE |
60 | |
61 | using namespace QPatternist; |
62 | |
63 | XsdSchemaChecker::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 | |
71 | XsdSchemaChecker::~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 | */ |
80 | void 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 | |
91 | void 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 | |
106 | void 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 | */ |
115 | static 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 | */ |
160 | static 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 | |
187 | static 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 | |
205 | void 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 | |
237 | void 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 | |
274 | void 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 | |
304 | void 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 | |
345 | void 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 | |
600 | void 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 | |
632 | void 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 | |
841 | void 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 | |
940 | void 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 | |
963 | void 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 | |
1612 | void 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 | |
1690 | void 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 | |
1802 | void 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 | |
1850 | bool 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 | |
1862 | void 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 | |
1949 | void 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 | |
1974 | void 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 | |
2032 | QSourceLocation 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 | |
2046 | QSourceLocation 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 | |
2054 | QT_END_NAMESPACE |
2055 | |