Qt 4.8
Static Public Functions | List of all members
QPatternist::XsdParticleChecker Class Reference

A helper class to check validity of particles. More...

#include <qxsdparticlechecker_p.h>

Static Public Functions

static bool hasDuplicatedElements (const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool, XsdElement::Ptr &conflictingElement)
 
static bool isUPAConform (const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool)
 
static bool isUPAConformXsdAll (const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool)
 
static bool subsumes (const XsdParticle::Ptr &particle, const XsdParticle::Ptr &derivedParticle, const XsdSchemaContext::Ptr &context, QString &errorMsg)
 

Detailed Description

A helper class to check validity of particles.

Author
Tobias Koenig tobia.nosp@m.s.ko.nosp@m.enig@.nosp@m.noki.nosp@m.a.com

Definition at line 72 of file qxsdparticlechecker_p.h.

Functions

◆ hasDuplicatedElements()

bool XsdParticleChecker::hasDuplicatedElements ( const XsdParticle::Ptr particle,
const NamePool::Ptr namePool,
XsdElement::Ptr conflictingElement 
)
static

Checks whether the given particle has two or more element declarations with the same name but different type definitions.

Definition at line 339 of file qxsdparticlechecker.cpp.

Referenced by QPatternist::XsdSchemaChecker::checkComplexTypeConstraints().

340 {
342  return hasDuplicatedElementsInternal(particle, namePool, hash, conflictingElement);
343 }
static uint hash(const uchar *p, int n)
Definition: qhash.cpp:68
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
static bool hasDuplicatedElementsInternal(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool, ElementHash &hash, XsdElement::Ptr &conflictingElement)

◆ isUPAConform()

bool XsdParticleChecker::isUPAConform ( const XsdParticle::Ptr particle,
const NamePool::Ptr namePool 
)
static

Checks whether the given particle is valid according the UPA (http://www.w3.org/TR/xmlschema-1/#cos-nonambig) constraint.

In case we encounter an <xsd:all> element, don't construct a state machine, but use the approach described at http://www.w3.org/TR/xmlschema-1/#non-ambig Reason: For n elements inside the <xsd:all>, represented in the NDA, the state machine constructs n! states in the DFA, which does not scale.

The algorithm is implemented like described in http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html#S2.2

Definition at line 345 of file qxsdparticlechecker.cpp.

Referenced by QPatternist::XsdSchemaChecker::checkComplexTypeConstraints().

346 {
347 
354  if (particle->term()->isModelGroup()) {
355  const XsdModelGroup::Ptr group(particle->term());
356  if (group->compositor() == XsdModelGroup::AllCompositor)
357  return isUPAConformXsdAll(particle, namePool);
358  }
359 
364  // create a state machine for the given particle
365  XsdStateMachine<XsdTerm::Ptr> stateMachine(namePool);
366 
367  XsdStateMachineBuilder builder(&stateMachine, namePool);
368  const XsdStateMachine<XsdTerm::Ptr>::StateId endState = builder.reset();
369  const XsdStateMachine<XsdTerm::Ptr>::StateId startState = builder.buildParticle(particle, endState);
370  builder.addStartState(startState);
371 
372 /*
373  static int counter = 0;
374  {
375  QFile file(QString("/tmp/file_upa%1.dot").arg(counter));
376  file.open(QIODevice::WriteOnly);
377  stateMachine.outputGraph(&file, "Base");
378  file.close();
379  }
380  ::system(QString("dot -Tpng /tmp/file_upa%1.dot -o/tmp/file_upa%1.png").arg(counter).toLatin1().data());
381 */
382  const XsdStateMachine<XsdTerm::Ptr> dfa = stateMachine.toDFA();
383 /*
384  {
385  QFile file(QString("/tmp/file_upa%1dfa.dot").arg(counter));
386  file.open(QIODevice::WriteOnly);
387  dfa.outputGraph(&file, "Base");
388  file.close();
389  }
390  ::system(QString("dot -Tpng /tmp/file_upa%1dfa.dot -o/tmp/file_upa%1dfa.png").arg(counter).toLatin1().data());
391 */
394 
395  // the basic idea of that algorithm is to iterate over all states of that machine and check that no two edges
396  // that match on the same term leave a state, so for a given term it should always be obvious which edge to take
397  QHashIterator<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> stateIt(states);
398  while (stateIt.hasNext()) { // iterate over all states
399  stateIt.next();
400 
401  // fetch all transitions the current state allows
402  const QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > currentTransitions = transitions.value(stateIt.key());
403  QHashIterator<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > transitionIt(currentTransitions);
404  while (transitionIt.hasNext()) { // iterate over all transitions
405  transitionIt.next();
406 
407  if (transitionIt.value().size() > 1) {
408  // we have one state with two edges leaving it, that means
409  // the XsdTerm::Ptr exists twice, that is an error
410  return false;
411  }
412 
413  QHashIterator<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > innerTransitionIt(currentTransitions);
414  while (innerTransitionIt.hasNext()) { // iterate over all transitions again, as we have to compare all transitions with all
415  innerTransitionIt.next();
416 
417  if (transitionIt.key() == innerTransitionIt.key()) // do no compare with ourself
418  continue;
419 
420  // use the helper method termMatches to check if both term matches
421  if (termMatches(transitionIt.key(), innerTransitionIt.key(), namePool))
422  return false;
423  }
424  }
425  }
426 
427  return true;
428 }
XsdStateMachine< TransitionType > toDFA() const
XsdTerm::Ptr term() const
The model group contains elements only.
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
static bool termMatches(const XsdTerm::Ptr &term, const XsdTerm::Ptr &otherTerm, const NamePool::Ptr &namePool)
QHash< StateId, StateType > states() const
static bool isUPAConformXsdAll(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool)
QHash< StateId, QHash< TransitionType, QVector< StateId > > > transitions() const
virtual bool isModelGroup() const
Definition: qxsdterm.cpp:53
A state machine used for evaluation.
A helper class to build up validation state machines.

◆ isUPAConformXsdAll()

bool XsdParticleChecker::isUPAConformXsdAll ( const XsdParticle::Ptr particle,
const NamePool::Ptr namePool 
)
static

Checks whether the given particle, which must be an xsd:all element, is valid according the UPA (http://www.w3.org/TR/xmlschema-1/#cos-nonambig) constraint. For xsd:all elements, we do not want to construct a state machine.

see http://www.w3.org/TR/xmlschema-1/#non-ambig

Definition at line 430 of file qxsdparticlechecker.cpp.

Referenced by isUPAConform().

431 {
435  const XsdModelGroup::Ptr group(particle->term());
436  const XsdParticle::List particles = group->particles();
437  const int count = particles.count();
438  for (int left = 0; left < count; ++left) {
439  for (int right = left+1; right < count; ++right) {
440  if (termMatches(particles.at(left)->term(), particles.at(right)->term(), namePool))
441  return false;
442  }
443  }
444  return true;
445 }
XsdTerm::Ptr term() const
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
static bool termMatches(const XsdTerm::Ptr &term, const XsdTerm::Ptr &otherTerm, const NamePool::Ptr &namePool)
Q_CORE_EXPORT QTextStream & left(QTextStream &s)

◆ subsumes()

bool XsdParticleChecker::subsumes ( const XsdParticle::Ptr particle,
const XsdParticle::Ptr derivedParticle,
const XsdSchemaContext::Ptr context,
QString errorMsg 
)
static

Checks whether the given particle subsumes the given derivedParticle. (http://www.w3.org/TR/xmlschema-1/#cos-particle-restrict)

The algorithm is implemented like described in http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html#S2.3

Definition at line 447 of file qxsdparticlechecker.cpp.

Referenced by QPatternist::XsdSchemaChecker::checkComplexTypeConstraints(), QPatternist::XsdSchemaResolver::checkRedefinedGroups(), and derivedTermValid().

448 {
453  const NamePool::Ptr namePool(context->namePool());
454 
455  XsdStateMachine<XsdTerm::Ptr> baseStateMachine(namePool);
456  XsdStateMachine<XsdTerm::Ptr> derivedStateMachine(namePool);
457 
458  // build up state machines for both particles
459  {
460  XsdStateMachineBuilder builder(&baseStateMachine, namePool);
461  const XsdStateMachine<XsdTerm::Ptr>::StateId endState = builder.reset();
462  const XsdStateMachine<XsdTerm::Ptr>::StateId startState = builder.buildParticle(particle, endState);
463  builder.addStartState(startState);
464 
465  baseStateMachine = baseStateMachine.toDFA();
466  }
467  {
468  XsdStateMachineBuilder builder(&derivedStateMachine, namePool);
469  const XsdStateMachine<XsdTerm::Ptr>::StateId endState = builder.reset();
470  const XsdStateMachine<XsdTerm::Ptr>::StateId startState = builder.buildParticle(derivedParticle, endState);
471  builder.addStartState(startState);
472 
473  derivedStateMachine = derivedStateMachine.toDFA();
474  }
475 
477  particlesHash.unite(XsdStateMachineBuilder::particleLookupMap(derivedParticle));
478 
479 /*
480  static int counter = 0;
481  {
482  QFile file(QString("/tmp/file_base%1.dot").arg(counter));
483  file.open(QIODevice::WriteOnly);
484  baseStateMachine.outputGraph(&file, QLatin1String("Base"));
485  file.close();
486  }
487  {
488  QFile file(QString("/tmp/file_derived%1.dot").arg(counter));
489  file.open(QIODevice::WriteOnly);
490  derivedStateMachine.outputGraph(&file, QLatin1String("Base"));
491  file.close();
492  }
493  ::system(QString("dot -Tpng /tmp/file_base%1.dot -o/tmp/file_base%1.png").arg(counter).toLatin1().data());
494  ::system(QString("dot -Tpng /tmp/file_derived%1.dot -o/tmp/file_derived%1.png").arg(counter).toLatin1().data());
495 */
496 
497  const XsdStateMachine<XsdTerm::Ptr>::StateId baseStartState = baseStateMachine.startState();
498  const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> baseStates = baseStateMachine.states();
500 
501  const XsdStateMachine<XsdTerm::Ptr>::StateId derivedStartState = derivedStateMachine.startState();
502  const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> derivedStates = derivedStateMachine.states();
503  const QHash<XsdStateMachine<XsdTerm::Ptr>::StateId, QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > > derivedTransitions = derivedStateMachine.transitions();
504 
505  // @see http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html#S2.3.1
506 
507  // define working set
510 
511  // 1) fill working set initially with start states
513  processedSet.append(qMakePair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId>(baseStartState, derivedStartState));
514 
515  while (!workSet.isEmpty()) { // while there are state sets to process
516 
517  // 3) dequeue on state set
519 
520  const QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > derivedTrans = derivedTransitions.value(set.second);
521  QHashIterator<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > derivedIt(derivedTrans);
522 
523  const QHash<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > baseTrans = baseTransitions.value(set.first);
524 
525  while (derivedIt.hasNext()) {
526  derivedIt.next();
527 
528  bool found = false;
529  QHashIterator<XsdTerm::Ptr, QVector<XsdStateMachine<XsdTerm::Ptr>::StateId> > baseIt(baseTrans);
530  while (baseIt.hasNext()) {
531  baseIt.next();
532  if (derivedTermValid(baseIt.key(), derivedIt.key(), particlesHash, context, errorMsg)) {
533  const QPair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId> endSet =
534  qMakePair<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateId>(baseIt.value().first(), derivedIt.value().first());
535  if (!processedSet.contains(endSet) && !workSet.contains(endSet)) {
536  workSet.append(endSet);
537  processedSet.append(endSet);
538  }
539 
540  found = true;
541  }
542  }
543 
544  if (!found) {
545  return false;
546  }
547  }
548  }
549 
550  // 5)
551  QHashIterator<XsdStateMachine<XsdTerm::Ptr>::StateId, XsdStateMachine<XsdTerm::Ptr>::StateType> it(derivedStates);
552  while (it.hasNext()) {
553  it.next();
554 
556  for (int i = 0; i < processedSet.count(); ++i) {
557  if (processedSet.at(i).second == it.key() &&
558  (baseStates.value(processedSet.at(i).first) != XsdStateMachine<XsdTerm::Ptr>::EndState &&
559  baseStates.value(processedSet.at(i).first) != XsdStateMachine<XsdTerm::Ptr>::StartEndState)) {
560  errorMsg = QtXmlPatterns::tr("Derived particle allows content that is not allowed in the base particle.");
561  return false;
562  }
563  }
564  }
565  }
566 
567  return true;
568 }
XsdStateMachine< TransitionType > toDFA() const
#define it(className, varName)
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
virtual NamePool::Ptr namePool() const
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
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
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
QBool contains(const T &t) const
Returns true if the list contains an occurrence of value; otherwise returns false.
Definition: qlist.h:880
T takeFirst()
Removes the first item in the list and returns it.
Definition: qlist.h:489
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
static bool derivedTermValid(const XsdTerm::Ptr &baseTerm, const XsdTerm::Ptr &derivedTerm, const QHash< XsdTerm::Ptr, XsdParticle::Ptr > &particles, const XsdSchemaContext::Ptr &context, QString &errorMsg)
Q_OUTOFLINE_TEMPLATE QPair< T1, T2 > qMakePair(const T1 &x, const T2 &y)
Definition: qpair.h:102
A state machine used for evaluation.
static QHash< XsdTerm::Ptr, XsdParticle::Ptr > particleLookupMap(const XsdParticle::Ptr &particle)
A helper class to build up validation state machines.
QHash< Key, T > & unite(const QHash< Key, T > &other)
Inserts all the items in the other hash into this hash.
Definition: qhash.h:556
The QList class is a template class that provides lists.
Definition: qdatastream.h:62

The documentation for this class was generated from the following files: