source: trunk/src/xmlpatterns/schema/qxsdschemahelper.cpp@ 966

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

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 34.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qxsdschemahelper_p.h"
43
44#include "qbuiltintypes_p.h"
45#include "qvaluefactory_p.h"
46#include "qxsdcomplextype_p.h"
47#include "qxsdmodelgroup_p.h"
48#include "qxsdsimpletype_p.h"
49#include "qxsdtypechecker_p.h"
50
51QT_BEGIN_NAMESPACE
52
53using namespace QPatternist;
54
55/*
56 * Calculates the effective total range minimum of the given @p particle as
57 * described by the algorithm in the schema spec.
58 */
59static inline unsigned int effectiveTotalRangeMinimum(const XsdParticle::Ptr &particle)
60{
61 const XsdModelGroup::Ptr group = particle->term();
62
63 if (group->compositor() == XsdModelGroup::ChoiceCompositor) {
64 // @see http://www.w3.org/TR/xmlschema11-1/# cos-choice-range
65
66 int minValue = -1;
67
68 const XsdParticle::List particles = group->particles();
69 if (particles.isEmpty())
70 minValue = 0;
71
72 for (int i = 0; i < particles.count(); ++i) {
73 const XsdParticle::Ptr particle = particles.at(i);
74
75 if (particle->term()->isElement() || particle->term()->isWildcard()) {
76 if (minValue == -1) {
77 minValue = particle->minimumOccurs();
78 } else {
79 minValue = qMin((unsigned int)minValue, particle->minimumOccurs());
80 }
81 } else if (particle->term()->isModelGroup()) {
82 if (minValue == -1) {
83 minValue = effectiveTotalRangeMinimum(particle);
84 } else {
85 minValue = qMin((unsigned int)minValue, effectiveTotalRangeMinimum(particle));
86 }
87 }
88 }
89
90 return (particle->minimumOccurs() * minValue);
91
92 } else {
93 // @see http://www.w3.org/TR/xmlschema11-1/# cos-seq-range
94
95 unsigned int sum = 0;
96 const XsdParticle::List particles = group->particles();
97 for (int i = 0; i < particles.count(); ++i) {
98 const XsdParticle::Ptr particle = particles.at(i);
99
100 if (particle->term()->isElement() || particle->term()->isWildcard())
101 sum += particle->minimumOccurs();
102 else if (particle->term()->isModelGroup())
103 sum += effectiveTotalRangeMinimum(particle);
104 }
105
106 return (particle->minimumOccurs() * sum);
107 }
108}
109
110bool XsdSchemaHelper::isParticleEmptiable(const XsdParticle::Ptr &particle)
111{
112 // @see http://www.w3.org/TR/xmlschema11-1/#cos-group-emptiable
113
114 if (particle->minimumOccurs() == 0)
115 return true;
116
117 if (!(particle->term()->isModelGroup()))
118 return false;
119
120 return (effectiveTotalRangeMinimum(particle) == 0);
121}
122
123bool XsdSchemaHelper::wildcardAllowsNamespaceName(const QString &nameSpace, const XsdWildcard::NamespaceConstraint::Ptr &constraint)
124{
125 // @see http://www.w3.org/TR/xmlschema11-1/#cvc-wildcard-namespace
126
127 // 1
128 if (constraint->variety() == XsdWildcard::NamespaceConstraint::Any)
129 return true;
130
131 // 2
132 if (constraint->variety() == XsdWildcard::NamespaceConstraint::Not) { // 2.1
133 if (!constraint->namespaces().contains(nameSpace)) // 2.2
134 if (nameSpace != XsdWildcard::absentNamespace()) // 2.3
135 return true;
136 }
137
138 // 3
139 if (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) {
140 if (constraint->namespaces().contains(nameSpace))
141 return true;
142 }
143
144 return false;
145}
146
147bool XsdSchemaHelper::wildcardAllowsExpandedName(const QXmlName &name, const XsdWildcard::Ptr &wildcard, const NamePool::Ptr &namePool)
148{
149 // @see http://www.w3.org/TR/xmlschema11-1/#cvc-wildcard-name
150
151 // 1
152 if (!wildcardAllowsNamespaceName(namePool->stringForNamespace(name.namespaceURI()), wildcard->namespaceConstraint()))
153 return false;
154
155 // 2, 3, 4
156 //TODO: we have no disallowed namespace yet
157
158 return true;
159}
160
161// small helper function that should be available in Qt 4.6
162template<class T>
163static inline bool containsSet(const QSet<T> &super, const QSet<T> &sub)
164{
165 QSetIterator<T> it(sub);
166 while (it.hasNext()) {
167 if (!super.contains(it.next()))
168 return false;
169 }
170
171 return true;
172}
173
174bool XsdSchemaHelper::isWildcardSubset(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard)
175{
176 // @see http://www.w3.org/TR/xmlschema11-1/#cos-ns-subset
177 // wildcard =^ sub
178 // otherWildcard =^ super
179
180 const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint());
181 const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint());
182
183 // 1
184 if (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any)
185 return true;
186
187 // 2
188 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
189 if (containsSet<QString>(otherConstraint->namespaces(), constraint->namespaces()))
190 return true;
191 }
192
193 // 3
194 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) {
195 if (constraint->namespaces().intersect(otherConstraint->namespaces()).isEmpty())
196 return true;
197 }
198
199 // 4
200 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) {
201 if (containsSet<QString>(constraint->namespaces(), otherConstraint->namespaces()))
202 return true;
203 }
204
205 return false;
206}
207
208XsdWildcard::Ptr XsdSchemaHelper::wildcardUnion(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard)
209{
210 // @see http://www.w3.org/TR/xmlschema11-1/#cos-aw-union
211
212 XsdWildcard::Ptr unionWildcard(new XsdWildcard());
213
214 const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint());
215 const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint());
216
217 // 1
218 if ((constraint->variety() == otherConstraint->variety()) &&
219 (constraint->namespaces() == otherConstraint->namespaces())) {
220 unionWildcard->namespaceConstraint()->setVariety(constraint->variety());
221 unionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces());
222 return unionWildcard;
223 }
224
225 // 2
226 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Any) || (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any)) {
227 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any);
228 return unionWildcard;
229 }
230
231 // 3
232 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
233 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration);
234 unionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces() + otherConstraint->namespaces());
235 return unionWildcard;
236 }
237
238 // 4
239 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) {
240 if (constraint->namespaces() != otherConstraint->namespaces()) {
241 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not);
242 unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace());
243 return unionWildcard;
244 }
245 }
246
247 // 5
248 QSet<QString> sSet, negatedSet;
249 bool matches5 = false;
250 if (((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && !constraint->namespaces().contains(XsdWildcard::absentNamespace()))
251 && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
252
253 negatedSet = constraint->namespaces();
254 sSet = otherConstraint->namespaces();
255 matches5 = true;
256 } else if (((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) && !otherConstraint->namespaces().contains(XsdWildcard::absentNamespace()))
257 && (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
258
259 negatedSet = otherConstraint->namespaces();
260 sSet = constraint->namespaces();
261 matches5 = true;
262 }
263
264 if (matches5) {
265 if (sSet.contains(negatedSet.values().first()) && sSet.contains(XsdWildcard::absentNamespace())) { // 5.1
266 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any);
267 return unionWildcard;
268 }
269 if (sSet.contains(negatedSet.values().first()) && !sSet.contains(XsdWildcard::absentNamespace())) { // 5.2
270 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not);
271 unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace());
272 return unionWildcard;
273 }
274 if (!sSet.contains(negatedSet.values().first()) && sSet.contains(XsdWildcard::absentNamespace())) { // 5.3
275 return XsdWildcard::Ptr(); // not expressible
276 }
277 if (!sSet.contains(negatedSet.values().first()) && !sSet.contains(XsdWildcard::absentNamespace())) { // 5.4
278 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not);
279 unionWildcard->namespaceConstraint()->setNamespaces(negatedSet);
280 return unionWildcard;
281 }
282 }
283
284 // 6
285 bool matches6 = false;
286 if (((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) && constraint->namespaces().contains(XsdWildcard::absentNamespace()))
287 && (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
288
289 negatedSet = constraint->namespaces();
290 sSet = otherConstraint->namespaces();
291 matches6 = true;
292 } else if (((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) && otherConstraint->namespaces().contains(XsdWildcard::absentNamespace()))
293 && (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
294
295 negatedSet = otherConstraint->namespaces();
296 sSet = constraint->namespaces();
297 matches6 = true;
298 }
299
300 if (matches6) {
301 if (sSet.contains(XsdWildcard::absentNamespace())) { // 6.1
302 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any);
303 return unionWildcard;
304 }
305 if (!sSet.contains(XsdWildcard::absentNamespace())) { // 6.2
306 unionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not);
307 unionWildcard->namespaceConstraint()->setNamespaces(QSet<QString>() += XsdWildcard::absentNamespace());
308 return unionWildcard;
309 }
310 }
311
312 return XsdWildcard::Ptr();
313}
314
315XsdWildcard::Ptr XsdSchemaHelper::wildcardIntersection(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &otherWildcard)
316{
317 // @see http://www.w3.org/TR/xmlschema11-1/#cos-aw-intersect
318
319 const XsdWildcard::NamespaceConstraint::Ptr constraint(wildcard->namespaceConstraint());
320 const XsdWildcard::NamespaceConstraint::Ptr otherConstraint(otherWildcard->namespaceConstraint());
321
322 const XsdWildcard::Ptr intersectionWildcard(new XsdWildcard());
323
324 // 1
325 if ((constraint->variety() == otherConstraint->variety()) &&
326 (constraint->namespaces() == otherConstraint->namespaces())) {
327 intersectionWildcard->namespaceConstraint()->setVariety(constraint->variety());
328 intersectionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces());
329 return intersectionWildcard;
330 }
331
332 // 2
333 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Any) &&
334 (otherConstraint->variety() != XsdWildcard::NamespaceConstraint::Any)) {
335 intersectionWildcard->namespaceConstraint()->setVariety(otherConstraint->variety());
336 intersectionWildcard->namespaceConstraint()->setNamespaces(otherConstraint->namespaces());
337 return intersectionWildcard;
338 }
339
340 // 2
341 if ((constraint->variety() != XsdWildcard::NamespaceConstraint::Any) &&
342 (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Any)) {
343 intersectionWildcard->namespaceConstraint()->setVariety(constraint->variety());
344 intersectionWildcard->namespaceConstraint()->setNamespaces(constraint->namespaces());
345 return intersectionWildcard;
346 }
347
348 // 3
349 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) &&
350 (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
351
352 QSet<QString> set = otherConstraint->namespaces();
353 set.subtract(constraint->namespaces());
354 set.remove(XsdWildcard::absentNamespace());
355
356 intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration);
357 intersectionWildcard->namespaceConstraint()->setNamespaces(set);
358
359 return intersectionWildcard;
360 }
361
362 // 3
363 if ((otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not) &&
364 (constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
365
366 QSet<QString> set = constraint->namespaces();
367 set.subtract(otherConstraint->namespaces());
368 set.remove(XsdWildcard::absentNamespace());
369
370 intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration);
371 intersectionWildcard->namespaceConstraint()->setNamespaces(set);
372
373 return intersectionWildcard;
374 }
375
376 // 4
377 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration) &&
378 (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Enumeration)) {
379
380 QSet<QString> set = constraint->namespaces();
381 set.intersect(otherConstraint->namespaces());
382
383 intersectionWildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration);
384 intersectionWildcard->namespaceConstraint()->setNamespaces(set);
385
386 return intersectionWildcard;
387 }
388
389 // 6
390 if ((constraint->variety() == XsdWildcard::NamespaceConstraint::Not) &&
391 (otherConstraint->variety() == XsdWildcard::NamespaceConstraint::Not)) {
392 if (!(constraint->namespaces().contains(XsdWildcard::absentNamespace())) && otherConstraint->namespaces().contains(XsdWildcard::absentNamespace())) {
393 return wildcard;
394 }
395 if (constraint->namespaces().contains(XsdWildcard::absentNamespace()) && !(otherConstraint->namespaces().contains(XsdWildcard::absentNamespace()))) {
396 return otherWildcard;
397 }
398 }
399
400 // 5 as not expressible return empty wildcard
401 return XsdWildcard::Ptr();
402}
403
404static SchemaType::DerivationConstraints convertBlockingConstraints(const NamedSchemaComponent::BlockingConstraints &constraints)
405{
406 SchemaType::DerivationConstraints result = 0;
407
408 if (constraints & NamedSchemaComponent::RestrictionConstraint)
409 result |= SchemaType::RestrictionConstraint;
410 if (constraints & NamedSchemaComponent::ExtensionConstraint)
411 result |= SchemaType::ExtensionConstraint;
412
413 return result;
414}
415
416bool XsdSchemaHelper::isValidlySubstitutable(const SchemaType::Ptr &type, const SchemaType::Ptr &otherType, const SchemaType::DerivationConstraints &constraints)
417{
418 // @see http://www.w3.org/TR/xmlschema11-1/#key-val-sub-type
419
420 // 1
421 if (type->isComplexType() && otherType->isComplexType()) {
422 SchemaType::DerivationConstraints keywords = constraints;
423 if (otherType->isDefinedBySchema())
424 keywords |= convertBlockingConstraints(XsdComplexType::Ptr(otherType)->prohibitedSubstitutions());
425
426 return isComplexDerivationOk(type, otherType, keywords);
427 }
428
429 // 2
430 if (type->isComplexType() && otherType->isSimpleType()) {
431 return isComplexDerivationOk(type, otherType, constraints);
432 }
433
434 // 3
435 if (type->isSimpleType() && otherType->isSimpleType()) {
436 return isSimpleDerivationOk(type, otherType, constraints);
437 }
438
439 return false;
440}
441
442bool XsdSchemaHelper::isSimpleDerivationOk(const SchemaType::Ptr &derivedType, const SchemaType::Ptr &baseType, const SchemaType::DerivationConstraints &constraints)
443{
444 // @see http://www.w3.org/TR/xmlschema11-1/#cos-st-derived-ok
445
446 // 1
447 if (derivedType == baseType)
448 return true;
449
450 // 2.1
451 if ((constraints & SchemaType::RestrictionConstraint) || derivedType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) {
452 return false;
453 }
454
455 // 2.2.1
456 if (derivedType->wxsSuperType() == baseType)
457 return true;
458
459 // 2.2.2
460 if (derivedType->wxsSuperType() != BuiltinTypes::xsAnyType) {
461 if (isSimpleDerivationOk(derivedType->wxsSuperType(), baseType, constraints))
462 return true;
463 }
464
465 // 2.2.3
466 if (derivedType->category() == SchemaType::SimpleTypeList || derivedType->category() == SchemaType::SimpleTypeUnion) {
467 if (baseType == BuiltinTypes::xsAnySimpleType)
468 return true;
469 }
470
471 // 2.2.4
472 if (baseType->category() == SchemaType::SimpleTypeUnion && baseType->isDefinedBySchema()) { // 2.2.4.1
473 const AnySimpleType::List memberTypes = XsdSimpleType::Ptr(baseType)->memberTypes();
474 for (int i = 0; i < memberTypes.count(); ++i) {
475 if (isSimpleDerivationOk(derivedType, memberTypes.at(i), constraints)) { // 2.2.4.2
476 if (XsdSimpleType::Ptr(baseType)->facets().isEmpty()) { // 2.2.4.3
477 return true;
478 }
479 }
480 }
481 }
482
483 return false;
484}
485
486bool XsdSchemaHelper::isComplexDerivationOk(const SchemaType::Ptr &derivedType, const SchemaType::Ptr &baseType, const SchemaType::DerivationConstraints &constraints)
487{
488 if (!derivedType)
489 return false;
490
491 // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-derived-ok
492
493 // 1
494 if (derivedType != baseType) {
495 if ((derivedType->derivationMethod() == SchemaType::DerivationRestriction) && (constraints & SchemaType::RestrictionConstraint))
496 return false;
497 if ((derivedType->derivationMethod() == SchemaType::DerivationExtension) && (constraints & SchemaType::ExtensionConstraint))
498 return false;
499 }
500
501 // 2.1
502 if (derivedType == baseType)
503 return true;
504
505 // 2.2
506 if (derivedType->wxsSuperType() == baseType)
507 return true;
508
509 // 2.3
510 bool isOk = true;
511 if (derivedType->wxsSuperType() == BuiltinTypes::xsAnyType) { // 2.3.1
512 isOk = false;
513 } else { // 2.3.2
514 if (!derivedType->wxsSuperType())
515 return false;
516
517 if (derivedType->wxsSuperType()->isComplexType()) { // 2.3.2.1
518 isOk = isComplexDerivationOk(derivedType->wxsSuperType(), baseType, constraints);
519 } else { // 2.3.2.2
520 isOk = isSimpleDerivationOk(derivedType->wxsSuperType(), baseType, constraints);
521 }
522 }
523 if (isOk)
524 return true;
525
526 return false;
527}
528
529bool XsdSchemaHelper::constructAndCompare(const DerivedString<TypeString>::Ptr &operand1,
530 const AtomicComparator::Operator op,
531 const DerivedString<TypeString>::Ptr &operand2,
532 const SchemaType::Ptr &type,
533 const ReportContext::Ptr &context,
534 const SourceLocationReflection *const sourceLocationReflection)
535{
536 Q_ASSERT_X(type->category() == SchemaType::SimpleTypeAtomic, Q_FUNC_INFO,
537 "We can only compare atomic values.");
538
539 // we can not cast a xs:String to a xs:QName, so lets go the safe way
540 if (type->name(context->namePool()) == BuiltinTypes::xsQName->name(context->namePool()))
541 return false;
542
543 const AtomicValue::Ptr value1 = ValueFactory::fromLexical(operand1->stringValue(), type, context, sourceLocationReflection);
544 if (value1->hasError())
545 return false;
546
547 const AtomicValue::Ptr value2 = ValueFactory::fromLexical(operand2->stringValue(), type, context, sourceLocationReflection);
548 if (value2->hasError())
549 return false;
550
551 return ComparisonFactory::compare(value1, op, value2, type, context, sourceLocationReflection);
552}
553
554bool XsdSchemaHelper::checkWildcardProcessContents(const XsdWildcard::Ptr &baseWildcard, const XsdWildcard::Ptr &derivedWildcard)
555{
556 if (baseWildcard->processContents() == XsdWildcard::Strict) {
557 if (derivedWildcard->processContents() == XsdWildcard::Lax || derivedWildcard->processContents() == XsdWildcard::Skip) {
558 return false;
559 }
560 } else if (baseWildcard->processContents() == XsdWildcard::Lax) {
561 if (derivedWildcard->processContents() == XsdWildcard::Skip)
562 return false;
563 }
564
565 return true;
566}
567
568bool XsdSchemaHelper::foundSubstitutionGroupTransitive(const XsdElement::Ptr &head, const XsdElement::Ptr &member, QSet<XsdElement::Ptr> &visitedElements)
569{
570 if (visitedElements.contains(member))
571 return false;
572 else
573 visitedElements.insert(member);
574
575 if (member->substitutionGroupAffiliations().isEmpty())
576 return false;
577
578 if (member->substitutionGroupAffiliations().contains(head)) {
579 return true;
580 } else {
581 const XsdElement::List affiliations = member->substitutionGroupAffiliations();
582 for (int i = 0; i < affiliations.count(); ++i) {
583 if (foundSubstitutionGroupTransitive(head, affiliations.at(i), visitedElements))
584 return true;
585 }
586
587 return false;
588 }
589}
590
591void XsdSchemaHelper::foundSubstitutionGroupTypeInheritance(const SchemaType::Ptr &headType, const SchemaType::Ptr &memberType,
592 QSet<SchemaType::DerivationMethod> &derivationSet, NamedSchemaComponent::BlockingConstraints &blockSet)
593{
594 if (!memberType)
595 return;
596
597 if (memberType == headType)
598 return;
599
600 derivationSet.insert(memberType->derivationMethod());
601
602 if (memberType->isComplexType()) {
603 const XsdComplexType::Ptr complexType(memberType);
604 blockSet |= complexType->prohibitedSubstitutions();
605 }
606
607 foundSubstitutionGroupTypeInheritance(headType, memberType->wxsSuperType(), derivationSet, blockSet);
608}
609
610bool XsdSchemaHelper::substitutionGroupOkTransitive(const XsdElement::Ptr &head, const XsdElement::Ptr &member, const NamePool::Ptr &namePool)
611{
612 // @see http://www.w3.org/TR/xmlschema11-1/#cos-equiv-derived-ok-rec
613
614 // 1
615 if ((member->name(namePool) == head->name(namePool)) && (member->type() == head->type()))
616 return true;
617
618 // 2.1
619 if (head->disallowedSubstitutions() & NamedSchemaComponent::SubstitutionConstraint)
620 return false;
621
622 // 2.2
623 {
624 QSet<XsdElement::Ptr> visitedElements;
625 if (!foundSubstitutionGroupTransitive(head, member, visitedElements))
626 return false;
627 }
628
629 // 2.3
630 {
631 QSet<SchemaType::DerivationMethod> derivationSet;
632 NamedSchemaComponent::BlockingConstraints blockSet;
633
634 foundSubstitutionGroupTypeInheritance(head->type(), member->type(), derivationSet, blockSet);
635
636 NamedSchemaComponent::BlockingConstraints checkSet(blockSet);
637 checkSet |= head->disallowedSubstitutions();
638 if (head->type()->isComplexType()) {
639 const XsdComplexType::Ptr complexType(head->type());
640 checkSet |= complexType->prohibitedSubstitutions();
641 }
642
643 if ((checkSet & NamedSchemaComponent::RestrictionConstraint) && derivationSet.contains(SchemaType::DerivationRestriction))
644 return false;
645 if ((checkSet & NamedSchemaComponent::ExtensionConstraint) && derivationSet.contains(SchemaType::DerivationExtension))
646 return false;
647 if (checkSet & NamedSchemaComponent::SubstitutionConstraint)
648 return false;
649 }
650
651 return true;
652}
653
654bool XsdSchemaHelper::isValidAttributeGroupRestriction(const XsdAttributeGroup::Ptr &derivedAttributeGroup, const XsdAttributeGroup::Ptr &attributeGroup, const XsdSchemaContext::Ptr &context, QString &errorMsg)
655{
656 // @see http://www.w3.org/TR/xmlschema-1/#derivation-ok-restriction
657
658 const XsdAttributeUse::List derivedAttributeUses = derivedAttributeGroup->attributeUses();
659 const XsdAttributeUse::List baseAttributeUses = attributeGroup->attributeUses();
660
661 return isValidAttributeUsesRestriction(derivedAttributeUses, baseAttributeUses,
662 derivedAttributeGroup->wildcard(), attributeGroup->wildcard(), context, errorMsg);
663}
664
665bool XsdSchemaHelper::isValidAttributeUsesRestriction(const XsdAttributeUse::List &derivedAttributeUses, const XsdAttributeUse::List &baseAttributeUses,
666 const XsdWildcard::Ptr &derivedWildcard, const XsdWildcard::Ptr &wildcard, const XsdSchemaContext::Ptr &context, QString &errorMsg)
667{
668 const NamePool::Ptr namePool(context->namePool());
669
670 QHash<QXmlName, XsdAttributeUse::Ptr> baseAttributeUsesLookup;
671 for (int i = 0; i < baseAttributeUses.count(); ++i)
672 baseAttributeUsesLookup.insert(baseAttributeUses.at(i)->attribute()->name(namePool), baseAttributeUses.at(i));
673
674 QHash<QXmlName, XsdAttributeUse::Ptr> derivedAttributeUsesLookup;
675 for (int i = 0; i < derivedAttributeUses.count(); ++i)
676 derivedAttributeUsesLookup.insert(derivedAttributeUses.at(i)->attribute()->name(namePool), derivedAttributeUses.at(i));
677
678 // 2
679 for (int i = 0; i < derivedAttributeUses.count(); ++i) {
680 const XsdAttributeUse::Ptr derivedAttributeUse = derivedAttributeUses.at(i);
681
682 // prohibited attributes are no real attributes, so skip them in that test here
683 if (derivedAttributeUse->useType() == XsdAttributeUse::ProhibitedUse)
684 continue;
685
686 if (baseAttributeUsesLookup.contains(derivedAttributeUse->attribute()->name(namePool))) {
687 const XsdAttributeUse::Ptr baseAttributeUse(baseAttributeUsesLookup.value(derivedAttributeUse->attribute()->name(namePool)));
688
689 // 2.1.1
690 if (baseAttributeUse->isRequired() == true && derivedAttributeUse->isRequired() == false) {
691 errorMsg = QtXmlPatterns::tr("Base attribute %1 is required but derived attribute is not.").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool)));
692 return false;
693 }
694
695 // 2.1.2
696 if (!isSimpleDerivationOk(derivedAttributeUse->attribute()->type(), baseAttributeUse->attribute()->type(), SchemaType::DerivationConstraints())) {
697 errorMsg = QtXmlPatterns::tr("Type of derived attribute %1 cannot be validly derived from type of base attribute.").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool)));
698 return false;
699 }
700
701 // 2.1.3
702 XsdAttributeUse::ValueConstraint::Ptr derivedConstraint;
703 if (derivedAttributeUse->valueConstraint())
704 derivedConstraint = derivedAttributeUse->valueConstraint();
705 else if (derivedAttributeUse->attribute()->valueConstraint())
706 derivedConstraint = XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(derivedAttributeUse->attribute()->valueConstraint());
707
708 XsdAttributeUse::ValueConstraint::Ptr baseConstraint;
709 if (baseAttributeUse->valueConstraint())
710 baseConstraint = baseAttributeUse->valueConstraint();
711 else if (baseAttributeUse->attribute()->valueConstraint())
712 baseConstraint = XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(baseAttributeUse->attribute()->valueConstraint());
713
714 bool ok = false;
715 if (!baseConstraint || baseConstraint->variety() == XsdAttributeUse::ValueConstraint::Default)
716 ok = true;
717
718 if (derivedConstraint && baseConstraint) {
719 const XsdTypeChecker checker(context, QVector<QXmlName>(), QSourceLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1));
720 if (derivedConstraint->variety() == XsdAttributeUse::ValueConstraint::Fixed && checker.valuesAreEqual(derivedConstraint->value(), baseConstraint->value(), baseAttributeUse->attribute()->type()))
721 ok = true;
722 }
723
724 if (!ok) {
725 errorMsg = QtXmlPatterns::tr("Value constraint of derived attribute %1 does not match value constraint of base attribute.").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool)));
726 return false;
727 }
728 } else {
729 if (!wildcard) {
730 errorMsg = QtXmlPatterns::tr("Derived attribute %1 does not exist in the base definition.").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool)));
731 return false;
732 }
733
734 QXmlName name = derivedAttributeUse->attribute()->name(namePool);
735
736 // wildcards using XsdWildcard::absentNamespace, so we have to fix that here
737 if (name.namespaceURI() == StandardNamespaces::empty)
738 name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace()));
739
740 if (!wildcardAllowsExpandedName(name, wildcard, namePool)) {
741 errorMsg = QtXmlPatterns::tr("Derived attribute %1 does not match the wildcard in the base definition.").arg(formatAttribute(derivedAttributeUse->attribute()->displayName(namePool)));
742 return false;
743 }
744 }
745 }
746
747 // 3
748 for (int i = 0; i < baseAttributeUses.count(); ++i) {
749 const XsdAttributeUse::Ptr baseAttributeUse = baseAttributeUses.at(i);
750
751 if (baseAttributeUse->isRequired()) {
752 if (derivedAttributeUsesLookup.contains(baseAttributeUse->attribute()->name(namePool))) {
753 if (!derivedAttributeUsesLookup.value(baseAttributeUse->attribute()->name(namePool))->isRequired()) {
754 errorMsg = QtXmlPatterns::tr("Base attribute %1 is required but derived attribute is not.").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool)));
755 return false;
756 }
757 } else {
758 errorMsg = QtXmlPatterns::tr("Base attribute %1 is required but missing in derived definition.").arg(formatAttribute(baseAttributeUse->attribute()->displayName(namePool)));
759 return false;
760 }
761 }
762 }
763
764 // 4
765 if (derivedWildcard) {
766 if (!wildcard) {
767 errorMsg = QtXmlPatterns::tr("Derived definition contains an %1 element that does not exists in the base definition").arg(formatElement("anyAttribute."));
768 return false;
769 }
770
771 if (!isWildcardSubset(derivedWildcard, wildcard)) {
772 errorMsg = QtXmlPatterns::tr("Derived wildcard is not a subset of the base wildcard.");
773 return false;
774 }
775
776 if (!checkWildcardProcessContents(wildcard, derivedWildcard)) {
777 errorMsg = QtXmlPatterns::tr("%1 of derived wildcard is not a valid restriction of %2 of base wildcard").arg(formatKeyword("processContents")).arg(formatKeyword("processContents."));
778 return false;
779 }
780 }
781
782 return true;
783}
784
785bool XsdSchemaHelper::isValidAttributeUsesExtension(const XsdAttributeUse::List &derivedAttributeUses, const XsdAttributeUse::List &attributeUses,
786 const XsdWildcard::Ptr &derivedWildcard, const XsdWildcard::Ptr &wildcard, const XsdSchemaContext::Ptr &context, QString &errorMsg)
787{
788 // @see http://www.w3.org/TR/xmlschema11-1/#cos-ct-extends
789
790 const NamePool::Ptr namePool(context->namePool());
791
792 // 1.2
793 QHash<QXmlName, XsdAttribute::Ptr> lookupHash;
794 for (int i = 0; i < derivedAttributeUses.count(); ++i)
795 lookupHash.insert(derivedAttributeUses.at(i)->attribute()->name(namePool), derivedAttributeUses.at(i)->attribute());
796
797 for (int i = 0; i < attributeUses.count(); ++i) {
798 const QXmlName attributeName = attributeUses.at(i)->attribute()->name(namePool);
799 if (!lookupHash.contains(attributeName)) {
800 errorMsg = QtXmlPatterns::tr("Attribute %1 from base type is missing in derived type.").arg(formatKeyword(namePool->displayName(attributeName)));
801 return false;
802 }
803
804 if (lookupHash.value(attributeName)->type() != attributeUses.at(i)->attribute()->type()) {
805 errorMsg = QtXmlPatterns::tr("Type of derived attribute %1 differs from type of base attribute.").arg(formatKeyword(namePool->displayName(attributeName)));
806 return false;
807 }
808 }
809
810 // 1.3
811 if (wildcard) {
812 if (!derivedWildcard) {
813 errorMsg = QtXmlPatterns::tr("Base definition contains an %1 element that is missing in the derived definition").arg(formatElement("anyAttribute."));
814 return false;
815 }
816 }
817
818 return true;
819}
820
821QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.