Qt 4.8
Namespaces | Typedefs | Functions
qxsdparticlechecker.cpp File Reference
#include "qxsdparticlechecker_p.h"
#include "qxsdelement_p.h"
#include "qxsdmodelgroup_p.h"
#include "qxsdschemahelper_p.h"
#include "qxsdstatemachine_p.h"
#include "qxsdstatemachinebuilder_p.h"
#include "qxsdtypechecker_p.h"
#include <QtCore/QFile>

Go to the source code of this file.

Namespaces

 QPatternist
 The namespace for the internal API of QtXmlPatterns.
 

Typedefs

typedef QHash< QXmlName, XsdElement::PtrElementHash
 

Functions

static bool derivedTermValid (const XsdTerm::Ptr &baseTerm, const XsdTerm::Ptr &derivedTerm, const QHash< XsdTerm::Ptr, XsdParticle::Ptr > &particles, const XsdSchemaContext::Ptr &context, QString &errorMsg)
 
static bool hasDuplicatedElementsInternal (const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool, ElementHash &hash, XsdElement::Ptr &conflictingElement)
 
static bool termMatches (const XsdTerm::Ptr &term, const XsdTerm::Ptr &otherTerm, const NamePool::Ptr &namePool)
 

Typedef Documentation

◆ ElementHash

Definition at line 301 of file qxsdparticlechecker.cpp.

Function Documentation

◆ derivedTermValid()

static bool derivedTermValid ( const XsdTerm::Ptr baseTerm,
const XsdTerm::Ptr derivedTerm,
const QHash< XsdTerm::Ptr, XsdParticle::Ptr > &  particles,
const XsdSchemaContext::Ptr context,
QString errorMsg 
)
static

This method is used by the subsumes algorithm to check whether the derivedTerm is validly derived from the baseTerm.

Parameters
baseTermThe term of the base component (type or group).
derivedTermThe term of the derived component (type or group).
particlesA hash to map the passed base and derived term to the particles they belong to.
contextThe schema context.
errorMsgThe error message in the case that an error occurs.

Definition at line 154 of file qxsdparticlechecker.cpp.

Referenced by QPatternist::XsdParticleChecker::subsumes().

155 {
156  const NamePool::Ptr namePool(context->namePool());
157 
158  // find the particles where the base and derived term belongs to
159  const XsdParticle::Ptr baseParticle = particles.value(baseTerm);
160  const XsdParticle::Ptr derivedParticle = particles.value(derivedTerm);
161 
162  // check that an empty particle can not be derived from a non-empty particle
163  if (derivedParticle && baseParticle) {
164  if (XsdSchemaHelper::isParticleEmptiable(derivedParticle) && !XsdSchemaHelper::isParticleEmptiable(baseParticle)) {
165  errorMsg = QtXmlPatterns::tr("Empty particle cannot be derived from non-empty particle.");
166  return false;
167  }
168  }
169 
170  if (baseTerm->isElement()) {
171  const XsdElement::Ptr element(baseTerm);
172 
173  if (derivedTerm->isElement()) {
174  // if both terms are elements
175 
176  const XsdElement::Ptr derivedElement(derivedTerm);
177 
178  // check names are equal
179  if (element->name(namePool) != derivedElement->name(namePool)) {
180  errorMsg = QtXmlPatterns::tr("Derived particle is missing element %1.").arg(formatKeyword(element->displayName(namePool)));
181  return false;
182  }
183 
184  // check value constraints are equal (if available)
185  if (element->valueConstraint() && element->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) {
186  if (!derivedElement->valueConstraint()) {
187  errorMsg = QtXmlPatterns::tr("Derived element %1 is missing value constraint as defined in base particle.").arg(formatKeyword(derivedElement->displayName(namePool)));
188  return false;
189  }
190 
191  if (derivedElement->valueConstraint()->variety() != XsdElement::ValueConstraint::Fixed) {
192  errorMsg = QtXmlPatterns::tr("Derived element %1 has weaker value constraint than base particle.").arg(formatKeyword(derivedElement->displayName(namePool)));
193  return false;
194  }
195 
196  const QSourceLocation dummyLocation(QUrl(QLatin1String("http://dummy.org")), 1, 1);
197  const XsdTypeChecker checker(context, QVector<QXmlName>(), dummyLocation);
198  if (!checker.valuesAreEqual(element->valueConstraint()->value(), derivedElement->valueConstraint()->value(), derivedElement->type())) {
199  errorMsg = QtXmlPatterns::tr("Fixed value constraint of element %1 differs from value constraint in base particle.").arg(formatKeyword(derivedElement->displayName(namePool)));
200  return false;
201  }
202  }
203 
204  // check that a derived element can not be nillable if the base element is not nillable
205  if (!element->isNillable() && derivedElement->isNillable()) {
206  errorMsg = QtXmlPatterns::tr("Derived element %1 cannot be nillable as base element is not nillable.").arg(formatKeyword(derivedElement->displayName(namePool)));
207  return false;
208  }
209 
210  // check that the constraints of the derived element are more strict then the constraints of the base element
211  const XsdElement::BlockingConstraints baseConstraints = element->disallowedSubstitutions();
212  const XsdElement::BlockingConstraints derivedConstraints = derivedElement->disallowedSubstitutions();
213  if (((baseConstraints & XsdElement::RestrictionConstraint) && !(derivedConstraints & XsdElement::RestrictionConstraint)) ||
214  ((baseConstraints & XsdElement::ExtensionConstraint) && !(derivedConstraints & XsdElement::ExtensionConstraint)) ||
215  ((baseConstraints & XsdElement::SubstitutionConstraint) && !(derivedConstraints & XsdElement::SubstitutionConstraint))) {
216  errorMsg = QtXmlPatterns::tr("Block constraints of derived element %1 must not be more weaker than in the base element.").arg(formatKeyword(derivedElement->displayName(namePool)));
217  return false;
218  }
219 
220  // if the type of both elements is the same we can stop testing here
221  if (element->type()->name(namePool) == derivedElement->type()->name(namePool))
222  return true;
223 
224  // check that the type of the derived element can validly derived from the type of the base element
225  if (derivedElement->type()->isSimpleType()) {
226  if (!XsdSchemaHelper::isSimpleDerivationOk(derivedElement->type(), element->type(), SchemaType::DerivationConstraints())) {
227  errorMsg = QtXmlPatterns::tr("Simple type of derived element %1 cannot be validly derived from base element.").arg(formatKeyword(derivedElement->displayName(namePool)));
228  return false;
229  }
230  } else if (derivedElement->type()->isComplexType()) {
231  if (!XsdSchemaHelper::isComplexDerivationOk(derivedElement->type(), element->type(), SchemaType::DerivationConstraints())) {
232  errorMsg = QtXmlPatterns::tr("Complex type of derived element %1 cannot be validly derived from base element.").arg(formatKeyword(derivedElement->displayName(namePool)));
233  return false;
234  }
235  }
236 
237  // if both, derived and base element, have a complex type that contains a particle itself, apply the subsumes algorithm
238  // recursive on their particles
239  if (element->type()->isComplexType() && derivedElement->type()->isComplexType()) {
240  if (element->type()->isDefinedBySchema() && derivedElement->type()->isDefinedBySchema()) {
241  const XsdComplexType::Ptr baseType(element->type());
242  const XsdComplexType::Ptr derivedType(derivedElement->type());
243  if ((baseType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly ||
244  baseType->contentType()->variety() == XsdComplexType::ContentType::Mixed) &&
245  (derivedType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly ||
246  derivedType->contentType()->variety() == XsdComplexType::ContentType::Mixed)) {
247 
248  return XsdParticleChecker::subsumes(baseType->contentType()->particle(), derivedType->contentType()->particle(), context, errorMsg);
249  }
250  }
251  }
252 
253  return true;
254  } else if (derivedTerm->isWildcard()) {
255  // derive a wildcard from an element is not allowed
256  errorMsg = QtXmlPatterns::tr("Element %1 is missing in derived particle.").arg(formatKeyword(element->displayName(namePool)));
257  return false;
258  }
259  } else if (baseTerm->isWildcard()) {
260  const XsdWildcard::Ptr wildcard(baseTerm);
261 
262  if (derivedTerm->isElement()) {
263  // the base term is a wildcard and derived term an element
264 
265  const XsdElement::Ptr derivedElement(derivedTerm);
266 
267  // wildcards using XsdWildcard::absentNamespace, so we have to fix that here
268  QXmlName name = derivedElement->name(namePool);
269  if (name.namespaceURI() == StandardNamespaces::empty)
270  name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace()));
271 
272  // check that name of the element is allowed by the wildcards namespace constraint
273  if (!XsdSchemaHelper::wildcardAllowsExpandedName(name, wildcard, namePool)) {
274  errorMsg = QtXmlPatterns::tr("Element %1 does not match namespace constraint of wildcard in base particle.").arg(formatKeyword(derivedElement->displayName(namePool)));
275  return false;
276  }
277 
278  } else if (derivedTerm->isWildcard()) {
279  // both, derived and base term are wildcards
280 
281  const XsdWildcard::Ptr derivedWildcard(derivedTerm);
282 
283  // check that the derived wildcard is a valid subset of the base wildcard
284  if (!XsdSchemaHelper::isWildcardSubset(derivedWildcard, wildcard)) {
285  errorMsg = QtXmlPatterns::tr("Wildcard in derived particle is not a valid subset of wildcard in base particle.");
286  return false;
287  }
288 
289  if (!XsdSchemaHelper::checkWildcardProcessContents(wildcard, derivedWildcard)) {
290  errorMsg = QtXmlPatterns::tr("processContent of wildcard in derived particle is weaker than wildcard in base particle.");
291  return false;
292  }
293  }
294 
295  return true;
296  }
297 
298  return false;
299 }
static QString formatKeyword(const VariableDeclaration::Ptr &var, const NamePool::Ptr &np)
Formats var appropriately for display.
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
virtual NamePool::Ptr namePool() const
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
virtual bool isWildcard() const
Definition: qxsdterm.cpp:58
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
virtual bool isElement() const
Definition: qxsdterm.cpp:48
const char * name
The QSourceLocation class identifies a location in a resource by URI, line, and column.
NamespaceCode namespaceURI() const
Definition: qnamepool_p.h:503
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
The QXmlName class represents the name of an XML node, in an efficient, namespace-aware way...
Definition: qxmlname.h:58
The class that provides methods for checking a string against a type.
void setNamespaceURI(const NamespaceCode c)
Definition: qnamepool_p.h:518

◆ hasDuplicatedElementsInternal()

static bool hasDuplicatedElementsInternal ( const XsdParticle::Ptr particle,
const NamePool::Ptr namePool,
ElementHash hash,
XsdElement::Ptr conflictingElement 
)
static

Internal helper method that checks if the given particle contains an element with the same name and type twice.

Definition at line 307 of file qxsdparticlechecker.cpp.

Referenced by QPatternist::XsdParticleChecker::hasDuplicatedElements().

308 {
309  const XsdTerm::Ptr term = particle->term();
310  if (term->isElement()) {
311  const XsdElement::Ptr mainElement(term);
312  XsdElement::WeakList substGroups = mainElement->substitutionGroups();
313  if (substGroups.isEmpty())
314  substGroups << mainElement.data();
315 
316  for (int i = 0; i < substGroups.count(); ++i) {
317  const XsdElement::Ptr element(substGroups.at(i));
318  if (hash.contains(element->name(namePool))) {
319  if (element->type()->name(namePool) != hash.value(element->name(namePool))->type()->name(namePool)) {
320  conflictingElement = element;
321  return true;
322  }
323  } else {
324  hash.insert(element->name(namePool), element);
325  }
326  }
327  } else if (term->isModelGroup()) {
328  const XsdModelGroup::Ptr group(term);
329  const XsdParticle::List particles = group->particles();
330  for (int i = 0; i < particles.count(); ++i) {
331  if (hasDuplicatedElementsInternal(particles.at(i), namePool, hash, conflictingElement))
332  return true;
333  }
334  }
335 
336  return false;
337 }
static uint hash(const uchar *p, int n)
Definition: qhash.cpp:68
int type
Definition: qmetatype.cpp:239
XsdTerm::Ptr term() const
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
bool contains(const Key &key) const
Returns true if the hash contains an item with the key; otherwise returns false.
Definition: qhash.h:872
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
virtual bool isElement() const
Definition: qxsdterm.cpp:48
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
virtual bool isModelGroup() const
Definition: qxsdterm.cpp:53
static bool hasDuplicatedElementsInternal(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool, ElementHash &hash, XsdElement::Ptr &conflictingElement)
The QList class is a template class that provides lists.
Definition: qdatastream.h:62

◆ termMatches()

static bool termMatches ( const XsdTerm::Ptr term,
const XsdTerm::Ptr otherTerm,
const NamePool::Ptr namePool 
)
static

This method is used by the isUPAConform method to check whether term and otherTerm are the same resp. match each other.

Definition at line 84 of file qxsdparticlechecker.cpp.

Referenced by QPatternist::XsdParticleChecker::isUPAConform(), and QPatternist::XsdParticleChecker::isUPAConformXsdAll().

85 {
86  if (term->isElement()) {
87  const XsdElement::Ptr element(term);
88 
89  if (otherTerm->isElement()) {
90  // both, the term and the other term are elements
91 
92  const XsdElement::Ptr otherElement(otherTerm);
93 
94  // if they have the same name they match
95  if (element->name(namePool) == otherElement->name(namePool))
96  return true;
97 
98  } else if (otherTerm->isWildcard()) {
99  // the term is an element and the other term a wildcard
100 
101  const XsdWildcard::Ptr wildcard(otherTerm);
102 
103  // wildcards using XsdWildcard::absentNamespace, so we have to fix that here
104  QXmlName name = element->name(namePool);
105  if (name.namespaceURI() == StandardNamespaces::empty)
106  name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace()));
107 
108  // if the wildcards namespace constraint allows the elements name, they match
109  if (XsdSchemaHelper::wildcardAllowsExpandedName(name, wildcard, namePool))
110  return true;
111  }
112  } else if (term->isWildcard()) {
113  const XsdWildcard::Ptr wildcard(term);
114 
115  if (otherTerm->isElement()) {
116  // the term is a wildcard and the other term an element
117 
118  const XsdElement::Ptr otherElement(otherTerm);
119 
120  // wildcards using XsdWildcard::absentNamespace, so we have to fix that here
121  QXmlName name = otherElement->name(namePool);
122  if (name.namespaceURI() == StandardNamespaces::empty)
123  name.setNamespaceURI(namePool->allocateNamespace(XsdWildcard::absentNamespace()));
124 
125  // if the wildcards namespace constraint allows the elements name, they match
126  if (XsdSchemaHelper::wildcardAllowsExpandedName(name, wildcard, namePool))
127  return true;
128 
129  } else if (otherTerm->isWildcard()) {
130  // both, the term and the other term are wildcards
131 
132  const XsdWildcard::Ptr otherWildcard(otherTerm);
133 
134  // check if the range of the wildcard overlaps.
135  const XsdWildcard::Ptr intersectionWildcard = XsdSchemaHelper::wildcardIntersection(wildcard, otherWildcard);
136  if (!intersectionWildcard ||
137  (intersectionWildcard && !(intersectionWildcard->namespaceConstraint()->variety() != XsdWildcard::NamespaceConstraint::Not && intersectionWildcard->namespaceConstraint()->namespaces().isEmpty())))
138  return true;
139  }
140  }
141 
142  return false;
143 }
QXmlName::NamespaceCode allocateNamespace(const QString &uri)
Definition: qnamepool_p.h:202
virtual bool isWildcard() const
Definition: qxsdterm.cpp:58
virtual bool isElement() const
Definition: qxsdterm.cpp:48
const char * name
NamespaceCode namespaceURI() const
Definition: qnamepool_p.h:503
NamespaceConstraint::Ptr namespaceConstraint() const
The QXmlName class represents the name of an XML node, in an efficient, namespace-aware way...
Definition: qxmlname.h:58
void setNamespaceURI(const NamespaceCode c)
Definition: qnamepool_p.h:518