/** * 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; }
/* * 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; }