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