bool XsdSchemaChecker::particleEqualsRecursively(const XsdParticle::Ptr &particle, const XsdParticle::Ptr &otherParticle) const { // @see http://www.w3.org/TR/xmlschema11-1/#cos-particle-extend //TODO: find out what 'properties' of a particle should be checked here... if (particle->minimumOccurs() != otherParticle->minimumOccurs()) return false; if (particle->maximumOccursUnbounded() != otherParticle->maximumOccursUnbounded()) return false; if (particle->maximumOccurs() != otherParticle->maximumOccurs()) return false; const XsdTerm::Ptr term = particle->term(); const XsdTerm::Ptr otherTerm = otherParticle->term(); if (term->isElement() && !(otherTerm->isElement())) return false; if (term->isModelGroup() && !(otherTerm->isModelGroup())) return false; if (term->isWildcard() && !(otherTerm->isWildcard())) return false; if (term->isElement()) { const XsdElement::Ptr element = term; const XsdElement::Ptr otherElement = otherTerm; if (element->name(m_namePool) != otherElement->name(m_namePool)) return false; if (element->type()->name(m_namePool) != otherElement->type()->name(m_namePool)) return false; } if (term->isModelGroup()) { const XsdModelGroup::Ptr group = term; const XsdModelGroup::Ptr otherGroup = otherTerm; if (group->particles().count() != otherGroup->particles().count()) return false; for (int i = 0; i < group->particles().count(); ++i) { if (!particleEqualsRecursively(group->particles().at(i), otherGroup->particles().at(i))) return false; } } if (term->isWildcard()) { } return true; }
/** * Internal helper method that checks if the given @p particle contains an element with the * same name and type twice. */ static bool hasDuplicatedElementsInternal(const XsdParticle::Ptr &particle, const NamePool::Ptr &namePool, ElementHash &hash, XsdElement::Ptr &conflictingElement) { const XsdTerm::Ptr term = particle->term(); if (term->isElement()) { const XsdElement::Ptr mainElement(term); XsdElement::WeakList substGroups = mainElement->substitutionGroups(); if (substGroups.isEmpty()) substGroups << mainElement.data(); for (int i = 0; i < substGroups.count(); ++i) { const XsdElement::Ptr element(substGroups.at(i)); if (hash.contains(element->name(namePool))) { if (element->type()->name(namePool) != hash.value(element->name(namePool))->type()->name(namePool)) { conflictingElement = element; return true; } } else { hash.insert(element->name(namePool), element); } } } else if (term->isModelGroup()) { const XsdModelGroup::Ptr group(term); const XsdParticle::List particles = group->particles(); for (int i = 0; i < particles.count(); ++i) { if (hasDuplicatedElementsInternal(particles.at(i), namePool, hash, conflictingElement)) return true; } } return false; }
QSet<XsdElement::Ptr> collectAllElements(const XsdParticle::Ptr &particle) { QSet<XsdElement::Ptr> elements; const XsdTerm::Ptr term(particle->term()); if (term->isElement()) { elements.insert(XsdElement::Ptr(term)); } else if (term->isModelGroup()) { const XsdModelGroup::Ptr group(term); for (int i = 0; i < group->particles().count(); ++i) elements.unite(collectAllElements(group->particles().at(i))); } return elements; }
/* * Create the FSA according to Algorithm Tt(S) from http://www.ltg.ed.ac.uk/~ht/XML_Europe_2003.html */ XsdStateMachine<XsdTerm::Ptr>::StateId XsdStateMachineBuilder::buildTerm(const XsdTerm::Ptr &term, XsdStateMachine<XsdTerm::Ptr>::StateId endState) { if (term->isWildcard()) { // 1 const XsdStateMachine<XsdTerm::Ptr>::StateId b = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); m_stateMachine->addTransition(b, term, endState); return b; } else if (term->isElement()) { // 2 const XsdStateMachine<XsdTerm::Ptr>::StateId b = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); m_stateMachine->addTransition(b, term, endState); const XsdElement::Ptr element(term); if (m_mode == CheckingMode) { const XsdElement::WeakList substGroups = element->substitutionGroups(); for (int i = 0; i < substGroups.count(); ++i) m_stateMachine->addTransition(b, XsdElement::Ptr(substGroups.at(i)), endState); } else if (m_mode == ValidatingMode) { const XsdElement::WeakList substGroups = element->substitutionGroups(); for (int i = 0; i < substGroups.count(); ++i) { if (XsdSchemaHelper::substitutionGroupOkTransitive(element, XsdElement::Ptr(substGroups.at(i)), m_namePool)) m_stateMachine->addTransition(b, XsdElement::Ptr(substGroups.at(i)), endState); } } return b; } else if (term->isModelGroup()) { const XsdModelGroup::Ptr group(term); if (group->compositor() == XsdModelGroup::ChoiceCompositor) { // 3 const XsdStateMachine<XsdTerm::Ptr>::StateId b = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); for (int i = 0; i < group->particles().count(); ++i) { const XsdParticle::Ptr particle(group->particles().at(i)); if (particle->maximumOccurs() != 0) { const XsdStateMachine<XsdTerm::Ptr>::StateId state = buildParticle(particle, endState); m_stateMachine->addEpsilonTransition(b, state); } } return b; } else if (group->compositor() == XsdModelGroup::SequenceCompositor) { // 4 XsdStateMachine<XsdTerm::Ptr>::StateId currentStartState = endState; XsdStateMachine<XsdTerm::Ptr>::StateId currentEndState = endState; for (int i = (group->particles().count() - 1); i >= 0; --i) { // iterate reverse const XsdParticle::Ptr particle(group->particles().at(i)); if (particle->maximumOccurs() != 0) { currentStartState = buildParticle(particle, currentEndState); currentEndState = currentStartState; } } return currentStartState; } else if (group->compositor() == XsdModelGroup::AllCompositor) { const XsdStateMachine<XsdTerm::Ptr>::StateId newStartState = m_stateMachine->addState(XsdStateMachine<XsdTerm::Ptr>::InternalState); const QList<XsdParticle::List> list = allCombinations(group->particles()); for (int i = 0; i < list.count(); ++i) { XsdStateMachine<XsdTerm::Ptr>::StateId currentStartState = endState; XsdStateMachine<XsdTerm::Ptr>::StateId currentEndState = endState; const XsdParticle::List particles = list.at(i); for (int j = (particles.count() - 1); j >= 0; --j) { // iterate reverse const XsdParticle::Ptr particle(particles.at(j)); if (particle->maximumOccurs() != 0) { currentStartState = buildParticle(particle, currentEndState); currentEndState = currentStartState; } } m_stateMachine->addEpsilonTransition(newStartState, currentStartState); } if (list.isEmpty()) return endState; else return newStartState; } } Q_ASSERT(false); return 0; }