|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 QT_BEGIN_NAMESPACE |
|
43 |
|
44 using namespace QPatternist; |
|
45 |
|
46 bool XsdSchemaChecker::hasDuplicatedAttributeUses(const XsdAttributeUse::List &list, XsdAttribute::Ptr &conflictingAttribute) const |
|
47 { |
|
48 const int length = list.count(); |
|
49 |
|
50 for (int i = 0; i < length; ++i) { |
|
51 for (int j = 0; j < length; ++j) { |
|
52 if (i == j) |
|
53 continue; |
|
54 |
|
55 if (list.at(i)->attribute()->name(m_namePool) == list.at(j)->attribute()->name(m_namePool)) { |
|
56 conflictingAttribute = list.at(i)->attribute(); |
|
57 return true; |
|
58 } |
|
59 } |
|
60 } |
|
61 |
|
62 return false; |
|
63 } |
|
64 |
|
65 bool XsdSchemaChecker::hasMultipleIDAttributeUses(const XsdAttributeUse::List &list) const |
|
66 { |
|
67 const int length = list.count(); |
|
68 |
|
69 bool hasIdDerivedAttribute = false; |
|
70 for (int i = 0; i < length; ++i) { |
|
71 if (BuiltinTypes::xsID->wxsTypeMatches(list.at(i)->attribute()->type())) { |
|
72 if (hasIdDerivedAttribute) |
|
73 return true; |
|
74 else |
|
75 hasIdDerivedAttribute = true; |
|
76 } |
|
77 } |
|
78 |
|
79 return false; |
|
80 } |
|
81 |
|
82 bool XsdSchemaChecker::hasConstraintIDAttributeUse(const XsdAttributeUse::List &list, XsdAttribute::Ptr &conflictingAttribute) const |
|
83 { |
|
84 const int length = list.count(); |
|
85 |
|
86 for (int i = 0; i < length; ++i) { |
|
87 const XsdAttributeUse::Ptr attributeUse(list.at(i)); |
|
88 if (BuiltinTypes::xsID->wxsTypeMatches(attributeUse->attribute()->type())) { |
|
89 if (attributeUse->valueConstraint()) { |
|
90 conflictingAttribute = attributeUse->attribute(); |
|
91 return true; |
|
92 } |
|
93 } |
|
94 } |
|
95 |
|
96 return false; |
|
97 } |
|
98 |
|
99 bool XsdSchemaChecker::particleEqualsRecursively(const XsdParticle::Ptr &particle, const XsdParticle::Ptr &otherParticle) const |
|
100 { |
|
101 // @see http://www.w3.org/TR/xmlschema11-1/#cos-particle-extend |
|
102 //TODO: find out what 'properties' of a particle should be checked here... |
|
103 |
|
104 if (particle->minimumOccurs() != otherParticle->minimumOccurs()) |
|
105 return false; |
|
106 |
|
107 if (particle->maximumOccursUnbounded() != otherParticle->maximumOccursUnbounded()) |
|
108 return false; |
|
109 |
|
110 if (particle->maximumOccurs() != otherParticle->maximumOccurs()) |
|
111 return false; |
|
112 |
|
113 const XsdTerm::Ptr term = particle->term(); |
|
114 const XsdTerm::Ptr otherTerm = otherParticle->term(); |
|
115 |
|
116 if (term->isElement() && !(otherTerm->isElement())) |
|
117 return false; |
|
118 |
|
119 if (term->isModelGroup() && !(otherTerm->isModelGroup())) |
|
120 return false; |
|
121 |
|
122 if (term->isWildcard() && !(otherTerm->isWildcard())) |
|
123 return false; |
|
124 |
|
125 if (term->isElement()) { |
|
126 const XsdElement::Ptr element = term; |
|
127 const XsdElement::Ptr otherElement = otherTerm; |
|
128 |
|
129 if (element->name(m_namePool) != otherElement->name(m_namePool)) |
|
130 return false; |
|
131 |
|
132 if (element->type()->name(m_namePool) != otherElement->type()->name(m_namePool)) |
|
133 return false; |
|
134 } |
|
135 |
|
136 if (term->isModelGroup()) { |
|
137 const XsdModelGroup::Ptr group = term; |
|
138 const XsdModelGroup::Ptr otherGroup = otherTerm; |
|
139 |
|
140 if (group->particles().count() != otherGroup->particles().count()) |
|
141 return false; |
|
142 |
|
143 for (int i = 0; i < group->particles().count(); ++i) { |
|
144 if (!particleEqualsRecursively(group->particles().at(i), otherGroup->particles().at(i))) |
|
145 return false; |
|
146 } |
|
147 } |
|
148 |
|
149 if (term->isWildcard()) { |
|
150 } |
|
151 |
|
152 return true; |
|
153 } |
|
154 |
|
155 bool XsdSchemaChecker::isValidParticleExtension(const XsdParticle::Ptr &extension, const XsdParticle::Ptr &base) const |
|
156 { |
|
157 // @see http://www.w3.org/TR/xmlschema11-1/#cos-particle-extend |
|
158 |
|
159 // 1 |
|
160 if (extension == base) |
|
161 return true; |
|
162 |
|
163 // 2 |
|
164 if (extension->minimumOccurs() == 1 && extension->maximumOccurs() == 1 && extension->maximumOccursUnbounded() == false) { |
|
165 if (extension->term()->isModelGroup()) { |
|
166 const XsdModelGroup::Ptr modelGroup = extension->term(); |
|
167 if (modelGroup->compositor() == XsdModelGroup::SequenceCompositor) { |
|
168 if (particleEqualsRecursively(modelGroup->particles().first(), base)) |
|
169 return true; |
|
170 } |
|
171 } |
|
172 } |
|
173 |
|
174 // 3 |
|
175 if (extension->minimumOccurs() == base->minimumOccurs()) { // 3.1 |
|
176 if (extension->term()->isModelGroup() && base->term()->isModelGroup()) { |
|
177 const XsdModelGroup::Ptr extensionGroup(extension->term()); |
|
178 const XsdModelGroup::Ptr baseGroup(base->term()); |
|
179 |
|
180 if (extensionGroup->compositor() == XsdModelGroup::AllCompositor && baseGroup->compositor() == XsdModelGroup::AllCompositor) { |
|
181 const XsdParticle::List extensionParticles = extensionGroup->particles(); |
|
182 const XsdParticle::List baseParticles = baseGroup->particles(); |
|
183 for (int i = 0; i < baseParticles.count() && i < extensionParticles.count(); ++i) { |
|
184 if (baseParticles.at(i) != extensionParticles.at(i)) |
|
185 return false; |
|
186 } |
|
187 } |
|
188 } |
|
189 } |
|
190 |
|
191 return false; |
|
192 } |
|
193 |
|
194 QSet<XsdElement::Ptr> collectAllElements(const XsdParticle::Ptr &particle) |
|
195 { |
|
196 QSet<XsdElement::Ptr> elements; |
|
197 |
|
198 const XsdTerm::Ptr term(particle->term()); |
|
199 if (term->isElement()) { |
|
200 elements.insert(XsdElement::Ptr(term)); |
|
201 } else if (term->isModelGroup()) { |
|
202 const XsdModelGroup::Ptr group(term); |
|
203 |
|
204 for (int i = 0; i < group->particles().count(); ++i) |
|
205 elements.unite(collectAllElements(group->particles().at(i))); |
|
206 } |
|
207 |
|
208 return elements; |
|
209 } |
|
210 |
|
211 QSet<XsdElement::Ptr> collectAllElements(const XsdSchema::Ptr &schema) |
|
212 { |
|
213 QSet<XsdElement::Ptr> elements; |
|
214 |
|
215 // collect global elements |
|
216 const XsdElement::List elementList = schema->elements(); |
|
217 for (int i = 0; i < elementList.count(); ++i) |
|
218 elements.insert(elementList.at(i)); |
|
219 |
|
220 // collect all elements from global groups |
|
221 const XsdModelGroup::List groupList = schema->elementGroups(); |
|
222 for (int i = 0; i < groupList.count(); ++i) { |
|
223 const XsdModelGroup::Ptr group(groupList.at(i)); |
|
224 |
|
225 for (int j = 0; j < group->particles().count(); ++j) |
|
226 elements.unite(collectAllElements(group->particles().at(j))); |
|
227 } |
|
228 |
|
229 // collect all elements from complex type definitions |
|
230 SchemaType::List types; |
|
231 types << schema->types() << schema->anonymousTypes(); |
|
232 |
|
233 for (int i = 0; i < types.count(); ++i) { |
|
234 if (types.at(i)->isComplexType() && types.at(i)->isDefinedBySchema()) { |
|
235 const XsdComplexType::Ptr complexType(types.at(i)); |
|
236 if (complexType->contentType()->particle()) |
|
237 elements.unite(collectAllElements(complexType->contentType()->particle())); |
|
238 } |
|
239 } |
|
240 |
|
241 return elements; |
|
242 } |
|
243 |
|
244 bool XsdSchemaChecker::elementSequenceAccepted(const XsdModelGroup::Ptr &sequence, const XsdParticle::Ptr &particle) const |
|
245 { |
|
246 // @see http://www.w3.org/TR/xmlschema11-1/#cvc-accept |
|
247 |
|
248 if (particle->term()->isWildcard()) { // 1 |
|
249 const XsdWildcard::Ptr wildcard(particle->term()); |
|
250 |
|
251 // 1.1 |
|
252 if ((unsigned int)sequence->particles().count() < particle->minimumOccurs()) |
|
253 return false; |
|
254 |
|
255 // 1.2 |
|
256 if (!particle->maximumOccursUnbounded()) { |
|
257 if ((unsigned int)sequence->particles().count() > particle->maximumOccurs()) |
|
258 return false; |
|
259 } |
|
260 |
|
261 // 1.3 |
|
262 const XsdParticle::List particles(sequence->particles()); |
|
263 for (int i = 0; i < particles.count(); ++i) { |
|
264 if (particles.at(i)->term()->isElement()) { |
|
265 if (!XsdSchemaHelper::wildcardAllowsExpandedName(XsdElement::Ptr(particles.at(i)->term())->name(m_namePool), wildcard, m_namePool)) |
|
266 return false; |
|
267 } |
|
268 } |
|
269 } else if (particle->term()->isElement()) { // 2 |
|
270 const XsdElement::Ptr element(particle->term()); |
|
271 |
|
272 // 2.1 |
|
273 if ((unsigned int)sequence->particles().count() < particle->minimumOccurs()) |
|
274 return false; |
|
275 |
|
276 // 2.2 |
|
277 if (!particle->maximumOccursUnbounded()) { |
|
278 if ((unsigned int)sequence->particles().count() > particle->maximumOccurs()) |
|
279 return false; |
|
280 } |
|
281 |
|
282 // 2.3 |
|
283 const XsdParticle::List particles(sequence->particles()); |
|
284 for (int i = 0; i < particles.count(); ++i) { |
|
285 bool isValid = false; |
|
286 if (particles.at(i)->term()->isElement()) { |
|
287 const XsdElement::Ptr seqElement(particles.at(i)->term()); |
|
288 |
|
289 // 2.3.1 |
|
290 if (element->name(m_namePool) == seqElement->name(m_namePool)) |
|
291 isValid = true; |
|
292 |
|
293 // 2.3.2 |
|
294 if (element->scope() && element->scope()->variety() == XsdElement::Scope::Global) { |
|
295 if (!(element->disallowedSubstitutions() & NamedSchemaComponent::SubstitutionConstraint)) { |
|
296 //TODO: continue |
|
297 } |
|
298 } |
|
299 } |
|
300 } |
|
301 } |
|
302 |
|
303 return true; |
|
304 } |
|
305 |
|
306 QT_END_NAMESPACE |