1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtXmlPatterns module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qxsdschemaresolver_p.h" |
41 | |
42 | #include "qderivedinteger_p.h" |
43 | #include "qderivedstring_p.h" |
44 | #include "qqnamevalue_p.h" |
45 | #include "qxsdattributereference_p.h" |
46 | #include "qxsdparticlechecker_p.h" |
47 | #include "qxsdreference_p.h" |
48 | #include "qxsdschemacontext_p.h" |
49 | #include "qxsdschemahelper_p.h" |
50 | #include "qxsdschemaparsercontext_p.h" |
51 | #include "qxsdschematypesfactory_p.h" |
52 | |
53 | QT_BEGIN_NAMESPACE |
54 | |
55 | using namespace QPatternist; |
56 | |
57 | XsdSchemaResolver::XsdSchemaResolver(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext) |
58 | : m_context(context) |
59 | , m_checker(parserContext->checker()) |
60 | , m_namePool(parserContext->namePool()) |
61 | , m_schema(parserContext->schema()) |
62 | { |
63 | m_keyReferences.reserve(asize: 20); |
64 | m_simpleRestrictionBases.reserve(asize: 20); |
65 | m_simpleListTypes.reserve(asize: 20); |
66 | m_simpleUnionTypes.reserve(asize: 20); |
67 | m_elementTypes.reserve(asize: 20); |
68 | m_complexBaseTypes.reserve(asize: 20); |
69 | m_attributeTypes.reserve(asize: 20); |
70 | m_alternativeTypes.reserve(asize: 20); |
71 | m_alternativeTypeElements.reserve(asize: 20); |
72 | m_substitutionGroupAffiliations.reserve(asize: 20); |
73 | |
74 | m_predefinedSchemaTypes = m_context->schemaTypeFactory()->types().values(); |
75 | } |
76 | |
77 | XsdSchemaResolver::~XsdSchemaResolver() |
78 | { |
79 | } |
80 | |
81 | void XsdSchemaResolver::resolve() |
82 | { |
83 | m_checker->addComponentLocationHash(hash: m_componentLocationHash); |
84 | |
85 | // resolve the base types for all types |
86 | resolveSimpleRestrictionBaseTypes(); |
87 | resolveComplexBaseTypes(); |
88 | |
89 | // do the basic checks which depend on having a base type available |
90 | m_checker->basicCheck(); |
91 | |
92 | // resolve further types that only map a type name to a type object |
93 | resolveSimpleListType(); |
94 | resolveSimpleUnionTypes(); |
95 | resolveElementTypes(); |
96 | resolveAttributeTypes(); |
97 | resolveAlternativeTypes(); |
98 | |
99 | // resolve objects that do not need information about inheritance |
100 | resolveKeyReferences(); |
101 | resolveSubstitutionGroupAffiliations(); |
102 | |
103 | // resolve objects that do need information about inheritance |
104 | resolveSimpleRestrictions(); |
105 | resolveSimpleContentComplexTypes(); |
106 | |
107 | // resolve objects which replace place holders |
108 | resolveTermReferences(); |
109 | resolveAttributeTermReferences(); |
110 | |
111 | // resolve additional objects that do need information about inheritance |
112 | resolveAttributeInheritance(); |
113 | resolveComplexContentComplexTypes(); |
114 | resolveSubstitutionGroups(); |
115 | |
116 | resolveEnumerationFacetValues(); |
117 | |
118 | checkRedefinedGroups(); |
119 | checkRedefinedAttributeGroups(); |
120 | |
121 | // check the constraining facets before we resolve them |
122 | m_checker->checkConstrainingFacets(); |
123 | |
124 | // add it again, as we may have added new components in the meantime |
125 | m_checker->addComponentLocationHash(hash: m_componentLocationHash); |
126 | |
127 | m_checker->check(); |
128 | } |
129 | |
130 | void XsdSchemaResolver::addKeyReference(const XsdElement::Ptr &element, const XsdIdentityConstraint::Ptr &keyRef, const QXmlName &reference, const QSourceLocation &location) |
131 | { |
132 | KeyReference item; |
133 | item.element = element; |
134 | item.keyRef = keyRef; |
135 | item.reference = reference; |
136 | item.location = location; |
137 | |
138 | m_keyReferences.append(t: item); |
139 | } |
140 | |
141 | void XsdSchemaResolver::addSimpleRestrictionBase(const XsdSimpleType::Ptr &simpleType, const QXmlName &baseName, const QSourceLocation &location) |
142 | { |
143 | SimpleRestrictionBase item; |
144 | item.simpleType = simpleType; |
145 | item.baseName = baseName; |
146 | item.location = location; |
147 | |
148 | m_simpleRestrictionBases.append(t: item); |
149 | } |
150 | |
151 | void XsdSchemaResolver::removeSimpleRestrictionBase(const XsdSimpleType::Ptr &type) |
152 | { |
153 | for (int i = 0; i < m_simpleRestrictionBases.count(); ++i) { |
154 | if (m_simpleRestrictionBases.at(i).simpleType == type) { |
155 | m_simpleRestrictionBases.remove(i); |
156 | break; |
157 | } |
158 | } |
159 | } |
160 | |
161 | void XsdSchemaResolver::addSimpleListType(const XsdSimpleType::Ptr &simpleType, const QXmlName &typeName, const QSourceLocation &location) |
162 | { |
163 | SimpleListType item; |
164 | item.simpleType = simpleType; |
165 | item.typeName = typeName; |
166 | item.location = location; |
167 | |
168 | m_simpleListTypes.append(t: item); |
169 | } |
170 | |
171 | void XsdSchemaResolver::addSimpleUnionTypes(const XsdSimpleType::Ptr &simpleType, const QList<QXmlName> &typeNames, const QSourceLocation &location) |
172 | { |
173 | SimpleUnionType item; |
174 | item.simpleType = simpleType; |
175 | item.typeNames = typeNames; |
176 | item.location = location; |
177 | |
178 | m_simpleUnionTypes.append(t: item); |
179 | } |
180 | |
181 | void XsdSchemaResolver::addElementType(const XsdElement::Ptr &element, const QXmlName &typeName, const QSourceLocation &location) |
182 | { |
183 | ElementType item; |
184 | item.element = element; |
185 | item.typeName = typeName; |
186 | item.location = location; |
187 | |
188 | m_elementTypes.append(t: item); |
189 | } |
190 | |
191 | void XsdSchemaResolver::addComplexBaseType(const XsdComplexType::Ptr &complexType, const QXmlName &baseName, const QSourceLocation &location, const XsdFacet::Hash &facets) |
192 | { |
193 | ComplexBaseType item; |
194 | item.complexType = complexType; |
195 | item.baseName = baseName; |
196 | item.location = location; |
197 | item.facets = facets; |
198 | |
199 | m_complexBaseTypes.append(t: item); |
200 | } |
201 | |
202 | void XsdSchemaResolver::removeComplexBaseType(const XsdComplexType::Ptr &type) |
203 | { |
204 | for (int i = 0; i < m_complexBaseTypes.count(); ++i) { |
205 | if (m_complexBaseTypes.at(i).complexType == type) { |
206 | m_complexBaseTypes.remove(i); |
207 | break; |
208 | } |
209 | } |
210 | } |
211 | |
212 | void XsdSchemaResolver::addComplexContentType(const XsdComplexType::Ptr &complexType, const XsdParticle::Ptr &content, bool mixed) |
213 | { |
214 | ComplexContentType item; |
215 | item.complexType = complexType; |
216 | item.explicitContent = content; |
217 | item.effectiveMixed = mixed; |
218 | m_complexContentTypes.append(t: item); |
219 | } |
220 | |
221 | void XsdSchemaResolver::addAttributeType(const XsdAttribute::Ptr &attribute, const QXmlName &typeName, const QSourceLocation &location) |
222 | { |
223 | AttributeType item; |
224 | item.attribute = attribute; |
225 | item.typeName = typeName; |
226 | item.location = location; |
227 | |
228 | m_attributeTypes.append(t: item); |
229 | } |
230 | |
231 | void XsdSchemaResolver::addAlternativeType(const XsdAlternative::Ptr &alternative, const QXmlName &typeName, const QSourceLocation &location) |
232 | { |
233 | AlternativeType item; |
234 | item.alternative = alternative; |
235 | item.typeName = typeName; |
236 | item.location = location; |
237 | |
238 | m_alternativeTypes.append(t: item); |
239 | } |
240 | |
241 | void XsdSchemaResolver::addAlternativeType(const XsdAlternative::Ptr &alternative, const XsdElement::Ptr &element) |
242 | { |
243 | AlternativeTypeElement item; |
244 | item.alternative = alternative; |
245 | item.element = element; |
246 | |
247 | m_alternativeTypeElements.append(t: item); |
248 | } |
249 | |
250 | void XsdSchemaResolver::addSubstitutionGroupAffiliation(const XsdElement::Ptr &element, const QList<QXmlName> &elementNames, const QSourceLocation &location) |
251 | { |
252 | SubstitutionGroupAffiliation item; |
253 | item.element = element; |
254 | item.elementNames = elementNames; |
255 | item.location = location; |
256 | |
257 | m_substitutionGroupAffiliations.append(t: item); |
258 | } |
259 | |
260 | void XsdSchemaResolver::addSubstitutionGroupType(const XsdElement::Ptr &element) |
261 | { |
262 | m_substitutionGroupTypes.append(t: element); |
263 | } |
264 | |
265 | void XsdSchemaResolver::addComponentLocationHash(const ComponentLocationHash &hash) |
266 | { |
267 | m_componentLocationHash.insert(hash); |
268 | } |
269 | |
270 | void XsdSchemaResolver::addEnumerationFacetValue(const AtomicValue::Ptr &facetValue, const NamespaceSupport &namespaceSupport) |
271 | { |
272 | m_enumerationFacetValues.insert(akey: facetValue, avalue: namespaceSupport); |
273 | } |
274 | |
275 | void XsdSchemaResolver::addRedefinedGroups(const XsdModelGroup::Ptr &redefinedGroup, const XsdModelGroup::Ptr &group) |
276 | { |
277 | RedefinedGroups item; |
278 | item.redefinedGroup = redefinedGroup; |
279 | item.group = group; |
280 | |
281 | m_redefinedGroups.append(t: item); |
282 | } |
283 | |
284 | void XsdSchemaResolver::addRedefinedAttributeGroups(const XsdAttributeGroup::Ptr &redefinedGroup, const XsdAttributeGroup::Ptr &group) |
285 | { |
286 | RedefinedAttributeGroups item; |
287 | item.redefinedGroup = redefinedGroup; |
288 | item.group = group; |
289 | |
290 | m_redefinedAttributeGroups.append(t: item); |
291 | } |
292 | |
293 | void XsdSchemaResolver::addAllGroupCheck(const XsdReference::Ptr &reference) |
294 | { |
295 | m_allGroups.insert(value: reference); |
296 | } |
297 | |
298 | void XsdSchemaResolver::copyDataTo(const XsdSchemaResolver::Ptr &other) const |
299 | { |
300 | other->m_keyReferences << m_keyReferences; |
301 | other->m_simpleRestrictionBases << m_simpleRestrictionBases; |
302 | other->m_simpleListTypes << m_simpleListTypes; |
303 | other->m_simpleUnionTypes << m_simpleUnionTypes; |
304 | other->m_elementTypes << m_elementTypes; |
305 | other->m_complexBaseTypes << m_complexBaseTypes; |
306 | other->m_complexContentTypes << m_complexContentTypes; |
307 | other->m_attributeTypes << m_attributeTypes; |
308 | other->m_alternativeTypes << m_alternativeTypes; |
309 | other->m_alternativeTypeElements << m_alternativeTypeElements; |
310 | other->m_substitutionGroupAffiliations << m_substitutionGroupAffiliations; |
311 | other->m_substitutionGroupTypes << m_substitutionGroupTypes; |
312 | } |
313 | |
314 | QXmlName XsdSchemaResolver::baseTypeNameOfType(const SchemaType::Ptr &type) const |
315 | { |
316 | for (int i = 0; i < m_simpleRestrictionBases.count(); ++i) { |
317 | if (m_simpleRestrictionBases.at(i).simpleType == type) |
318 | return m_simpleRestrictionBases.at(i).baseName; |
319 | } |
320 | |
321 | for (int i = 0; i < m_complexBaseTypes.count(); ++i) { |
322 | if (m_complexBaseTypes.at(i).complexType == type) |
323 | return m_complexBaseTypes.at(i).baseName; |
324 | } |
325 | |
326 | return QXmlName(); |
327 | } |
328 | |
329 | QXmlName XsdSchemaResolver::typeNameOfAttribute(const XsdAttribute::Ptr &attribute) const |
330 | { |
331 | for (int i = 0; i < m_attributeTypes.count(); ++i) { |
332 | if (m_attributeTypes.at(i).attribute == attribute) |
333 | return m_attributeTypes.at(i).typeName; |
334 | } |
335 | |
336 | return QXmlName(); |
337 | } |
338 | |
339 | void XsdSchemaResolver::setDefaultOpenContent(const XsdComplexType::OpenContent::Ptr &openContent, bool appliesToEmpty) |
340 | { |
341 | m_defaultOpenContent = openContent; |
342 | m_defaultOpenContentAppliesToEmpty = appliesToEmpty; |
343 | } |
344 | |
345 | void XsdSchemaResolver::resolveKeyReferences() |
346 | { |
347 | for (int i = 0; i < m_keyReferences.count(); ++i) { |
348 | const KeyReference ref = m_keyReferences.at(i); |
349 | |
350 | const XsdIdentityConstraint::Ptr constraint = m_schema->identityConstraint(name: ref.reference); |
351 | if (!constraint) { |
352 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 references unknown %2 or %3 element %4." ) |
353 | .arg(a: formatKeyword(keyword: ref.keyRef->displayName(namePool: m_namePool))) |
354 | .arg(a: formatElement(element: "key" )) |
355 | .arg(a: formatElement(element: "unique" )) |
356 | .arg(a: formatKeyword(np: m_namePool, name: ref.reference)), |
357 | errorCode: XsdSchemaContext::XSDError, sourceLocation: ref.location); |
358 | return; |
359 | } |
360 | |
361 | if (constraint->category() != XsdIdentityConstraint::Key && constraint->category() != XsdIdentityConstraint::Unique) { // only key and unique can be referenced |
362 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 references identity constraint %2 that is no %3 or %4 element." ) |
363 | .arg(a: formatKeyword(keyword: ref.keyRef->displayName(namePool: m_namePool))) |
364 | .arg(a: formatKeyword(np: m_namePool, name: ref.reference)) |
365 | .arg(a: formatElement(element: "key" )) |
366 | .arg(a: formatElement(element: "unique" )), |
367 | errorCode: XsdSchemaContext::XSDError, sourceLocation: ref.location); |
368 | return; |
369 | } |
370 | |
371 | if (constraint->fields().count() != ref.keyRef->fields().count()) { |
372 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 has a different number of fields from the identity constraint %2 that it references." ) |
373 | .arg(a: formatKeyword(keyword: ref.keyRef->displayName(namePool: m_namePool))) |
374 | .arg(a: formatKeyword(np: m_namePool, name: ref.reference)), |
375 | errorCode: XsdSchemaContext::XSDError, sourceLocation: ref.location); |
376 | return; |
377 | } |
378 | |
379 | ref.keyRef->setReferencedKey(constraint); |
380 | } |
381 | } |
382 | |
383 | void XsdSchemaResolver::resolveSimpleRestrictionBaseTypes() |
384 | { |
385 | // iterate over all simple types that are derived by restriction |
386 | for (int i = 0; i < m_simpleRestrictionBases.count(); ++i) { |
387 | const SimpleRestrictionBase item = m_simpleRestrictionBases.at(i); |
388 | |
389 | // find the base type |
390 | SchemaType::Ptr type = m_schema->type(name: item.baseName); |
391 | if (!type) { |
392 | // maybe it's a basic type... |
393 | type = m_context->schemaTypeFactory()->createSchemaType(name: item.baseName); |
394 | if (!type) { |
395 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Base type %1 of %2 element cannot be resolved." ) |
396 | .arg(a: formatType(np: m_namePool, name: item.baseName)) |
397 | .arg(a: formatElement(element: "restriction" )), |
398 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
399 | return; |
400 | } |
401 | } |
402 | |
403 | item.simpleType->setWxsSuperType(type); |
404 | } |
405 | } |
406 | |
407 | void XsdSchemaResolver::resolveSimpleRestrictions() |
408 | { |
409 | XsdSimpleType::List simpleTypes; |
410 | |
411 | // first collect the global simple types |
412 | const SchemaType::List types = m_schema->types(); |
413 | for (int i = 0; i < types.count(); ++i) { |
414 | if (types.at(i)->isSimpleType() && (types.at(i)->derivationMethod() == SchemaType::DerivationRestriction)) |
415 | simpleTypes.append(t: types.at(i)); |
416 | } |
417 | |
418 | // then collect all anonymous simple types |
419 | const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); |
420 | for (int i = 0; i < anonymousTypes.count(); ++i) { |
421 | if (anonymousTypes.at(i)->isSimpleType() && (anonymousTypes.at(i)->derivationMethod() == SchemaType::DerivationRestriction)) |
422 | simpleTypes.append(t: anonymousTypes.at(i)); |
423 | } |
424 | |
425 | QSet<XsdSimpleType::Ptr> visitedTypes; |
426 | for (int i = 0; i < simpleTypes.count(); ++i) { |
427 | resolveSimpleRestrictions(simpleType: simpleTypes.at(i), visitedTypes); |
428 | } |
429 | } |
430 | |
431 | void XsdSchemaResolver::resolveSimpleRestrictions(const XsdSimpleType::Ptr &simpleType, QSet<XsdSimpleType::Ptr> &visitedTypes) |
432 | { |
433 | if (visitedTypes.contains(value: simpleType)) |
434 | return; |
435 | else |
436 | visitedTypes.insert(value: simpleType); |
437 | |
438 | if (simpleType->derivationMethod() != XsdSimpleType::DerivationRestriction) |
439 | return; |
440 | |
441 | // as xs:NMTOKENS, xs:ENTITIES and xs:IDREFS are provided by our XsdSchemaTypesFactory, they are |
442 | // setup correctly already and shouldn't be handled here |
443 | if (m_predefinedSchemaTypes.contains(t: simpleType)) |
444 | return; |
445 | |
446 | const SchemaType::Ptr baseType = simpleType->wxsSuperType(); |
447 | Q_ASSERT(baseType); |
448 | |
449 | if (baseType->isDefinedBySchema()) |
450 | resolveSimpleRestrictions(simpleType: XsdSimpleType::Ptr(baseType), visitedTypes); |
451 | |
452 | simpleType->setCategory(baseType->category()); |
453 | |
454 | if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) { |
455 | QSet<AnySimpleType::Ptr> visitedPrimitiveTypes; |
456 | const AnySimpleType::Ptr primitiveType = findPrimitiveType(type: baseType, visitedTypes&: visitedPrimitiveTypes); |
457 | simpleType->setPrimitiveType(primitiveType); |
458 | } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) { |
459 | const XsdSimpleType::Ptr simpleBaseType = baseType; |
460 | simpleType->setItemType(simpleBaseType->itemType()); |
461 | } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) { |
462 | const XsdSimpleType::Ptr simpleBaseType = baseType; |
463 | simpleType->setMemberTypes(simpleBaseType->memberTypes()); |
464 | } |
465 | } |
466 | |
467 | void XsdSchemaResolver::resolveSimpleListType() |
468 | { |
469 | // iterate over all simple types where the item type shall be resolved |
470 | for (int i = 0; i < m_simpleListTypes.count(); ++i) { |
471 | const SimpleListType item = m_simpleListTypes.at(i); |
472 | |
473 | // try to resolve the name |
474 | SchemaType::Ptr type = m_schema->type(name: item.typeName); |
475 | if (!type) { |
476 | // maybe it's a basic type... |
477 | type = m_context->schemaTypeFactory()->createSchemaType(name: item.typeName); |
478 | if (!type) { |
479 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Item type %1 of %2 element cannot be resolved." ) |
480 | .arg(a: formatType(np: m_namePool, name: item.typeName)) |
481 | .arg(a: formatElement(element: "list" )), |
482 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
483 | return; |
484 | } |
485 | } |
486 | |
487 | item.simpleType->setItemType(type); |
488 | } |
489 | } |
490 | |
491 | void XsdSchemaResolver::resolveSimpleUnionTypes() |
492 | { |
493 | // iterate over all simple types where the union member types shall be resolved |
494 | for (int i = 0; i < m_simpleUnionTypes.count(); ++i) { |
495 | const SimpleUnionType item = m_simpleUnionTypes.at(i); |
496 | |
497 | AnySimpleType::List memberTypes; |
498 | |
499 | // iterate over all union member type names |
500 | const QList<QXmlName> typeNames = item.typeNames; |
501 | for (int j = 0; j < typeNames.count(); ++j) { |
502 | const QXmlName typeName = typeNames.at(i: j); |
503 | |
504 | // try to resolve the name |
505 | SchemaType::Ptr type = m_schema->type(name: typeName); |
506 | if (!type) { |
507 | // maybe it's a basic type... |
508 | type = m_context->schemaTypeFactory()->createSchemaType(name: typeName); |
509 | if (!type) { |
510 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Member type %1 of %2 element cannot be resolved." ) |
511 | .arg(a: formatType(np: m_namePool, name: typeName)) |
512 | .arg(a: formatElement(element: "union" )), |
513 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
514 | return; |
515 | } |
516 | } |
517 | |
518 | memberTypes.append(t: type); |
519 | } |
520 | |
521 | // append the types that have been defined as <simpleType> children |
522 | memberTypes << item.simpleType->memberTypes(); |
523 | |
524 | item.simpleType->setMemberTypes(memberTypes); |
525 | } |
526 | } |
527 | |
528 | void XsdSchemaResolver::resolveElementTypes() |
529 | { |
530 | for (int i = 0; i < m_elementTypes.count(); ++i) { |
531 | const ElementType item = m_elementTypes.at(i); |
532 | |
533 | SchemaType::Ptr type = m_schema->type(name: item.typeName); |
534 | if (!type) { |
535 | // maybe it's a basic type... |
536 | type = m_context->schemaTypeFactory()->createSchemaType(name: item.typeName); |
537 | if (!type) { |
538 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Type %1 of %2 element cannot be resolved." ) |
539 | .arg(a: formatType(np: m_namePool, name: item.typeName)) |
540 | .arg(a: formatElement(element: "element" )), |
541 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
542 | return; |
543 | } |
544 | } |
545 | |
546 | item.element->setType(type); |
547 | } |
548 | } |
549 | |
550 | void XsdSchemaResolver::resolveComplexBaseTypes() |
551 | { |
552 | for (int i = 0; i < m_complexBaseTypes.count(); ++i) { |
553 | const ComplexBaseType item = m_complexBaseTypes.at(i); |
554 | |
555 | SchemaType::Ptr type = m_schema->type(name: item.baseName); |
556 | if (!type) { |
557 | // maybe it's a basic type... |
558 | type = m_context->schemaTypeFactory()->createSchemaType(name: item.baseName); |
559 | if (!type) { |
560 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Base type %1 of complex type cannot be resolved." ).arg(a: formatType(np: m_namePool, name: item.baseName)), errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
561 | return; |
562 | } |
563 | } |
564 | |
565 | if (item.complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) { |
566 | if (type->isComplexType() && type->isDefinedBySchema()) { |
567 | const XsdComplexType::Ptr baseType = type; |
568 | if (baseType->contentType()->variety() != XsdComplexType::ContentType::Simple) { |
569 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 cannot have complex base type that has a %2." ) |
570 | .arg(a: formatElement(element: "simpleContent" )) |
571 | .arg(a: formatElement(element: "complexContent" )), |
572 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
573 | return; |
574 | } |
575 | } |
576 | } |
577 | |
578 | item.complexType->setWxsSuperType(type); |
579 | } |
580 | } |
581 | |
582 | void XsdSchemaResolver::resolveSimpleContentComplexTypes() |
583 | { |
584 | XsdComplexType::List complexTypes; |
585 | |
586 | // first collect the global complex types |
587 | const SchemaType::List types = m_schema->types(); |
588 | for (int i = 0; i < types.count(); ++i) { |
589 | if (types.at(i)->isComplexType() && types.at(i)->isDefinedBySchema()) |
590 | complexTypes.append(t: types.at(i)); |
591 | } |
592 | |
593 | // then collect all anonymous simple types |
594 | const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); |
595 | for (int i = 0; i < anonymousTypes.count(); ++i) { |
596 | if (anonymousTypes.at(i)->isComplexType() && anonymousTypes.at(i)->isDefinedBySchema()) |
597 | complexTypes.append(t: anonymousTypes.at(i)); |
598 | } |
599 | |
600 | QSet<XsdComplexType::Ptr> visitedTypes; |
601 | for (int i = 0; i < complexTypes.count(); ++i) { |
602 | if (XsdComplexType::Ptr(complexTypes.at(i))->contentType()->variety() == XsdComplexType::ContentType::Simple) |
603 | resolveSimpleContentComplexTypes(complexType: complexTypes.at(i), visitedTypes); |
604 | } |
605 | } |
606 | |
607 | void XsdSchemaResolver::resolveSimpleContentComplexTypes(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes) |
608 | { |
609 | if (visitedTypes.contains(value: complexType)) |
610 | return; |
611 | else |
612 | visitedTypes.insert(value: complexType); |
613 | |
614 | const SchemaType::Ptr baseType = complexType->wxsSuperType(); |
615 | |
616 | // at this point simple types have been resolved already, so we care about |
617 | // complex types here only |
618 | |
619 | // http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.ctsc |
620 | // 1 |
621 | if (baseType->isComplexType() && baseType->isDefinedBySchema()) { |
622 | const XsdComplexType::Ptr complexBaseType = baseType; |
623 | |
624 | resolveSimpleContentComplexTypes(complexType: complexBaseType, visitedTypes); |
625 | |
626 | if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Simple) { |
627 | if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { |
628 | if (complexType->contentType()->simpleType()) { |
629 | // 1.1 contains the content of the <simpleType> already |
630 | } else { |
631 | // 1.2 |
632 | const XsdSimpleType::Ptr anonType(new XsdSimpleType()); |
633 | XsdSimpleType::TypeCategory baseCategory = complexBaseType->contentType()->simpleType()->category(); |
634 | anonType->setCategory(baseCategory); |
635 | |
636 | if (baseCategory == XsdSimpleType::SimpleTypeList) { |
637 | const XsdSimpleType::Ptr baseSimpleType = complexBaseType->contentType()->simpleType(); |
638 | anonType->setItemType(baseSimpleType->itemType()); |
639 | } |
640 | |
641 | anonType->setDerivationMethod(XsdSimpleType::DerivationRestriction); |
642 | anonType->setWxsSuperType(complexBaseType->contentType()->simpleType()); |
643 | anonType->setFacets(complexTypeFacets(complexType)); |
644 | |
645 | QSet<AnySimpleType::Ptr> visitedPrimitiveTypes; |
646 | const AnySimpleType::Ptr primitiveType = findPrimitiveType(type: anonType->wxsSuperType(), visitedTypes&: visitedPrimitiveTypes); |
647 | anonType->setPrimitiveType(primitiveType); |
648 | |
649 | complexType->contentType()->setSimpleType(anonType); |
650 | |
651 | m_schema->addAnonymousType(type: anonType); |
652 | m_componentLocationHash.insert(akey: anonType, avalue: m_componentLocationHash.value(akey: complexType)); |
653 | } |
654 | } else if (complexBaseType->derivationMethod() == XsdComplexType::DerivationExtension) { // 3 |
655 | complexType->contentType()->setSimpleType(complexBaseType->contentType()->simpleType()); |
656 | } |
657 | } else if (complexBaseType->contentType()->variety() == XsdComplexType::ContentType::Mixed && |
658 | complexType->derivationMethod() == XsdComplexType::DerivationRestriction && |
659 | XsdSchemaHelper::isParticleEmptiable(particle: complexBaseType->contentType()->particle())) { // 2 |
660 | // simple type was already set in parser |
661 | |
662 | const XsdSimpleType::Ptr anonType(new XsdSimpleType()); |
663 | anonType->setCategory(complexType->contentType()->simpleType()->category()); |
664 | anonType->setDerivationMethod(XsdSimpleType::DerivationRestriction); |
665 | anonType->setWxsSuperType(complexType->contentType()->simpleType()); |
666 | anonType->setFacets(complexTypeFacets(complexType)); |
667 | |
668 | QSet<AnySimpleType::Ptr> visitedPrimitiveTypes; |
669 | const AnySimpleType::Ptr primitiveType = findPrimitiveType(type: anonType->wxsSuperType(), visitedTypes&: visitedPrimitiveTypes); |
670 | anonType->setPrimitiveType(primitiveType); |
671 | |
672 | complexType->contentType()->setSimpleType(anonType); |
673 | |
674 | m_schema->addAnonymousType(type: anonType); |
675 | m_componentLocationHash.insert(akey: anonType, avalue: m_componentLocationHash.value(akey: complexType)); |
676 | } else { |
677 | complexType->contentType()->setSimpleType(BuiltinTypes::xsAnySimpleType); |
678 | } |
679 | } else if (baseType->isSimpleType()) { // 4 |
680 | complexType->contentType()->setSimpleType(baseType); |
681 | } else { // 5 |
682 | complexType->contentType()->setSimpleType(BuiltinTypes::xsAnySimpleType); |
683 | } |
684 | } |
685 | |
686 | void XsdSchemaResolver::resolveComplexContentComplexTypes() |
687 | { |
688 | XsdComplexType::List complexTypes; |
689 | |
690 | // first collect the global complex types |
691 | const SchemaType::List types = m_schema->types(); |
692 | for (int i = 0; i < types.count(); ++i) { |
693 | if (types.at(i)->isComplexType() && types.at(i)->isDefinedBySchema()) |
694 | complexTypes.append(t: types.at(i)); |
695 | } |
696 | |
697 | // then collect all anonymous simple types |
698 | const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); |
699 | for (int i = 0; i < anonymousTypes.count(); ++i) { |
700 | if (anonymousTypes.at(i)->isComplexType() && anonymousTypes.at(i)->isDefinedBySchema()) |
701 | complexTypes.append(t: anonymousTypes.at(i)); |
702 | } |
703 | |
704 | QSet<XsdComplexType::Ptr> visitedTypes; |
705 | for (int i = 0; i < complexTypes.count(); ++i) { |
706 | if (XsdComplexType::Ptr(complexTypes.at(i))->contentType()->variety() != XsdComplexType::ContentType::Simple) |
707 | resolveComplexContentComplexTypes(complexType: complexTypes.at(i), visitedTypes); |
708 | } |
709 | } |
710 | |
711 | void XsdSchemaResolver::resolveComplexContentComplexTypes(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes) |
712 | { |
713 | if (visitedTypes.contains(value: complexType)) |
714 | return; |
715 | else |
716 | visitedTypes.insert(value: complexType); |
717 | |
718 | ComplexContentType item; |
719 | bool foundCorrespondingItem = false; |
720 | for (int i = 0; i < m_complexContentTypes.count(); ++i) { |
721 | if (m_complexContentTypes.at(i).complexType == complexType) { |
722 | item = m_complexContentTypes.at(i); |
723 | foundCorrespondingItem = true; |
724 | break; |
725 | } |
726 | } |
727 | |
728 | if (!foundCorrespondingItem) |
729 | return; |
730 | |
731 | const SchemaType::Ptr baseType = complexType->wxsSuperType(); |
732 | |
733 | // at this point simple types have been resolved already, so we care about |
734 | // complex types here only |
735 | if (baseType->isComplexType() && baseType->isDefinedBySchema()) |
736 | resolveComplexContentComplexTypes(complexType: XsdComplexType::Ptr(baseType), visitedTypes); |
737 | |
738 | |
739 | // @see http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.ctcc.common |
740 | |
741 | // 3 |
742 | XsdParticle::Ptr effectiveContent; |
743 | if (!item.explicitContent) { // 3.1 |
744 | if (item.effectiveMixed == true) { // 3.1.1 |
745 | const XsdParticle::Ptr particle(new XsdParticle()); |
746 | particle->setMinimumOccurs(1); |
747 | particle->setMaximumOccurs(1); |
748 | particle->setMaximumOccursUnbounded(false); |
749 | |
750 | const XsdModelGroup::Ptr sequence(new XsdModelGroup()); |
751 | sequence->setCompositor(XsdModelGroup::SequenceCompositor); |
752 | particle->setTerm(sequence); |
753 | |
754 | effectiveContent = particle; |
755 | } else { // 3.1.2 |
756 | effectiveContent = XsdParticle::Ptr(); |
757 | } |
758 | } else { // 3.2 |
759 | effectiveContent = item.explicitContent; |
760 | } |
761 | |
762 | // 4 |
763 | XsdComplexType::ContentType::Ptr explicitContentType(new XsdComplexType::ContentType()); |
764 | if (item.complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { // 4.1 |
765 | if (!effectiveContent) { // 4.1.1 |
766 | explicitContentType->setVariety(XsdComplexType::ContentType::Empty); |
767 | } else { // 4.1.2 |
768 | if (item.effectiveMixed == true) |
769 | explicitContentType->setVariety(XsdComplexType::ContentType::Mixed); |
770 | else |
771 | explicitContentType->setVariety(XsdComplexType::ContentType::ElementOnly); |
772 | |
773 | explicitContentType->setParticle(effectiveContent); |
774 | } |
775 | } else if (item.complexType->derivationMethod() == XsdComplexType::DerivationExtension) { // 4.2 |
776 | const SchemaType::Ptr baseType = item.complexType->wxsSuperType(); |
777 | if (baseType->isSimpleType() || (baseType->isComplexType() && baseType->isDefinedBySchema() && (XsdComplexType::Ptr(baseType)->contentType()->variety() == XsdComplexType::ContentType::Empty || |
778 | XsdComplexType::Ptr(baseType)->contentType()->variety() == XsdComplexType::ContentType::Simple))) { // 4.2.1 |
779 | if (!effectiveContent) { |
780 | explicitContentType->setVariety(XsdComplexType::ContentType::Empty); |
781 | } else { |
782 | if (item.effectiveMixed == true) |
783 | explicitContentType->setVariety(XsdComplexType::ContentType::Mixed); |
784 | else |
785 | explicitContentType->setVariety(XsdComplexType::ContentType::ElementOnly); |
786 | |
787 | explicitContentType->setParticle(effectiveContent); |
788 | } |
789 | } else if (baseType->isComplexType() && baseType->isDefinedBySchema() && (XsdComplexType::Ptr(baseType)->contentType()->variety() == XsdComplexType::ContentType::ElementOnly || |
790 | XsdComplexType::Ptr(baseType)->contentType()->variety() == XsdComplexType::ContentType::Mixed) && !effectiveContent) { // 4.2.2 |
791 | const XsdComplexType::Ptr complexBaseType(baseType); |
792 | |
793 | explicitContentType = complexBaseType->contentType(); |
794 | } else { // 4.2.3 |
795 | explicitContentType->setVariety(item.effectiveMixed ? XsdComplexType::ContentType::Mixed : XsdComplexType::ContentType::ElementOnly); |
796 | |
797 | XsdParticle::Ptr baseParticle; |
798 | if (baseType == BuiltinTypes::xsAnyType) { |
799 | // we need a workaround here, since the xsAnyType is no real (aka XsdComplexType) complex type... |
800 | |
801 | baseParticle = XsdParticle::Ptr(new XsdParticle()); |
802 | baseParticle->setMinimumOccurs(1); |
803 | baseParticle->setMaximumOccurs(1); |
804 | baseParticle->setMaximumOccursUnbounded(false); |
805 | |
806 | const XsdModelGroup::Ptr group(new XsdModelGroup()); |
807 | group->setCompositor(XsdModelGroup::SequenceCompositor); |
808 | |
809 | const XsdParticle::Ptr particle(new XsdParticle()); |
810 | particle->setMinimumOccurs(0); |
811 | particle->setMaximumOccursUnbounded(true); |
812 | |
813 | const XsdWildcard::Ptr wildcard(new XsdWildcard()); |
814 | wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); |
815 | wildcard->setProcessContents(XsdWildcard::Lax); |
816 | |
817 | particle->setTerm(wildcard); |
818 | XsdParticle::List particles; |
819 | particles.append(t: particle); |
820 | group->setParticles(particles); |
821 | baseParticle->setTerm(group); |
822 | } else { |
823 | const XsdComplexType::Ptr complexBaseType(baseType); |
824 | baseParticle = complexBaseType->contentType()->particle(); |
825 | } |
826 | if (baseParticle && baseParticle->term()->isModelGroup() && (XsdModelGroup::Ptr(baseParticle->term())->compositor() == XsdModelGroup::AllCompositor) && |
827 | (!item.explicitContent)) { // 4.2.3.1 |
828 | |
829 | explicitContentType->setParticle(baseParticle); |
830 | } else if (baseParticle && baseParticle->term()->isModelGroup() && (XsdModelGroup::Ptr(baseParticle->term())->compositor() == XsdModelGroup::AllCompositor) && |
831 | (effectiveContent->term()->isModelGroup() && (XsdModelGroup::Ptr(effectiveContent->term())->compositor() == XsdModelGroup::AllCompositor))) { // 4.2.3.2 |
832 | const XsdParticle::Ptr particle(new XsdParticle()); |
833 | particle->setMinimumOccurs(effectiveContent->minimumOccurs()); |
834 | particle->setMaximumOccurs(1); |
835 | particle->setMaximumOccursUnbounded(false); |
836 | |
837 | const XsdModelGroup::Ptr group(new XsdModelGroup()); |
838 | group->setCompositor(XsdModelGroup::AllCompositor); |
839 | XsdParticle::List particles = XsdModelGroup::Ptr(baseParticle->term())->particles(); |
840 | particles << XsdModelGroup::Ptr(effectiveContent->term())->particles(); |
841 | group->setParticles(particles); |
842 | particle->setTerm(group); |
843 | |
844 | explicitContentType->setParticle(particle); |
845 | } else { // 4.2.3.3 |
846 | const XsdParticle::Ptr particle(new XsdParticle()); |
847 | particle->setMinimumOccurs(1); |
848 | particle->setMaximumOccurs(1); |
849 | particle->setMaximumOccursUnbounded(false); |
850 | |
851 | const XsdModelGroup::Ptr group(new XsdModelGroup()); |
852 | group->setCompositor(XsdModelGroup::SequenceCompositor); |
853 | |
854 | if (effectiveContent && effectiveContent->term()->isModelGroup() && XsdModelGroup::Ptr(effectiveContent->term())->compositor() == XsdModelGroup::AllCompositor) { |
855 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Content model of complex type %1 contains %2 element so it cannot be derived by extension from a non-empty type." ) |
856 | .arg(a: formatType(np: m_namePool, type: complexType)).arg(a: formatKeyword(keyword: "all" )), errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType)); |
857 | return; |
858 | } |
859 | |
860 | if (baseParticle && baseParticle->term()->isModelGroup() && XsdModelGroup::Ptr(baseParticle->term())->compositor() == XsdModelGroup::AllCompositor) { |
861 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Complex type %1 cannot be derived by extension from %2 as the latter contains %3 element in its content model." ) |
862 | .arg(a: formatType(np: m_namePool, type: complexType)) |
863 | .arg(a: formatType(np: m_namePool, type: baseType)) |
864 | .arg(a: formatKeyword(keyword: "all" )), errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType)); |
865 | return; |
866 | } |
867 | |
868 | XsdParticle::List particles; |
869 | if (baseParticle) |
870 | particles << baseParticle; |
871 | if (effectiveContent) |
872 | particles << effectiveContent; |
873 | group->setParticles(particles); |
874 | particle->setTerm(group); |
875 | |
876 | explicitContentType->setParticle(particle); |
877 | } |
878 | |
879 | if (baseType->isDefinedBySchema()) { // xs:anyType has no open content |
880 | const XsdComplexType::Ptr complexBaseType(baseType); |
881 | explicitContentType->setOpenContent(complexBaseType->contentType()->openContent()); |
882 | } |
883 | } |
884 | } |
885 | |
886 | // 5 |
887 | XsdComplexType::OpenContent::Ptr wildcardElement; |
888 | if (item.complexType->contentType()->openContent()) { // 5.1 |
889 | wildcardElement = item.complexType->contentType()->openContent(); |
890 | } else { |
891 | if (m_defaultOpenContent) { // 5.2 |
892 | if ((explicitContentType->variety() != XsdComplexType::ContentType::Empty) || // 5.2.1 |
893 | (explicitContentType->variety() == XsdComplexType::ContentType::Empty && m_defaultOpenContentAppliesToEmpty)) { // 5.2.2 |
894 | wildcardElement = m_defaultOpenContent; |
895 | } |
896 | } |
897 | } |
898 | |
899 | // 6 |
900 | if (!wildcardElement) { // 6.1 |
901 | item.complexType->setContentType(explicitContentType); |
902 | } else { |
903 | if (wildcardElement->mode() == XsdComplexType::OpenContent::None) { // 6.2 |
904 | const XsdComplexType::ContentType::Ptr contentType(new XsdComplexType::ContentType()); |
905 | contentType->setVariety(explicitContentType->variety()); |
906 | contentType->setParticle(explicitContentType->particle()); |
907 | |
908 | item.complexType->setContentType(contentType); |
909 | } else { // 6.3 |
910 | const XsdComplexType::ContentType::Ptr contentType(new XsdComplexType::ContentType()); |
911 | |
912 | if (explicitContentType->variety() == XsdComplexType::ContentType::Empty) |
913 | contentType->setVariety(XsdComplexType::ContentType::ElementOnly); |
914 | else |
915 | contentType->setVariety(explicitContentType->variety()); |
916 | |
917 | if (explicitContentType->variety() == XsdComplexType::ContentType::Empty) { |
918 | const XsdParticle::Ptr particle(new XsdParticle()); |
919 | particle->setMinimumOccurs(1); |
920 | particle->setMaximumOccurs(1); |
921 | const XsdModelGroup::Ptr sequence(new XsdModelGroup()); |
922 | sequence->setCompositor(XsdModelGroup::SequenceCompositor); |
923 | particle->setTerm(sequence); |
924 | contentType->setParticle(particle); |
925 | } else { |
926 | contentType->setParticle(explicitContentType->particle()); |
927 | } |
928 | |
929 | const XsdComplexType::OpenContent::Ptr openContent(new XsdComplexType::OpenContent()); |
930 | if (wildcardElement) |
931 | openContent->setMode(wildcardElement->mode()); |
932 | else |
933 | openContent->setMode(XsdComplexType::OpenContent::Interleave); |
934 | |
935 | if (wildcardElement) |
936 | openContent->setWildcard(wildcardElement->wildcard()); |
937 | |
938 | item.complexType->setContentType(contentType); |
939 | } |
940 | } |
941 | } |
942 | |
943 | void XsdSchemaResolver::resolveAttributeTypes() |
944 | { |
945 | for (int i = 0; i < m_attributeTypes.count(); ++i) { |
946 | const AttributeType item = m_attributeTypes.at(i); |
947 | |
948 | SchemaType::Ptr type = m_schema->type(name: item.typeName); |
949 | if (!type) { |
950 | // maybe it's a basic type... |
951 | type = m_context->schemaTypeFactory()->createSchemaType(name: item.typeName); |
952 | if (!type) { |
953 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Type %1 of %2 element cannot be resolved." ) |
954 | .arg(a: formatType(np: m_namePool, name: item.typeName)) |
955 | .arg(a: formatElement(element: "attribute" )), |
956 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
957 | return; |
958 | } |
959 | } |
960 | |
961 | if (!type->isSimpleType() && type->category() != SchemaType::None) { |
962 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Type of %1 element must be a simple type, %2 is not." ) |
963 | .arg(a: formatElement(element: "attribute" )) |
964 | .arg(a: formatType(np: m_namePool, name: item.typeName)), |
965 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
966 | return; |
967 | } |
968 | |
969 | item.attribute->setType(type); |
970 | } |
971 | } |
972 | |
973 | void XsdSchemaResolver::resolveAlternativeTypes() |
974 | { |
975 | for (int i = 0; i < m_alternativeTypes.count(); ++i) { |
976 | const AlternativeType item = m_alternativeTypes.at(i); |
977 | |
978 | SchemaType::Ptr type = m_schema->type(name: item.typeName); |
979 | if (!type) { |
980 | // maybe it's a basic type... |
981 | type = m_context->schemaTypeFactory()->createSchemaType(name: item.typeName); |
982 | if (!type) { |
983 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Type %1 of %2 element cannot be resolved." ) |
984 | .arg(a: formatType(np: m_namePool, name: item.typeName)) |
985 | .arg(a: formatElement(element: "alternative" )), |
986 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
987 | return; |
988 | } |
989 | } |
990 | |
991 | item.alternative->setType(type); |
992 | } |
993 | |
994 | for (int i = 0; i < m_alternativeTypeElements.count(); ++i) { |
995 | const AlternativeTypeElement item = m_alternativeTypeElements.at(i); |
996 | item.alternative->setType(item.element->type()); |
997 | } |
998 | } |
999 | |
1000 | bool hasCircularSubstitutionGroup(const XsdElement::Ptr ¤t, const XsdElement::Ptr &head, const NamePool::Ptr &namePool) |
1001 | { |
1002 | if (current == head) |
1003 | return true; |
1004 | else { |
1005 | const XsdElement::List elements = current->substitutionGroupAffiliations(); |
1006 | for (int i = 0; i < elements.count(); ++i) { |
1007 | if (hasCircularSubstitutionGroup(current: elements.at(i), head, namePool)) |
1008 | return true; |
1009 | } |
1010 | } |
1011 | |
1012 | return false; |
1013 | } |
1014 | |
1015 | void XsdSchemaResolver::resolveSubstitutionGroupAffiliations() |
1016 | { |
1017 | for (int i = 0; i < m_substitutionGroupAffiliations.count(); ++i) { |
1018 | const SubstitutionGroupAffiliation item = m_substitutionGroupAffiliations.at(i); |
1019 | |
1020 | XsdElement::List affiliations; |
1021 | for (int j = 0; j < item.elementNames.count(); ++j) { |
1022 | const XsdElement::Ptr element = m_schema->element(name: item.elementNames.at(i: j)); |
1023 | if (!element) { |
1024 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Substitution group %1 of %2 element cannot be resolved." ) |
1025 | .arg(a: formatKeyword(np: m_namePool, name: item.elementNames.at(i: j))) |
1026 | .arg(a: formatElement(element: "element" )), |
1027 | errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
1028 | return; |
1029 | } |
1030 | |
1031 | // @see http://www.w3.org/TR/xmlschema11-1/#e-props-correct 5) |
1032 | if (hasCircularSubstitutionGroup(current: element, head: item.element, namePool: m_namePool)) { |
1033 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Substitution group %1 has circular definition." ).arg(a: formatKeyword(np: m_namePool, name: item.elementNames.at(i: j))), errorCode: XsdSchemaContext::XSDError, sourceLocation: item.location); |
1034 | return; |
1035 | } |
1036 | |
1037 | affiliations.append(t: element); |
1038 | } |
1039 | |
1040 | item.element->setSubstitutionGroupAffiliations(affiliations); |
1041 | } |
1042 | |
1043 | for (int i = 0; i < m_substitutionGroupTypes.count(); ++i) { |
1044 | const XsdElement::Ptr element = m_substitutionGroupTypes.at(i); |
1045 | element->setType(element->substitutionGroupAffiliations().first()->type()); |
1046 | } |
1047 | } |
1048 | |
1049 | bool isSubstGroupHeadOf(const XsdElement::Ptr &head, const XsdElement::Ptr &element, const NamePool::Ptr &namePool) |
1050 | { |
1051 | if (head->name(namePool) == element->name(namePool)) |
1052 | return true; |
1053 | |
1054 | const XsdElement::List affiliations = element->substitutionGroupAffiliations(); |
1055 | for (int i = 0; i < affiliations.count(); ++i) { |
1056 | if (isSubstGroupHeadOf(head, element: affiliations.at(i), namePool)) |
1057 | return true; |
1058 | } |
1059 | |
1060 | return false; |
1061 | } |
1062 | |
1063 | void XsdSchemaResolver::resolveSubstitutionGroups() |
1064 | { |
1065 | const XsdElement::List elements = m_schema->elements(); |
1066 | for (int i = 0; i < elements.count(); ++i) { |
1067 | const XsdElement::Ptr element = elements.at(i); |
1068 | |
1069 | // the element is always itself in the substitution group |
1070 | element->addSubstitutionGroup(elements: element); |
1071 | |
1072 | for (int j = 0; j < elements.count(); ++j) { |
1073 | if (i == j) |
1074 | continue; |
1075 | |
1076 | if (isSubstGroupHeadOf(head: element, element: elements.at(i: j), namePool: m_namePool)) |
1077 | element->addSubstitutionGroup(elements: elements.at(i: j)); |
1078 | } |
1079 | } |
1080 | } |
1081 | |
1082 | void XsdSchemaResolver::resolveTermReferences() |
1083 | { |
1084 | // first the global complex types |
1085 | const SchemaType::List types = m_schema->types(); |
1086 | for (int i = 0; i < types.count(); ++i) { |
1087 | if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema()) |
1088 | continue; |
1089 | |
1090 | const XsdComplexType::Ptr complexType = types.at(i); |
1091 | if (complexType->contentType()->variety() != XsdComplexType::ContentType::ElementOnly && complexType->contentType()->variety() != XsdComplexType::ContentType::Mixed) |
1092 | continue; |
1093 | |
1094 | resolveTermReference(particle: complexType->contentType()->particle(), visitedGroups: QSet<QXmlName>()); |
1095 | } |
1096 | |
1097 | // then all anonymous complex types |
1098 | const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); |
1099 | for (int i = 0; i < anonymousTypes.count(); ++i) { |
1100 | if (!(anonymousTypes.at(i)->isComplexType()) || !anonymousTypes.at(i)->isDefinedBySchema()) |
1101 | continue; |
1102 | |
1103 | const XsdComplexType::Ptr complexType = anonymousTypes.at(i); |
1104 | if (complexType->contentType()->variety() != XsdComplexType::ContentType::ElementOnly && complexType->contentType()->variety() != XsdComplexType::ContentType::Mixed) |
1105 | continue; |
1106 | |
1107 | resolveTermReference(particle: complexType->contentType()->particle(), visitedGroups: QSet<QXmlName>()); |
1108 | } |
1109 | |
1110 | const XsdModelGroup::List groups = m_schema->elementGroups(); |
1111 | for (int i = 0; i < groups.count(); ++i) { |
1112 | const XsdParticle::Ptr particle(new XsdParticle()); |
1113 | particle->setTerm(groups.at(i)); |
1114 | resolveTermReference(particle, visitedGroups: QSet<QXmlName>()); |
1115 | } |
1116 | } |
1117 | |
1118 | void XsdSchemaResolver::resolveTermReference(const XsdParticle::Ptr &particle, QSet<QXmlName> visitedGroups) |
1119 | { |
1120 | if (!particle) |
1121 | return; |
1122 | |
1123 | const XsdTerm::Ptr term = particle->term(); |
1124 | |
1125 | // if it is a model group, we iterate over it recursive... |
1126 | if (term->isModelGroup()) { |
1127 | const XsdModelGroup::Ptr modelGroup = term; |
1128 | const XsdParticle::List particles = modelGroup->particles(); |
1129 | |
1130 | for (int i = 0; i < particles.count(); ++i) { |
1131 | resolveTermReference(particle: particles.at(i), visitedGroups); |
1132 | } |
1133 | |
1134 | // check for unique names of elements inside all compositor |
1135 | if (modelGroup->compositor() != XsdModelGroup::ChoiceCompositor) { |
1136 | for (int i = 0; i < particles.count(); ++i) { |
1137 | const XsdParticle::Ptr particle = particles.at(i); |
1138 | const XsdTerm::Ptr term = particle->term(); |
1139 | |
1140 | if (!(term->isElement())) |
1141 | continue; |
1142 | |
1143 | for (int j = 0; j < particles.count(); ++j) { |
1144 | const XsdParticle::Ptr otherParticle = particles.at(i: j); |
1145 | const XsdTerm::Ptr otherTerm = otherParticle->term(); |
1146 | |
1147 | if (otherTerm->isElement() && i != j) { |
1148 | const XsdElement::Ptr element = term; |
1149 | const XsdElement::Ptr otherElement = otherTerm; |
1150 | |
1151 | if (element->name(namePool: m_namePool) == otherElement->name(namePool: m_namePool)) { |
1152 | if (modelGroup->compositor() == XsdModelGroup::AllCompositor) { |
1153 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Duplicated element names %1 in %2 element." ) |
1154 | .arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool))) |
1155 | .arg(a: formatElement(element: "all" )), |
1156 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: modelGroup)); |
1157 | return; |
1158 | } else if (modelGroup->compositor() == XsdModelGroup::SequenceCompositor) { |
1159 | if (element->type() != otherElement->type()) { // not same variety |
1160 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Duplicated element names %1 in %2 element." ) |
1161 | .arg(a: formatKeyword(keyword: element->displayName(namePool: m_namePool))) |
1162 | .arg(a: formatElement(element: "sequence" )), |
1163 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: modelGroup)); |
1164 | return; |
1165 | } |
1166 | } |
1167 | } |
1168 | } |
1169 | } |
1170 | } |
1171 | } |
1172 | |
1173 | return; |
1174 | } |
1175 | |
1176 | // ...otherwise we have reached the end of recursion... |
1177 | if (!term->isReference()) |
1178 | return; |
1179 | |
1180 | // ...or we have reached a reference term that must be resolved |
1181 | const XsdReference::Ptr reference = term; |
1182 | switch (reference->type()) { |
1183 | case XsdReference::Element: |
1184 | { |
1185 | const XsdElement::Ptr element = m_schema->element(name: reference->referenceName()); |
1186 | if (element) { |
1187 | particle->setTerm(element); |
1188 | } else { |
1189 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Reference %1 of %2 element cannot be resolved." ) |
1190 | .arg(a: formatKeyword(np: m_namePool, name: reference->referenceName())) |
1191 | .arg(a: formatElement(element: "element" )), |
1192 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1193 | return; |
1194 | } |
1195 | } |
1196 | break; |
1197 | case XsdReference::ModelGroup: |
1198 | { |
1199 | const XsdModelGroup::Ptr modelGroup = m_schema->elementGroup(name: reference->referenceName()); |
1200 | if (modelGroup) { |
1201 | if (visitedGroups.contains(value: modelGroup->name(namePool: m_namePool))) { |
1202 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Circular group reference for %1." ).arg(a: formatKeyword(keyword: modelGroup->displayName(namePool: m_namePool))), |
1203 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1204 | } else { |
1205 | visitedGroups.insert(value: modelGroup->name(namePool: m_namePool)); |
1206 | } |
1207 | |
1208 | particle->setTerm(modelGroup); |
1209 | |
1210 | // start recursive iteration here as well to get all references resolved |
1211 | const XsdParticle::List particles = modelGroup->particles(); |
1212 | for (int i = 0; i < particles.count(); ++i) { |
1213 | resolveTermReference(particle: particles.at(i), visitedGroups); |
1214 | } |
1215 | |
1216 | if (modelGroup->compositor() == XsdModelGroup::AllCompositor) { |
1217 | if (m_allGroups.contains(value: reference)) { |
1218 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 element is not allowed in this scope" ).arg(a: formatElement(element: "all." )), |
1219 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1220 | return; |
1221 | } |
1222 | if (particle->maximumOccursUnbounded() || particle->maximumOccurs() != 1) { |
1223 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 element cannot have %2 attribute with value other than %3." ) |
1224 | .arg(a: formatElement(element: "all" )) |
1225 | .arg(a: formatAttribute(attribute: "maxOccurs" )) |
1226 | .arg(a: formatData(data: "1" )), |
1227 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1228 | return; |
1229 | } |
1230 | if (particle->minimumOccurs() != 0 && particle->minimumOccurs() != 1) { |
1231 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 element cannot have %2 attribute with value other than %3 or %4." ) |
1232 | .arg(a: formatElement(element: "all" )) |
1233 | .arg(a: formatAttribute(attribute: "minOccurs" )) |
1234 | .arg(a: formatData(data: "0" )) |
1235 | .arg(a: formatData(data: "1" )), |
1236 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1237 | return; |
1238 | } |
1239 | } |
1240 | } else { |
1241 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Reference %1 of %2 element cannot be resolved." ) |
1242 | .arg(a: formatKeyword(np: m_namePool, name: reference->referenceName())) |
1243 | .arg(a: formatElement(element: "group" )), |
1244 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1245 | return; |
1246 | } |
1247 | } |
1248 | break; |
1249 | } |
1250 | } |
1251 | |
1252 | void XsdSchemaResolver::resolveAttributeTermReferences() |
1253 | { |
1254 | // first all global attribute groups |
1255 | const XsdAttributeGroup::List attributeGroups = m_schema->attributeGroups(); |
1256 | for (int i = 0; i < attributeGroups.count(); ++i) { |
1257 | XsdWildcard::Ptr wildcard = attributeGroups.at(i)->wildcard(); |
1258 | const XsdAttributeUse::List uses = resolveAttributeTermReferences(attributeUses: attributeGroups.at(i)->attributeUses(), wildcard, visitedAttributeGroups: QSet<QXmlName>()); |
1259 | attributeGroups.at(i)->setAttributeUses(uses); |
1260 | attributeGroups.at(i)->setWildcard(wildcard); |
1261 | } |
1262 | |
1263 | // then the global complex types |
1264 | const SchemaType::List types = m_schema->types(); |
1265 | for (int i = 0; i < types.count(); ++i) { |
1266 | if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema()) |
1267 | continue; |
1268 | |
1269 | const XsdComplexType::Ptr complexType = types.at(i); |
1270 | const XsdAttributeUse::List attributeUses = complexType->attributeUses(); |
1271 | |
1272 | XsdWildcard::Ptr wildcard = complexType->attributeWildcard(); |
1273 | const XsdAttributeUse::List uses = resolveAttributeTermReferences(attributeUses, wildcard, visitedAttributeGroups: QSet<QXmlName>()); |
1274 | complexType->setAttributeUses(uses); |
1275 | complexType->setAttributeWildcard(wildcard); |
1276 | } |
1277 | |
1278 | // and afterwards all anonymous complex types |
1279 | const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); |
1280 | for (int i = 0; i < anonymousTypes.count(); ++i) { |
1281 | if (!(anonymousTypes.at(i)->isComplexType()) || !anonymousTypes.at(i)->isDefinedBySchema()) |
1282 | continue; |
1283 | |
1284 | const XsdComplexType::Ptr complexType = anonymousTypes.at(i); |
1285 | const XsdAttributeUse::List attributeUses = complexType->attributeUses(); |
1286 | |
1287 | XsdWildcard::Ptr wildcard = complexType->attributeWildcard(); |
1288 | const XsdAttributeUse::List uses = resolveAttributeTermReferences(attributeUses, wildcard, visitedAttributeGroups: QSet<QXmlName>()); |
1289 | complexType->setAttributeUses(uses); |
1290 | complexType->setAttributeWildcard(wildcard); |
1291 | } |
1292 | } |
1293 | |
1294 | XsdAttributeUse::List XsdSchemaResolver::resolveAttributeTermReferences(const XsdAttributeUse::List &attributeUses, XsdWildcard::Ptr &wildcard, QSet<QXmlName> visitedAttributeGroups) |
1295 | { |
1296 | XsdAttributeUse::List resolvedAttributeUses; |
1297 | |
1298 | for (int i = 0; i < attributeUses.count(); ++i) { |
1299 | const XsdAttributeUse::Ptr attributeUse = attributeUses.at(i); |
1300 | if (attributeUse->isAttributeUse()) { |
1301 | // it is a real attribute use, so no need to resolve it |
1302 | resolvedAttributeUses.append(t: attributeUse); |
1303 | } else if (attributeUse->isReference()) { |
1304 | // it is just a reference, so resolve it to the real attribute use |
1305 | |
1306 | const XsdAttributeReference::Ptr reference = attributeUse; |
1307 | if (reference->type() == XsdAttributeReference::AttributeUse) { |
1308 | |
1309 | // lookup the real attribute |
1310 | const XsdAttribute::Ptr attribute = m_schema->attribute(name: reference->referenceName()); |
1311 | if (!attribute) { |
1312 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Reference %1 of %2 element cannot be resolved." ) |
1313 | .arg(a: formatKeyword(np: m_namePool, name: reference->referenceName())) |
1314 | .arg(a: formatElement(element: "attribute" )), |
1315 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1316 | return XsdAttributeUse::List(); |
1317 | } |
1318 | |
1319 | // if both, reference and definition have a fixed or default value set, then they must be equal |
1320 | if (attribute->valueConstraint() && attributeUse->valueConstraint()) { |
1321 | if (attribute->valueConstraint()->value() != attributeUse->valueConstraint()->value()) { |
1322 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 or %2 attribute of reference %3 does not match with the attribute declaration %4." ) |
1323 | .arg(a: formatAttribute(attribute: "fixed" )) |
1324 | .arg(a: formatAttribute(attribute: "default" )) |
1325 | .arg(a: formatKeyword(np: m_namePool, name: reference->referenceName())) |
1326 | .arg(a: formatKeyword(keyword: attribute->displayName(namePool: m_namePool))), |
1327 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1328 | return XsdAttributeUse::List(); |
1329 | } |
1330 | } |
1331 | |
1332 | attributeUse->setAttribute(attribute); |
1333 | if (!attributeUse->valueConstraint() && attribute->valueConstraint()) |
1334 | attributeUse->setValueConstraint(XsdAttributeUse::ValueConstraint::fromAttributeValueConstraint(constraint: attribute->valueConstraint())); |
1335 | |
1336 | resolvedAttributeUses.append(t: attributeUse); |
1337 | } else if (reference->type() == XsdAttributeReference::AttributeGroup) { |
1338 | const XsdAttributeGroup::Ptr attributeGroup = m_schema->attributeGroup(name: reference->referenceName()); |
1339 | if (!attributeGroup) { |
1340 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Reference %1 of %2 element cannot be resolved." ) |
1341 | .arg(a: formatKeyword(np: m_namePool, name: reference->referenceName())) |
1342 | .arg(a: formatElement(element: "attributeGroup" )), |
1343 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1344 | return XsdAttributeUse::List(); |
1345 | } |
1346 | if (visitedAttributeGroups.contains(value: attributeGroup->name(namePool: m_namePool))) { |
1347 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute group %1 has circular reference." ).arg(a: formatKeyword(np: m_namePool, name: reference->referenceName())), |
1348 | errorCode: XsdSchemaContext::XSDError, sourceLocation: reference->sourceLocation()); |
1349 | return XsdAttributeUse::List(); |
1350 | } else { |
1351 | visitedAttributeGroups.insert(value: attributeGroup->name(namePool: m_namePool)); |
1352 | } |
1353 | |
1354 | // resolve attribute wildcards as defined in http://www.w3.org/TR/xmlschema11-1/#declare-attributeGroup-wildcard |
1355 | XsdWildcard::Ptr childWildcard; |
1356 | resolvedAttributeUses << resolveAttributeTermReferences(attributeUses: attributeGroup->attributeUses(), wildcard&: childWildcard, visitedAttributeGroups); |
1357 | if (!childWildcard) { |
1358 | if (attributeGroup->wildcard()) { |
1359 | if (wildcard) { |
1360 | const XsdWildcard::ProcessContents contents = wildcard->processContents(); |
1361 | wildcard = XsdSchemaHelper::wildcardIntersection(wildcard, otherWildcard: attributeGroup->wildcard()); |
1362 | wildcard->setProcessContents(contents); |
1363 | } else { |
1364 | wildcard = attributeGroup->wildcard(); |
1365 | } |
1366 | } |
1367 | } else { |
1368 | XsdWildcard::Ptr newWildcard; |
1369 | if (attributeGroup->wildcard()) { |
1370 | const XsdWildcard::ProcessContents contents = attributeGroup->wildcard()->processContents(); |
1371 | newWildcard = XsdSchemaHelper::wildcardIntersection(wildcard: attributeGroup->wildcard(), otherWildcard: childWildcard); |
1372 | newWildcard->setProcessContents(contents); |
1373 | } else { |
1374 | newWildcard = childWildcard; |
1375 | } |
1376 | |
1377 | if (wildcard) { |
1378 | const XsdWildcard::ProcessContents contents = wildcard->processContents(); |
1379 | wildcard = XsdSchemaHelper::wildcardIntersection(wildcard, otherWildcard: newWildcard); |
1380 | wildcard->setProcessContents(contents); |
1381 | } else { |
1382 | wildcard = newWildcard; |
1383 | } |
1384 | } |
1385 | } |
1386 | } |
1387 | } |
1388 | |
1389 | return resolvedAttributeUses; |
1390 | } |
1391 | |
1392 | void XsdSchemaResolver::resolveAttributeInheritance() |
1393 | { |
1394 | // collect the global and anonymous complex types |
1395 | SchemaType::List types = m_schema->types(); |
1396 | types << m_schema->anonymousTypes(); |
1397 | |
1398 | QSet<XsdComplexType::Ptr> visitedTypes; |
1399 | for (int i = 0; i < types.count(); ++i) { |
1400 | if (!(types.at(i)->isComplexType()) || !types.at(i)->isDefinedBySchema()) |
1401 | continue; |
1402 | |
1403 | const XsdComplexType::Ptr complexType = types.at(i); |
1404 | |
1405 | resolveAttributeInheritance(complexType, visitedTypes); |
1406 | } |
1407 | } |
1408 | |
1409 | bool isValidWildcardRestriction(const XsdWildcard::Ptr &wildcard, const XsdWildcard::Ptr &baseWildcard) |
1410 | { |
1411 | if (wildcard->namespaceConstraint()->variety() == baseWildcard->namespaceConstraint()->variety()) { |
1412 | if (!XsdSchemaHelper::checkWildcardProcessContents(baseWildcard, derivedWildcard: wildcard)) |
1413 | return false; |
1414 | } |
1415 | |
1416 | if (wildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Any && |
1417 | baseWildcard->namespaceConstraint()->variety() != XsdWildcard::NamespaceConstraint::Any ) { |
1418 | return false; |
1419 | } |
1420 | if (baseWildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Not && |
1421 | wildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Enumeration) { |
1422 | if (baseWildcard->namespaceConstraint()->namespaces().intersects(other: wildcard->namespaceConstraint()->namespaces())) |
1423 | return false; |
1424 | } |
1425 | if (baseWildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Enumeration && |
1426 | wildcard->namespaceConstraint()->variety() == XsdWildcard::NamespaceConstraint::Enumeration) { |
1427 | if (!wildcard->namespaceConstraint()->namespaces().subtract(other: baseWildcard->namespaceConstraint()->namespaces()).isEmpty()) |
1428 | return false; |
1429 | } |
1430 | |
1431 | return true; |
1432 | } |
1433 | |
1434 | /* |
1435 | * Since we inherit the attributes from our base class we have to walk up in the |
1436 | * inheritance hierarchy first and resolve the attribute inheritance top-down. |
1437 | */ |
1438 | void XsdSchemaResolver::resolveAttributeInheritance(const XsdComplexType::Ptr &complexType, QSet<XsdComplexType::Ptr> &visitedTypes) |
1439 | { |
1440 | if (visitedTypes.contains(value: complexType)) |
1441 | return; |
1442 | else |
1443 | visitedTypes.insert(value: complexType); |
1444 | |
1445 | const SchemaType::Ptr baseType = complexType->wxsSuperType(); |
1446 | Q_ASSERT(baseType); |
1447 | |
1448 | if (!(baseType->isComplexType()) || !baseType->isDefinedBySchema()) |
1449 | return; |
1450 | |
1451 | const XsdComplexType::Ptr complexBaseType = baseType; |
1452 | |
1453 | resolveAttributeInheritance(complexType: complexBaseType, visitedTypes); |
1454 | |
1455 | // @see http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.attuses |
1456 | |
1457 | // 1 and 2 (the attribute groups have been resolved here already) |
1458 | const XsdAttributeUse::List uses = complexBaseType->attributeUses(); |
1459 | |
1460 | if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { // 3.2 |
1461 | const XsdAttributeUse::List currentUses = complexType->attributeUses(); |
1462 | |
1463 | // 3.2.1 and 3.2.2 As we also keep the prohibited attributes as objects, the algorithm below |
1464 | // handles both the same way |
1465 | |
1466 | // add only these attribute uses of the base type that match one of the following criteria: |
1467 | // 1: there is no attribute use with the same name in type |
1468 | // 2: there is no attribute with the same name marked as prohibited in type |
1469 | for (int j = 0; j < uses.count(); ++j) { |
1470 | const XsdAttributeUse::Ptr use = uses.at(i: j); |
1471 | bool found = false; |
1472 | for (int k = 0; k < currentUses.count(); ++k) { |
1473 | if (use->attribute()->name(namePool: m_namePool) == currentUses.at(i: k)->attribute()->name(namePool: m_namePool)) { |
1474 | found = true; |
1475 | |
1476 | // check if prohibited usage is violated |
1477 | if ((use->useType() == XsdAttributeUse::ProhibitedUse) && (currentUses.at(i: k)->useType() != XsdAttributeUse::ProhibitedUse)) { |
1478 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 attribute in %2 must have %3 use like in base type %4." ) |
1479 | .arg(a: formatAttribute(attribute: use->attribute()->displayName(namePool: m_namePool))) |
1480 | .arg(a: formatType(np: m_namePool, type: complexType)) |
1481 | .arg(a: formatData(data: "prohibited" )) |
1482 | .arg(a: formatType(np: m_namePool, type: complexBaseType)), |
1483 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType)); |
1484 | return; |
1485 | } |
1486 | |
1487 | break; |
1488 | } |
1489 | } |
1490 | |
1491 | if (!found && uses.at(i: j)->useType() != XsdAttributeUse::ProhibitedUse) { |
1492 | complexType->addAttributeUse(use: uses.at(i: j)); |
1493 | } |
1494 | } |
1495 | } else if (complexType->derivationMethod() == XsdComplexType::DerivationExtension) { // 3.1 |
1496 | QHash<QXmlName, XsdAttributeUse::Ptr> availableUses; |
1497 | |
1498 | // fill hash with attribute uses of current type for faster lookup |
1499 | { |
1500 | const XsdAttributeUse::List attributeUses = complexType->attributeUses(); |
1501 | |
1502 | for (int i = 0; i < attributeUses.count(); ++i) { |
1503 | availableUses.insert(akey: attributeUses.at(i)->attribute()->name(namePool: m_namePool), avalue: attributeUses.at(i)); |
1504 | } |
1505 | } |
1506 | |
1507 | // just add the attribute uses of the base type |
1508 | for (int i = 0; i < uses.count(); ++i) { |
1509 | const XsdAttributeUse::Ptr currentAttributeUse = uses.at(i); |
1510 | |
1511 | // if the base type defines the attribute as prohibited but we override it in current type, then don't copy the prohibited attribute use |
1512 | if ((currentAttributeUse->useType() == XsdAttributeUse::ProhibitedUse) && availableUses.contains(akey: currentAttributeUse->attribute()->name(namePool: m_namePool))) |
1513 | continue; |
1514 | |
1515 | complexType->addAttributeUse(use: uses.at(i)); |
1516 | } |
1517 | } |
1518 | |
1519 | // handle attribute wildcards: @see http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.anyatt |
1520 | |
1521 | // 1 |
1522 | const XsdWildcard::Ptr completeWildcard(complexType->attributeWildcard()); |
1523 | |
1524 | if (complexType->derivationMethod() == XsdComplexType::DerivationRestriction) { |
1525 | if (complexType->wxsSuperType()->isComplexType() && complexType->wxsSuperType()->isDefinedBySchema()) { |
1526 | const XsdComplexType::Ptr complexBaseType(complexType->wxsSuperType()); |
1527 | if (complexType->attributeWildcard()) { |
1528 | if (complexBaseType->attributeWildcard()) { |
1529 | if (!isValidWildcardRestriction(wildcard: complexType->attributeWildcard(), baseWildcard: complexBaseType->attributeWildcard())) { |
1530 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Attribute wildcard of %1 is not a valid restriction of attribute wildcard of base type %2." ) |
1531 | .arg(a: formatType(np: m_namePool, type: complexType)) |
1532 | .arg(a: formatType(np: m_namePool, type: complexBaseType)), |
1533 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType)); |
1534 | return; |
1535 | } |
1536 | } else { |
1537 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 has attribute wildcard but its base type %2 has not." ) |
1538 | .arg(a: formatType(np: m_namePool, type: complexType)) |
1539 | .arg(a: formatType(np: m_namePool, type: complexBaseType)), |
1540 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType)); |
1541 | return; |
1542 | } |
1543 | } |
1544 | } |
1545 | complexType->setAttributeWildcard(completeWildcard); // 2.1 |
1546 | } else if (complexType->derivationMethod() == XsdComplexType::DerivationExtension) { |
1547 | XsdWildcard::Ptr baseWildcard; // 2.2.1 |
1548 | if (complexType->wxsSuperType()->isComplexType() && complexType->wxsSuperType()->isDefinedBySchema()) |
1549 | baseWildcard = XsdComplexType::Ptr(complexType->wxsSuperType())->attributeWildcard(); // 2.2.1.1 |
1550 | else |
1551 | baseWildcard = XsdWildcard::Ptr(); // 2.2.1.2 |
1552 | |
1553 | if (!baseWildcard) { |
1554 | complexType->setAttributeWildcard(completeWildcard); // 2.2.2.1 |
1555 | } else if (!completeWildcard) { |
1556 | complexType->setAttributeWildcard(baseWildcard); // 2.2.2.2 |
1557 | } else { |
1558 | XsdWildcard::Ptr unionWildcard = XsdSchemaHelper::wildcardUnion(wildcard: completeWildcard, otherWildcard: baseWildcard); |
1559 | if (unionWildcard) { |
1560 | unionWildcard->setProcessContents(completeWildcard->processContents()); |
1561 | complexType->setAttributeWildcard(unionWildcard); // 2.2.2.3 |
1562 | } else { |
1563 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Union of attribute wildcard of type %1 and attribute wildcard of its base type %2 is not expressible." ) |
1564 | .arg(a: formatType(np: m_namePool, type: complexType)) |
1565 | .arg(a: formatType(np: m_namePool, type: complexBaseType)), |
1566 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: complexType)); |
1567 | return; |
1568 | } |
1569 | } |
1570 | } |
1571 | } |
1572 | |
1573 | void XsdSchemaResolver::resolveEnumerationFacetValues() |
1574 | { |
1575 | XsdSimpleType::List simpleTypes; |
1576 | |
1577 | // first collect the global simple types |
1578 | const SchemaType::List types = m_schema->types(); |
1579 | for (int i = 0; i < types.count(); ++i) { |
1580 | if (types.at(i)->isSimpleType()) |
1581 | simpleTypes.append(t: types.at(i)); |
1582 | } |
1583 | |
1584 | // then collect all anonymous simple types |
1585 | const SchemaType::List anonymousTypes = m_schema->anonymousTypes(); |
1586 | for (int i = 0; i < anonymousTypes.count(); ++i) { |
1587 | if (anonymousTypes.at(i)->isSimpleType()) |
1588 | simpleTypes.append(t: anonymousTypes.at(i)); |
1589 | } |
1590 | // process all simple types |
1591 | for (int i = 0; i < simpleTypes.count(); ++i) { |
1592 | const XsdSimpleType::Ptr simpleType = simpleTypes.at(i); |
1593 | |
1594 | // we resolve the enumeration values only for xs:QName and xs:NOTATION based types |
1595 | if (BuiltinTypes::xsQName->wxsTypeMatches(other: simpleType) || |
1596 | BuiltinTypes::xsNOTATION->wxsTypeMatches(other: simpleType)) { |
1597 | const XsdFacet::Hash facets = simpleType->facets(); |
1598 | if (facets.contains(akey: XsdFacet::Enumeration)) { |
1599 | AtomicValue::List newValues; |
1600 | |
1601 | const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration); |
1602 | const AtomicValue::List values = facet->multiValue(); |
1603 | for (int j = 0; j < values.count(); ++j) { |
1604 | const AtomicValue::Ptr value = values.at(i: j); |
1605 | |
1606 | Q_ASSERT(m_enumerationFacetValues.contains(value)); |
1607 | const NamespaceSupport support( m_enumerationFacetValues.value(akey: value) ); |
1608 | |
1609 | const QString qualifiedName = value->as<DerivedString<TypeString> >()->stringValue(); |
1610 | if (!XPathHelper::isQName(qName: qualifiedName)) { |
1611 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Enumeration facet contains invalid content: {%1} is not a value of type %2." ) |
1612 | .arg(a: formatData(data: qualifiedName)) |
1613 | .arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsQName)), |
1614 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType)); |
1615 | return; |
1616 | } |
1617 | |
1618 | QXmlName qNameValue; |
1619 | bool result = support.processName(qualifiedName, type: NamespaceSupport::ElementName, name&: qNameValue); |
1620 | if (!result) { |
1621 | m_context->error(message: QtXmlPatterns::tr(sourceText: "Namespace prefix of qualified name %1 is not defined." ).arg(a: formatData(data: qualifiedName)), |
1622 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: simpleType)); |
1623 | return; |
1624 | } |
1625 | |
1626 | newValues.append(t: QNameValue::fromValue(np: m_namePool, name: qNameValue)); |
1627 | } |
1628 | facet->setMultiValue(newValues); |
1629 | } |
1630 | } |
1631 | } |
1632 | } |
1633 | |
1634 | QSourceLocation XsdSchemaResolver::sourceLocation(const NamedSchemaComponent::Ptr component) const |
1635 | { |
1636 | if (m_componentLocationHash.contains(akey: component)) { |
1637 | return m_componentLocationHash.value(akey: component); |
1638 | } else { |
1639 | QSourceLocation location; |
1640 | location.setLine(1); |
1641 | location.setColumn(1); |
1642 | location.setUri(QString::fromLatin1(str: "dummyUri" )); |
1643 | |
1644 | return location; |
1645 | } |
1646 | } |
1647 | |
1648 | XsdFacet::Hash XsdSchemaResolver::complexTypeFacets(const XsdComplexType::Ptr &complexType) const |
1649 | { |
1650 | for (int i = 0; i < m_complexBaseTypes.count(); ++i) { |
1651 | if (m_complexBaseTypes.at(i).complexType == complexType) |
1652 | return m_complexBaseTypes.at(i).facets; |
1653 | } |
1654 | |
1655 | return XsdFacet::Hash(); |
1656 | } |
1657 | |
1658 | void XsdSchemaResolver::checkRedefinedGroups() |
1659 | { |
1660 | for (int i = 0; i < m_redefinedGroups.count(); ++i) { |
1661 | const RedefinedGroups item = m_redefinedGroups.at(i); |
1662 | |
1663 | // create dummy particles... |
1664 | const XsdParticle::Ptr redefinedParticle(new XsdParticle()); |
1665 | redefinedParticle->setTerm(item.redefinedGroup); |
1666 | const XsdParticle::Ptr particle(new XsdParticle()); |
1667 | particle->setTerm(item.group); |
1668 | |
1669 | // so that we can pass them to XsdParticleChecker::subsumes() |
1670 | QString errorMsg; |
1671 | if (!XsdParticleChecker::subsumes(particle, derivedParticle: redefinedParticle, context: m_context, errorMsg)) { |
1672 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 element %2 is not a valid restriction of the %3 element it redefines: %4." ) |
1673 | .arg(a: formatElement(element: "group" )) |
1674 | .arg(a: formatData(data: item.redefinedGroup->displayName(namePool: m_namePool))) |
1675 | .arg(a: formatElement(element: "group" )) |
1676 | .arg(a: errorMsg), |
1677 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: item.redefinedGroup)); |
1678 | return; |
1679 | } |
1680 | } |
1681 | } |
1682 | |
1683 | void XsdSchemaResolver::checkRedefinedAttributeGroups() |
1684 | { |
1685 | for (int i = 0; i < m_redefinedAttributeGroups.count(); ++i) { |
1686 | const RedefinedAttributeGroups item = m_redefinedAttributeGroups.at(i); |
1687 | |
1688 | QString errorMsg; |
1689 | if (!XsdSchemaHelper::isValidAttributeGroupRestriction(derivedAttributeGroup: item.redefinedGroup, attributeGroup: item.group, context: m_context, errorMsg)) { |
1690 | m_context->error(message: QtXmlPatterns::tr(sourceText: "%1 element %2 is not a valid restriction of the %3 element it redefines: %4." ) |
1691 | .arg(a: formatElement(element: "attributeGroup" )) |
1692 | .arg(a: formatData(data: item.redefinedGroup->displayName(namePool: m_namePool))) |
1693 | .arg(a: formatElement(element: "attributeGroup" )) |
1694 | .arg(a: errorMsg), |
1695 | errorCode: XsdSchemaContext::XSDError, sourceLocation: sourceLocation(component: item.redefinedGroup)); |
1696 | return; |
1697 | } |
1698 | } |
1699 | } |
1700 | |
1701 | AnySimpleType::Ptr XsdSchemaResolver::findPrimitiveType(const AnySimpleType::Ptr &type, QSet<AnySimpleType::Ptr> &visitedTypes) |
1702 | { |
1703 | if (visitedTypes.contains(value: type)) { |
1704 | // found invalid circular reference... |
1705 | return AnySimpleType::Ptr(); |
1706 | } else { |
1707 | visitedTypes.insert(value: type); |
1708 | } |
1709 | |
1710 | const QXmlName typeName = type->name(np: m_namePool); |
1711 | if (typeName == BuiltinTypes::xsString->name(np: m_namePool) || |
1712 | typeName == BuiltinTypes::xsBoolean->name(np: m_namePool) || |
1713 | typeName == BuiltinTypes::xsFloat->name(np: m_namePool) || |
1714 | typeName == BuiltinTypes::xsDouble->name(np: m_namePool) || |
1715 | typeName == BuiltinTypes::xsDecimal->name(np: m_namePool) || |
1716 | typeName == BuiltinTypes::xsDuration->name(np: m_namePool) || |
1717 | typeName == BuiltinTypes::xsDateTime->name(np: m_namePool) || |
1718 | typeName == BuiltinTypes::xsTime->name(np: m_namePool) || |
1719 | typeName == BuiltinTypes::xsDate->name(np: m_namePool) || |
1720 | typeName == BuiltinTypes::xsGYearMonth->name(np: m_namePool) || |
1721 | typeName == BuiltinTypes::xsGYear->name(np: m_namePool) || |
1722 | typeName == BuiltinTypes::xsGMonthDay->name(np: m_namePool) || |
1723 | typeName == BuiltinTypes::xsGDay->name(np: m_namePool) || |
1724 | typeName == BuiltinTypes::xsGMonth->name(np: m_namePool) || |
1725 | typeName == BuiltinTypes::xsHexBinary->name(np: m_namePool) || |
1726 | typeName == BuiltinTypes::xsBase64Binary->name(np: m_namePool) || |
1727 | typeName == BuiltinTypes::xsAnyURI->name(np: m_namePool) || |
1728 | typeName == BuiltinTypes::xsQName->name(np: m_namePool) || |
1729 | typeName == BuiltinTypes::xsNOTATION->name(np: m_namePool) || |
1730 | typeName == BuiltinTypes::xsAnySimpleType->name(np: m_namePool)) |
1731 | return type; |
1732 | else { |
1733 | if (type->wxsSuperType()) |
1734 | return findPrimitiveType(type: type->wxsSuperType(), visitedTypes); |
1735 | else { |
1736 | return AnySimpleType::Ptr(); |
1737 | } |
1738 | } |
1739 | } |
1740 | |
1741 | QT_END_NAMESPACE |
1742 | |