src/xmlpatterns/schema/qxsdvalidatinginstancereader.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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 #include "qxsdvalidatinginstancereader_p.h"
       
    43 
       
    44 #include "qabstractdatetime_p.h"
       
    45 #include "qacceltreeresourceloader_p.h"
       
    46 #include "qbase64binary_p.h"
       
    47 #include "qboolean_p.h"
       
    48 #include "qcommonnamespaces_p.h"
       
    49 #include "qderivedinteger_p.h"
       
    50 #include "qduration_p.h"
       
    51 #include "qgenericstaticcontext_p.h"
       
    52 #include "qhexbinary_p.h"
       
    53 #include "qnamespaceresolver_p.h"
       
    54 #include "qpatternplatform_p.h"
       
    55 #include "qqnamevalue_p.h"
       
    56 #include "qsourcelocationreflection_p.h"
       
    57 #include "qvaluefactory_p.h"
       
    58 #include "qxmlnamepool.h"
       
    59 #include "qxmlquery_p.h"
       
    60 #include "qxmlschema_p.h"
       
    61 #include "qxsdschemahelper_p.h"
       
    62 #include "qxsdschemamerger_p.h"
       
    63 #include "qxsdstatemachine_p.h"
       
    64 #include "qxsdstatemachinebuilder_p.h"
       
    65 #include "qxsdtypechecker_p.h"
       
    66 
       
    67 #include "qxsdschemadebugger_p.h"
       
    68 
       
    69 #include <QtCore/QFile>
       
    70 #include <QtXmlPatterns/QXmlQuery>
       
    71 #include <QtXmlPatterns/QXmlResultItems>
       
    72 
       
    73 QT_BEGIN_NAMESPACE
       
    74 
       
    75 using namespace QPatternist;
       
    76 
       
    77 namespace QPatternist
       
    78 {
       
    79     template <>
       
    80     template <>
       
    81     bool XsdStateMachine<XsdTerm::Ptr>::inputEqualsTransition<QXmlName>(QXmlName name, XsdTerm::Ptr term) const
       
    82     {
       
    83         if (term->isElement()) {
       
    84             return (XsdElement::Ptr(term)->name(m_namePool) == name);
       
    85         } else if (term->isWildcard()) {
       
    86             // wildcards using XsdWildcard::absentNamespace, so we have to fix that here
       
    87             if (name.namespaceURI() == StandardNamespaces::empty) {
       
    88                 name.setNamespaceURI(m_namePool->allocateNamespace(XsdWildcard::absentNamespace()));
       
    89             }
       
    90 
       
    91             return XsdSchemaHelper::wildcardAllowsExpandedName(name, XsdWildcard::Ptr(term), m_namePool);
       
    92         }
       
    93 
       
    94         return false;
       
    95     }
       
    96 }
       
    97 
       
    98 XsdValidatingInstanceReader::XsdValidatingInstanceReader(XsdValidatedXmlNodeModel *model, const QUrl &documentUri, const XsdSchemaContext::Ptr &context)
       
    99     : XsdInstanceReader(model, context)
       
   100     , m_model(model)
       
   101     , m_namePool(m_context->namePool())
       
   102     , m_xsiNilName(m_namePool->allocateQName(CommonNamespaces::XSI, QLatin1String("nil")))
       
   103     , m_xsiTypeName(m_namePool->allocateQName(CommonNamespaces::XSI, QLatin1String("type")))
       
   104     , m_xsiSchemaLocationName(m_namePool->allocateQName(CommonNamespaces::XSI, QLatin1String("schemaLocation")))
       
   105     , m_xsiNoNamespaceSchemaLocationName(m_namePool->allocateQName(CommonNamespaces::XSI, QLatin1String("noNamespaceSchemaLocation")))
       
   106     , m_documentUri(documentUri)
       
   107 {
       
   108     m_idRefsType = m_context->schemaTypeFactory()->createSchemaType(m_namePool->allocateQName(CommonNamespaces::WXS, QLatin1String("IDREFS")));
       
   109 }
       
   110 
       
   111 void XsdValidatingInstanceReader::addSchema(const XsdSchema::Ptr &schema, const QUrl &locationUrl)
       
   112 {
       
   113     if (!m_mergedSchemas.contains(locationUrl)) {
       
   114         m_mergedSchemas.insert(locationUrl, QStringList() << schema->targetNamespace());
       
   115     } else {
       
   116         QStringList &targetNamespaces = m_mergedSchemas[locationUrl];
       
   117         if (targetNamespaces.contains(schema->targetNamespace()))
       
   118             return;
       
   119 
       
   120         targetNamespaces.append(schema->targetNamespace());
       
   121     }
       
   122 
       
   123     const XsdSchemaMerger merger(m_schema, schema);
       
   124     m_schema = merger.mergedSchema();
       
   125 /*
       
   126     XsdSchemaDebugger dbg(m_namePool);
       
   127     dbg.dumpSchema(m_schema);
       
   128 */
       
   129 }
       
   130 
       
   131 bool XsdValidatingInstanceReader::read()
       
   132 {
       
   133     while (!atEnd()) {
       
   134         readNext();
       
   135 
       
   136         if (isEndElement())
       
   137             return true;
       
   138 
       
   139         if (isStartElement()) {
       
   140             const QXmlName elementName = name();
       
   141             const QXmlItem currentItem = item();
       
   142             bool hasStateMachine = false;
       
   143             XsdElement::Ptr processedElement;
       
   144 
       
   145             if (!validate(hasStateMachine, processedElement))
       
   146                 return false;
       
   147 
       
   148             read();
       
   149 
       
   150             if (processedElement) { // for wildcard with 'skip' we have no element
       
   151                 m_model->setAssignedElement(currentItem.toNodeModelIndex(), processedElement);
       
   152 
       
   153                 // check identity constraints after all child nodes have been
       
   154                 // validated, so that we know there assigned types
       
   155                 validateIdentityConstraint(processedElement, currentItem);
       
   156             }
       
   157 
       
   158             if (!m_stateMachines.isEmpty() && hasStateMachine) {
       
   159                 if (!m_stateMachines.top().inEndState()) {
       
   160                     error(QtXmlPatterns::tr("Element %1 is missing child element.").arg(formatKeyword(m_namePool->displayName(elementName))));
       
   161                     return false;
       
   162                 }
       
   163                 m_stateMachines.pop();
       
   164             }
       
   165         }
       
   166     }
       
   167 
       
   168     // final validations
       
   169 
       
   170     // check IDREF occurrences
       
   171     const QStringList ids = m_model->idIdRefBindingIds();
       
   172     QSetIterator<QString> it(m_idRefs);
       
   173     while (it.hasNext()) {
       
   174         const QString id = it.next();
       
   175         if (!ids.contains(id)) {
       
   176             error(QtXmlPatterns::tr("There is one IDREF value with no corresponding ID: %1.").arg(formatKeyword(id)));
       
   177             return false;
       
   178         }
       
   179     }
       
   180 
       
   181     return true;
       
   182 }
       
   183 
       
   184 void XsdValidatingInstanceReader::error(const QString &msg) const
       
   185 {
       
   186     m_context.data()->error(msg, XsdSchemaContext::XSDError, sourceLocation());
       
   187 }
       
   188 
       
   189 bool XsdValidatingInstanceReader::loadSchema(const QString &targetNamespace, const QUrl &location)
       
   190 {
       
   191     const AutoPtr<QNetworkReply> reply(AccelTreeResourceLoader::load(location, m_context->networkAccessManager(),
       
   192                                                                      m_context, AccelTreeResourceLoader::ContinueOnError));
       
   193     if (!reply)
       
   194         return true;
       
   195 
       
   196     // we have to create a separated schema context here, that however shares the type factory
       
   197     XsdSchemaContext::Ptr context(new XsdSchemaContext(m_namePool));
       
   198     context->m_schemaTypeFactory = m_context->m_schemaTypeFactory;
       
   199 
       
   200     QXmlSchemaPrivate schema(context);
       
   201     schema.load(reply.data(), location, targetNamespace);
       
   202     if (!schema.isValid()) {
       
   203         error(QtXmlPatterns::tr("Loaded schema file is invalid."));
       
   204         return false;
       
   205     }
       
   206 
       
   207     addSchema(schema.m_schemaParserContext->schema(), location);
       
   208 
       
   209     return true;
       
   210 }
       
   211 
       
   212 bool XsdValidatingInstanceReader::validate(bool &hasStateMachine, XsdElement::Ptr &processedElement)
       
   213 {
       
   214     // first check if a custom schema is defined
       
   215     if (hasAttribute(m_xsiSchemaLocationName)) {
       
   216         const QString schemaLocation = attribute(m_xsiSchemaLocationName);
       
   217         const QStringList parts = schemaLocation.split(QLatin1Char(' '), QString::SkipEmptyParts);
       
   218         if ((parts.count()%2) == 1) {
       
   219             error(QtXmlPatterns::tr("%1 contains invalid data.").arg(formatKeyword(m_namePool, m_xsiSchemaLocationName)));
       
   220             return false;
       
   221         }
       
   222 
       
   223         for (int i = 0; i < parts.count(); i += 2) {
       
   224             const QString identifier = QString::fromLatin1("%1 %2").arg(parts.at(i)).arg(parts.at(i + 1));
       
   225             if (m_processedSchemaLocations.contains(identifier))
       
   226                 continue;
       
   227             else
       
   228                 m_processedSchemaLocations.insert(identifier);
       
   229 
       
   230             // check constraint 4) from http://www.w3.org/TR/xmlschema-1/#schema-loc (only valid for XML Schema 1.0?)
       
   231             if (m_processedNamespaces.contains(parts.at(i))) {
       
   232                 error(QtXmlPatterns::tr("xsi:schemaLocation namespace %1 has already appeared earlier in the instance document.").arg(formatKeyword(parts.at(i))));
       
   233                 return false;
       
   234             }
       
   235 
       
   236             QUrl url(parts.at(i + 1));
       
   237             if (url.isRelative()) {
       
   238                 Q_ASSERT(m_documentUri.isValid());
       
   239 
       
   240                 url = m_documentUri.resolved(url);
       
   241             }
       
   242 
       
   243             loadSchema(parts.at(i), url);
       
   244         }
       
   245     }
       
   246 
       
   247     if (hasAttribute(m_xsiNoNamespaceSchemaLocationName)) {
       
   248         const QString schemaLocation = attribute(m_xsiNoNamespaceSchemaLocationName);
       
   249 
       
   250         if (!m_processedSchemaLocations.contains(schemaLocation)) {
       
   251             m_processedSchemaLocations.insert(schemaLocation);
       
   252 
       
   253             if (m_processedNamespaces.contains(QString())) {
       
   254                 error(QtXmlPatterns::tr("xsi:noNamespaceSchemaLocation cannot appear after the first no-namespace element or attribute."));
       
   255                 return false;
       
   256             }
       
   257 
       
   258             QUrl url(schemaLocation);
       
   259             if (url.isRelative()) {
       
   260                 Q_ASSERT(m_documentUri.isValid());
       
   261 
       
   262                 url = m_documentUri.resolved(url);
       
   263             }
       
   264 
       
   265             loadSchema(QString(), url);
       
   266         }
       
   267     }
       
   268 
       
   269     m_processedNamespaces.insert(m_namePool->stringForNamespace(name().namespaceURI()));
       
   270 
       
   271     if (!m_schema) {
       
   272         error(QtXmlPatterns::tr("No schema defined for validation."));
       
   273         return false;
       
   274     }
       
   275 
       
   276     // check if we are 'inside' a type definition
       
   277     if (m_stateMachines.isEmpty()) {
       
   278         // find out the type of the top-level element
       
   279         XsdElement::Ptr element = elementByName(name());
       
   280         if (!element) {
       
   281             if (!hasAttribute(m_xsiTypeName)) {
       
   282                 error(QtXmlPatterns::tr("No definition for element %1 available.").arg(formatKeyword(m_namePool, name())));
       
   283                 return false;
       
   284             }
       
   285 
       
   286             // This instance document has an element with no definition in the schema
       
   287             // but an explicitly given type, that is fine according to the spec.
       
   288             // We will create an element definition manually here and continue the
       
   289             // normal validation process
       
   290             element = XsdElement::Ptr(new XsdElement());
       
   291             element->setName(name());
       
   292             element->setIsAbstract(false);
       
   293             element->setIsNillable(hasAttribute(m_xsiNilName));
       
   294 
       
   295             const QString type = qNameAttribute(m_xsiTypeName);
       
   296             const QXmlName typeName = convertToQName(type);
       
   297 
       
   298             const SchemaType::Ptr elementType = typeByName(typeName);
       
   299             if (!elementType) {
       
   300                 error(QtXmlPatterns::tr("Specified type %1 is not known to the schema.").arg(formatType(m_namePool, typeName)));
       
   301                 return false;
       
   302             }
       
   303             element->setType(elementType);
       
   304         }
       
   305 
       
   306         // rememeber the element we process
       
   307         processedElement = element;
       
   308 
       
   309         if (!validateElement(element, hasStateMachine)) {
       
   310             return false;
       
   311         }
       
   312 
       
   313     } else {
       
   314         if (!m_stateMachines.top().proceed<QXmlName>(name())) {
       
   315             error(QtXmlPatterns::tr("Element %1 is not defined in this scope.").arg(formatKeyword(m_namePool, name())));
       
   316             return false;
       
   317         }
       
   318 
       
   319         const XsdTerm::Ptr term = m_stateMachines.top().lastTransition();
       
   320         if (term->isElement()) {
       
   321             const XsdElement::Ptr element(term);
       
   322 
       
   323             // rememeber the element we process
       
   324             processedElement = element;
       
   325 
       
   326             if (!validateElement(element, hasStateMachine))
       
   327                 return false;
       
   328 
       
   329         } else {
       
   330             const XsdWildcard::Ptr wildcard(term);
       
   331             if (wildcard->processContents() != XsdWildcard::Skip) {
       
   332                 XsdElement::Ptr elementDeclaration = elementByName(name());
       
   333                 if (!elementDeclaration) {
       
   334                     if (hasAttribute(m_xsiTypeName)) {
       
   335                         // This instance document has an element with no definition in the schema
       
   336                         // but an explicitly given type, that is fine according to the spec.
       
   337                         // We will create an element definition manually here and continue the
       
   338                         // normal validation process
       
   339                         elementDeclaration = XsdElement::Ptr(new XsdElement());
       
   340                         elementDeclaration->setName(name());
       
   341                         elementDeclaration->setIsAbstract(false);
       
   342                         elementDeclaration->setIsNillable(hasAttribute(m_xsiNilName));
       
   343 
       
   344                         const QString type = qNameAttribute(m_xsiTypeName);
       
   345                         const QXmlName typeName = convertToQName(type);
       
   346 
       
   347                         const SchemaType::Ptr elementType = typeByName(typeName);
       
   348                         if (!elementType) {
       
   349                             error(QtXmlPatterns::tr("Specified type %1 is not known to the schema.").arg(formatType(m_namePool, typeName)));
       
   350                             return false;
       
   351                         }
       
   352                         elementDeclaration->setType(elementType);
       
   353                     }
       
   354                 }
       
   355 
       
   356                 if (!elementDeclaration) {
       
   357                     if (wildcard->processContents() == XsdWildcard::Strict) {
       
   358                         error(QtXmlPatterns::tr("Declaration for element %1 does not exist.").arg(formatKeyword(m_namePool->displayName(name()))));
       
   359                         return false;
       
   360                     } else {
       
   361                         // in this case we put a state machine for the xs:anyType on the statemachine stack,
       
   362                         // so we accept every content of this element
       
   363 
       
   364                         createAndPushStateMachine(anyType()->contentType()->particle());
       
   365                         hasStateMachine = true;
       
   366                     }
       
   367                 } else {
       
   368                     if (!validateElement(elementDeclaration, hasStateMachine)) {
       
   369                         if (wildcard->processContents() == XsdWildcard::Strict) {
       
   370                             error(QtXmlPatterns::tr("Element %1 contains invalid content.").arg(formatKeyword(m_namePool->displayName(name()))));
       
   371                             return false;
       
   372                         }
       
   373                     }
       
   374 
       
   375                     // rememeber the type of that element node
       
   376                     m_model->setAssignedType(item().toNodeModelIndex(), elementDeclaration->type());
       
   377                 }
       
   378             } else { // wildcard process contents type is Skip
       
   379                 // in this case we put a state machine for the xs:anyType on the statemachine stack,
       
   380                 // so we accept every content of this element
       
   381 
       
   382                 const XsdWildcard::Ptr wildcard(new XsdWildcard());
       
   383                 wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any);
       
   384                 wildcard->setProcessContents(XsdWildcard::Skip);
       
   385 
       
   386                 const XsdParticle::Ptr outerParticle(new XsdParticle());
       
   387                 outerParticle->setMinimumOccurs(1);
       
   388                 outerParticle->setMaximumOccurs(1);
       
   389 
       
   390                 const XsdParticle::Ptr innerParticle(new XsdParticle());
       
   391                 innerParticle->setMinimumOccurs(0);
       
   392                 innerParticle->setMaximumOccursUnbounded(true);
       
   393                 innerParticle->setTerm(wildcard);
       
   394 
       
   395                 const XsdModelGroup::Ptr outerModelGroup(new XsdModelGroup());
       
   396                 outerModelGroup->setCompositor(XsdModelGroup::SequenceCompositor);
       
   397                 outerModelGroup->setParticles(XsdParticle::List() << innerParticle);
       
   398                 outerParticle->setTerm(outerModelGroup);
       
   399 
       
   400                 createAndPushStateMachine(outerParticle);
       
   401                 hasStateMachine = true;
       
   402             }
       
   403         }
       
   404     }
       
   405 
       
   406     return true;
       
   407 }
       
   408 
       
   409 void XsdValidatingInstanceReader::createAndPushStateMachine(const XsdParticle::Ptr &particle)
       
   410 {
       
   411     XsdStateMachine<XsdTerm::Ptr> stateMachine(m_namePool);
       
   412 
       
   413     XsdStateMachineBuilder builder(&stateMachine, m_namePool, XsdStateMachineBuilder::ValidatingMode);
       
   414     const XsdStateMachine<XsdTerm::Ptr>::StateId endState = builder.reset();
       
   415     const XsdStateMachine<XsdTerm::Ptr>::StateId startState = builder.buildParticle(particle, endState);
       
   416     builder.addStartState(startState);
       
   417 
       
   418 /*
       
   419     QString fileName = QString("/tmp/foo_%1.dot").arg(m_namePool->displayName(complexType->name(m_namePool)));
       
   420     QString pngFileName = QString("/tmp/foo_%1.png").arg(m_namePool->displayName(complexType->name(m_namePool)));
       
   421     QFile file(fileName);
       
   422     file.open(QIODevice::WriteOnly);
       
   423     stateMachine.outputGraph(&file, "Hello");
       
   424     file.close();
       
   425     ::system(QString("dot -Tpng %1 -o%2").arg(fileName).arg(pngFileName).toLatin1().data());
       
   426 */
       
   427 
       
   428     stateMachine = stateMachine.toDFA();
       
   429 
       
   430     m_stateMachines.push(stateMachine);
       
   431 }
       
   432 
       
   433 bool XsdValidatingInstanceReader::validateElement(const XsdElement::Ptr &declaration, bool &hasStateMachine)
       
   434 {
       
   435     // http://www.w3.org/TR/xmlschema11-1/#d0e10998
       
   436 
       
   437     bool isNilled = false;
       
   438 
       
   439     // 1 tested already, 'declaration' corresponds D
       
   440 
       
   441     // 2
       
   442     if (declaration->isAbstract()) {
       
   443         error(QtXmlPatterns::tr("Element %1 is declared as abstract.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   444         return false;
       
   445     }
       
   446 
       
   447     // 3
       
   448     if (!declaration->isNillable()) {
       
   449         if (hasAttribute(m_xsiNilName)) {
       
   450             error(QtXmlPatterns::tr("Element %1 is not nillable.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   451             return false; // 3.1
       
   452         }
       
   453     } else {
       
   454         if (hasAttribute(m_xsiNilName)) {
       
   455             const QString value = attribute(m_xsiNilName);
       
   456             const Boolean::Ptr nil = Boolean::fromLexical(value);
       
   457             if (nil->hasError()) {
       
   458                 error(QtXmlPatterns::tr("Attribute %1 contains invalid data: %2").arg(formatKeyword(QLatin1String("nil."))).arg(formatData(value)));
       
   459                 return false;
       
   460             }
       
   461 
       
   462             // 3.2.3
       
   463             if (nil->as<Boolean>()->value() == true) {
       
   464                 // 3.2.3.1
       
   465                 if (hasChildElement() || hasChildText()) {
       
   466                     error(QtXmlPatterns::tr("Element contains content although it is nillable."));
       
   467                     return false;
       
   468                 }
       
   469 
       
   470                 // 3.2.3.2
       
   471                 if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) {
       
   472                     error(QtXmlPatterns::tr("Fixed value constrained not allowed if element is nillable."));
       
   473                     return false;
       
   474                 }
       
   475             }
       
   476 
       
   477             isNilled = nil->as<Boolean>()->value();
       
   478         }
       
   479     }
       
   480 
       
   481     SchemaType::Ptr finalElementType = declaration->type();
       
   482 
       
   483     // 4
       
   484     if (hasAttribute(m_xsiTypeName)) {
       
   485         const QString type = qNameAttribute(m_xsiTypeName);
       
   486         const QXmlName typeName = convertToQName(type);
       
   487 
       
   488         const SchemaType::Ptr elementType = typeByName(typeName);
       
   489         // 4.1
       
   490         if (!elementType) {
       
   491             error(QtXmlPatterns::tr("Specified type %1 is not known to the schema.").arg(formatType(m_namePool, typeName)));
       
   492             return false;
       
   493         }
       
   494 
       
   495         // 4.2
       
   496         SchemaType::DerivationConstraints constraints = 0;
       
   497         if (declaration->disallowedSubstitutions() & NamedSchemaComponent::ExtensionConstraint)
       
   498             constraints |= SchemaType::ExtensionConstraint;
       
   499         if (declaration->disallowedSubstitutions() & NamedSchemaComponent::RestrictionConstraint)
       
   500             constraints |= SchemaType::RestrictionConstraint;
       
   501 
       
   502         if (!XsdSchemaHelper::isValidlySubstitutable(elementType, declaration->type(), constraints)) {
       
   503             if (declaration->type()->name(m_namePool) != BuiltinTypes::xsAnyType->name(m_namePool)) { // xs:anyType is a valid substitutable type here
       
   504                 error(QtXmlPatterns::tr("Specified type %1 is not validly substitutable with element type %2.").arg(formatType(m_namePool, elementType)).arg(formatType(m_namePool, declaration->type())));
       
   505                 return false;
       
   506             }
       
   507         }
       
   508 
       
   509         finalElementType = elementType;
       
   510     }
       
   511 
       
   512     if (!validateElementType(declaration, finalElementType, isNilled, hasStateMachine))
       
   513         return false;
       
   514 
       
   515     return true;
       
   516 }
       
   517 
       
   518 bool XsdValidatingInstanceReader::validateElementType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled, bool &hasStateMachine)
       
   519 {
       
   520     // @see http://www.w3.org/TR/xmlschema11-1/#d0e11749
       
   521 
       
   522     // 1 checked already
       
   523 
       
   524     // 2
       
   525     if (type->isComplexType() && type->isDefinedBySchema()) {
       
   526         if (XsdComplexType::Ptr(type)->isAbstract()) {
       
   527             error(QtXmlPatterns::tr("Complex type %1 is not allowed to be abstract.").arg(formatType(m_namePool, type)));
       
   528             return false;
       
   529         }
       
   530     }
       
   531 
       
   532     // 3
       
   533     if (type->isSimpleType())
       
   534         return validateElementSimpleType(declaration, type, isNilled); // 3.1
       
   535     else
       
   536         return validateElementComplexType(declaration, type, isNilled, hasStateMachine); // 3.2
       
   537 }
       
   538 
       
   539 bool XsdValidatingInstanceReader::validateElementSimpleType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled)
       
   540 {
       
   541     // @see http://www.w3.org/TR/xmlschema11-1/#d0e11749
       
   542 
       
   543     // 3.1.1
       
   544     const QSet<QXmlName> allowedAttributes(QSet<QXmlName>() << m_xsiNilName << m_xsiTypeName << m_xsiSchemaLocationName << m_xsiNoNamespaceSchemaLocationName);
       
   545     QSet<QXmlName> elementAttributes = attributeNames();
       
   546     elementAttributes.subtract(allowedAttributes);
       
   547     if (!elementAttributes.isEmpty()) {
       
   548         error(QtXmlPatterns::tr("Element %1 contains not allowed attributes.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   549         return false;
       
   550     }
       
   551 
       
   552     // 3.1.2
       
   553     if (hasChildElement()) {
       
   554         error(QtXmlPatterns::tr("Element %1 contains not allowed child element.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   555         return false;
       
   556     }
       
   557 
       
   558     // 3.1.3
       
   559     if (!isNilled) {
       
   560         const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(type, m_context);
       
   561 
       
   562         QString actualValue;
       
   563         if (hasChildText()) {
       
   564             actualValue = XsdTypeChecker::normalizedValue(text(), facets);
       
   565         } else {
       
   566             if (declaration->valueConstraint())
       
   567                 actualValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets);
       
   568         }
       
   569 
       
   570         QString errorMsg;
       
   571         AnySimpleType::Ptr boundType;
       
   572 
       
   573         const XsdTypeChecker checker(m_context, namespaceBindings(item().toNodeModelIndex()), sourceLocation());
       
   574         if (!checker.isValidString(actualValue, type, errorMsg, &boundType)) {
       
   575             error(QtXmlPatterns::tr("Content of element %1 does not match its type definition: %2.").arg(formatKeyword(declaration->displayName(m_namePool))).arg(errorMsg));
       
   576             return false;
       
   577         }
       
   578 
       
   579         // additional check
       
   580         if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) {
       
   581             const QString actualConstraintValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets);
       
   582             if (!text().isEmpty() && !checker.valuesAreEqual(actualValue, actualConstraintValue, type)) {
       
   583                 error(QtXmlPatterns::tr("Content of element %1 does not match defined value constraint.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   584                 return false;
       
   585             }
       
   586         }
       
   587     }
       
   588 
       
   589     // 4  checked in validateElement already
       
   590 
       
   591     // rememeber the type of that element node
       
   592     m_model->setAssignedType(item().toNodeModelIndex(), type);
       
   593 
       
   594     const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(type, m_context);
       
   595     const QString actualValue = XsdTypeChecker::normalizedValue(text(), facets);
       
   596 
       
   597     if (BuiltinTypes::xsID->wxsTypeMatches(type)) {
       
   598         addIdIdRefBinding(actualValue, declaration);
       
   599     }
       
   600 
       
   601     if (m_idRefsType->wxsTypeMatches(type)) {
       
   602         const QStringList idRefs = actualValue.split(QLatin1Char(' '), QString::SkipEmptyParts);
       
   603         for (int i = 0; i < idRefs.count(); ++i) {
       
   604             m_idRefs.insert(idRefs.at(i));
       
   605         }
       
   606     } else if (BuiltinTypes::xsIDREF->wxsTypeMatches(type)) {
       
   607         m_idRefs.insert(actualValue);
       
   608     }
       
   609 
       
   610     return true;
       
   611 }
       
   612 
       
   613 static bool hasIDAttributeUse(const XsdAttributeUse::List &uses)
       
   614 {
       
   615     const int count = uses.count();
       
   616     for (int i = 0; i < count; ++i) {
       
   617         if (BuiltinTypes::xsID->wxsTypeMatches(uses.at(i)->attribute()->type()))
       
   618             return true;
       
   619     }
       
   620 
       
   621     return false;
       
   622 }
       
   623 
       
   624 bool XsdValidatingInstanceReader::validateElementComplexType(const XsdElement::Ptr &declaration, const SchemaType::Ptr &type, bool isNilled, bool &hasStateMachine)
       
   625 {
       
   626     // @see http://www.w3.org/TR/xmlschema11-1/#cvc-complex-type
       
   627 
       
   628     // 1
       
   629     if (!isNilled) {
       
   630         XsdComplexType::Ptr complexType;
       
   631 
       
   632         if (type->isDefinedBySchema()) {
       
   633             complexType = XsdComplexType::Ptr(type);
       
   634         } else {
       
   635             if (type->name(m_namePool) == BuiltinTypes::xsAnyType->name(m_namePool))
       
   636                 complexType = anyType();
       
   637         }
       
   638 
       
   639         if (complexType) {
       
   640             // 1.1
       
   641             if (complexType->contentType()->variety() == XsdComplexType::ContentType::Empty) {
       
   642                 if (hasChildText() || hasChildElement()) {
       
   643                     error(QtXmlPatterns::tr("Element %1 contains not allowed child content.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   644                     return false;
       
   645                 }
       
   646             }
       
   647 
       
   648             // 1.2
       
   649             if (complexType->contentType()->variety() == XsdComplexType::ContentType::Simple) {
       
   650                 if (hasChildElement()) {
       
   651                     error(QtXmlPatterns::tr("Element %1 contains not allowed child element.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   652                     return false;
       
   653                 }
       
   654 
       
   655                 const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(complexType->contentType()->simpleType(), m_context);
       
   656                 QString actualValue;
       
   657                 if (hasChildText()) {
       
   658                     actualValue = XsdTypeChecker::normalizedValue(text(), facets);
       
   659                 } else {
       
   660                     if (declaration->valueConstraint())
       
   661                         actualValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets);
       
   662                 }
       
   663 
       
   664                 QString errorMsg;
       
   665                 AnySimpleType::Ptr boundType;
       
   666                 const XsdTypeChecker checker(m_context, namespaceBindings(item().toNodeModelIndex()), sourceLocation());
       
   667                 if (!checker.isValidString(actualValue, complexType->contentType()->simpleType(), errorMsg, &boundType)) {
       
   668                     error(QtXmlPatterns::tr("Content of element %1 does not match its type definition: %2.").arg(formatKeyword(declaration->displayName(m_namePool))).arg(errorMsg));
       
   669                     return false;
       
   670                 }
       
   671 
       
   672                 // additional check
       
   673                 if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) {
       
   674                     if (!checker.valuesAreEqual(actualValue, declaration->valueConstraint()->value(), boundType)) {
       
   675                         error(QtXmlPatterns::tr("Content of element %1 does not match defined value constraint.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   676                         return false;
       
   677                     }
       
   678                 }
       
   679             }
       
   680 
       
   681             // 1.3
       
   682             if (complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly) {
       
   683                 if (!text().simplified().isEmpty()) {
       
   684                     error(QtXmlPatterns::tr("Element %1 contains not allowed text content.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   685                     return false;
       
   686                 }
       
   687             }
       
   688 
       
   689             // 1.4
       
   690             if (complexType->contentType()->variety() == XsdComplexType::ContentType::ElementOnly ||
       
   691                 complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed) {
       
   692 
       
   693                 if (complexType->contentType()->particle()) {
       
   694                     createAndPushStateMachine(complexType->contentType()->particle());
       
   695                     hasStateMachine = true;
       
   696                 }
       
   697 
       
   698                 // additional check
       
   699                 if (complexType->contentType()->variety() == XsdComplexType::ContentType::Mixed) {
       
   700                     if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdElement::ValueConstraint::Fixed) {
       
   701                         if (hasChildElement()) {
       
   702                             error(QtXmlPatterns::tr("Element %1 can not contain other elements, as it has a fixed content.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   703                             return false;
       
   704                         }
       
   705 
       
   706                         const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(complexType->contentType()->simpleType(), m_context);
       
   707                         QString actualValue;
       
   708                         if (hasChildText()) {
       
   709                             actualValue = XsdTypeChecker::normalizedValue(text(), facets);
       
   710                         } else {
       
   711                             if (declaration->valueConstraint())
       
   712                                 actualValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets);
       
   713                         }
       
   714 
       
   715                         if (actualValue != declaration->valueConstraint()->value()) {
       
   716                             error(QtXmlPatterns::tr("Content of element %1 does not match defined value constraint.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   717                             return false;
       
   718                         }
       
   719                     }
       
   720                 }
       
   721             }
       
   722         }
       
   723     }
       
   724 
       
   725     if (type->isDefinedBySchema()) {
       
   726         const XsdComplexType::Ptr complexType(type);
       
   727 
       
   728         // create a lookup hash for faster access
       
   729         QHash<QXmlName, XsdAttributeUse::Ptr> attributeUseHash;
       
   730         {
       
   731             const XsdAttributeUse::List attributeUses = complexType->attributeUses();
       
   732             for (int i = 0; i < attributeUses.count(); ++i)
       
   733                 attributeUseHash.insert(attributeUses.at(i)->attribute()->name(m_namePool), attributeUses.at(i));
       
   734         }
       
   735 
       
   736         const QSet<QXmlName> attributes(attributeNames());
       
   737 
       
   738         // 3
       
   739         QHashIterator<QXmlName, XsdAttributeUse::Ptr> usesIt(attributeUseHash);
       
   740         while (usesIt.hasNext()) {
       
   741             usesIt.next();
       
   742 
       
   743             if (usesIt.value()->isRequired()) {
       
   744                 if (!attributes.contains(usesIt.key())) {
       
   745                     error(QtXmlPatterns::tr("Element %1 is missing required attribute %2.").arg(formatKeyword(declaration->displayName(m_namePool)))
       
   746                                                                                           .arg(formatKeyword(m_namePool->displayName(usesIt.key()))));
       
   747                     return false;
       
   748                 }
       
   749             }
       
   750         }
       
   751 
       
   752         bool hasIDAttribute = hasIDAttributeUse(complexType->attributeUses());
       
   753 
       
   754         // 2
       
   755         QSetIterator<QXmlName> it(attributes);
       
   756         while (it.hasNext()) {
       
   757             const QXmlName attributeName = it.next();
       
   758 
       
   759             // skip builtin attributes
       
   760             if (attributeName == m_xsiNilName ||
       
   761                 attributeName == m_xsiTypeName ||
       
   762                 attributeName == m_xsiSchemaLocationName ||
       
   763                 attributeName == m_xsiNoNamespaceSchemaLocationName)
       
   764                 continue;
       
   765 
       
   766             // 2.1
       
   767             if (attributeUseHash.contains(attributeName) && (attributeUseHash.value(attributeName)->useType() != XsdAttributeUse::ProhibitedUse)) {
       
   768                 if (!validateAttribute(attributeUseHash.value(attributeName), attribute(attributeName)))
       
   769                     return false;
       
   770             } else { // 2.2
       
   771                 if (complexType->attributeWildcard()) {
       
   772                     const XsdWildcard::Ptr wildcard(complexType->attributeWildcard());
       
   773                     if (!validateAttributeWildcard(attributeName, wildcard)) {
       
   774                         error(QtXmlPatterns::tr("Attribute %1 does not match the attribute wildcard.").arg(formatKeyword(m_namePool->displayName(attributeName))));
       
   775                         return false;
       
   776                     }
       
   777 
       
   778                     if (wildcard->processContents() != XsdWildcard::Skip) {
       
   779                         const XsdAttribute::Ptr attributeDeclaration = attributeByName(attributeName);
       
   780 
       
   781                         if (!attributeDeclaration) {
       
   782                             if (wildcard->processContents() == XsdWildcard::Strict) {
       
   783                                 error(QtXmlPatterns::tr("Declaration for attribute %1 does not exist.").arg(formatKeyword(m_namePool->displayName(attributeName))));
       
   784                                 return false;
       
   785                             }
       
   786                         } else {
       
   787                             if (BuiltinTypes::xsID->wxsTypeMatches(attributeDeclaration->type())) {
       
   788                                 if (hasIDAttribute) {
       
   789                                     error(QtXmlPatterns::tr("Element %1 contains two attributes of type %2.")
       
   790                                                            .arg(formatKeyword(declaration->displayName(m_namePool)))
       
   791                                                            .arg(formatKeyword("ID")));
       
   792                                     return false;
       
   793                                 }
       
   794 
       
   795                                 hasIDAttribute = true;
       
   796                             }
       
   797 
       
   798                             if (!validateAttribute(attributeDeclaration, attribute(attributeName))) {
       
   799                                 if (wildcard->processContents() == XsdWildcard::Strict) {
       
   800                                     error(QtXmlPatterns::tr("Attribute %1 contains invalid content.").arg(formatKeyword(m_namePool->displayName(attributeName))));
       
   801                                     return false;
       
   802                                 }
       
   803                             }
       
   804                         }
       
   805                     }
       
   806                 } else {
       
   807                     error(QtXmlPatterns::tr("Element %1 contains unknown attribute %2.").arg(formatKeyword(declaration->displayName(m_namePool)))
       
   808                                                                                        .arg(formatKeyword(m_namePool->displayName(attributeName))));
       
   809                     return false;
       
   810                 }
       
   811             }
       
   812         }
       
   813     }
       
   814 
       
   815     // 4
       
   816     // so what?...
       
   817 
       
   818     // 5
       
   819     // hmm...
       
   820 
       
   821     // 6
       
   822     // TODO: check assertions
       
   823 
       
   824     // 7
       
   825     // TODO: check type table restrictions
       
   826 
       
   827     // rememeber the type of that element node
       
   828     m_model->setAssignedType(item().toNodeModelIndex(), type);
       
   829 
       
   830     return true;
       
   831 }
       
   832 
       
   833 bool XsdValidatingInstanceReader::validateAttribute(const XsdAttributeUse::Ptr &declaration, const QString &value)
       
   834 {
       
   835     const AnySimpleType::Ptr attributeType = declaration->attribute()->type();
       
   836     const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(attributeType, m_context);
       
   837 
       
   838     const QString actualValue = XsdTypeChecker::normalizedValue(value, facets);
       
   839 
       
   840     QString errorMsg;
       
   841     AnySimpleType::Ptr boundType;
       
   842 
       
   843     const QXmlNodeModelIndex index = attributeItem(declaration->attribute()->name(m_namePool)).toNodeModelIndex();
       
   844 
       
   845     const XsdTypeChecker checker(m_context, namespaceBindings(index), sourceLocation());
       
   846     if (!checker.isValidString(actualValue, attributeType, errorMsg, &boundType)) {
       
   847         error(QtXmlPatterns::tr("Content of attribute %1 does not match its type definition: %2.").arg(formatKeyword(declaration->attribute()->displayName(m_namePool))).arg(errorMsg));
       
   848         return false;
       
   849     }
       
   850 
       
   851     // @see http://www.w3.org/TR/xmlschema11-1/#cvc-au
       
   852     if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Fixed) {
       
   853         const QString actualConstraintValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets);
       
   854         if (!checker.valuesAreEqual(actualValue, actualConstraintValue, attributeType)) {
       
   855             error(QtXmlPatterns::tr("Content of attribute %1 does not match defined value constraint.").arg(formatKeyword(declaration->attribute()->displayName(m_namePool))));
       
   856             return false;
       
   857         }
       
   858     }
       
   859 
       
   860     if (BuiltinTypes::xsID->wxsTypeMatches(declaration->attribute()->type())) {
       
   861         addIdIdRefBinding(actualValue, declaration->attribute());
       
   862     }
       
   863 
       
   864     if (m_idRefsType->wxsTypeMatches(declaration->attribute()->type())) {
       
   865         const QStringList idRefs = actualValue.split(QLatin1Char(' '), QString::SkipEmptyParts);
       
   866         for (int i = 0; i < idRefs.count(); ++i)
       
   867             m_idRefs.insert(idRefs.at(i));
       
   868     } else if (BuiltinTypes::xsIDREF->wxsTypeMatches(declaration->attribute()->type())) {
       
   869         m_idRefs.insert(actualValue);
       
   870     }
       
   871 
       
   872     m_model->setAssignedType(index, declaration->attribute()->type());
       
   873     m_model->setAssignedAttribute(index, declaration->attribute());
       
   874 
       
   875     return true;
       
   876 }
       
   877 
       
   878 //TODO: merge that with the method above
       
   879 bool XsdValidatingInstanceReader::validateAttribute(const XsdAttribute::Ptr &declaration, const QString &value)
       
   880 {
       
   881     const AnySimpleType::Ptr attributeType = declaration->type();
       
   882     const XsdFacet::Hash facets = XsdTypeChecker::mergedFacetsForType(attributeType, m_context);
       
   883 
       
   884     const QString actualValue = XsdTypeChecker::normalizedValue(value, facets);
       
   885 
       
   886     QString errorMsg;
       
   887     AnySimpleType::Ptr boundType;
       
   888 
       
   889     const QXmlNodeModelIndex index = attributeItem(declaration->name(m_namePool)).toNodeModelIndex();
       
   890 
       
   891     const XsdTypeChecker checker(m_context, namespaceBindings(index), sourceLocation());
       
   892     if (!checker.isValidString(actualValue, attributeType, errorMsg, &boundType)) {
       
   893         error(QtXmlPatterns::tr("Content of attribute %1 does not match its type definition: %2.").arg(formatKeyword(declaration->displayName(m_namePool))).arg(errorMsg));
       
   894         return false;
       
   895     }
       
   896 
       
   897     // @see http://www.w3.org/TR/xmlschema11-1/#cvc-au
       
   898     if (declaration->valueConstraint() && declaration->valueConstraint()->variety() == XsdAttribute::ValueConstraint::Fixed) {
       
   899         const QString actualConstraintValue = XsdTypeChecker::normalizedValue(declaration->valueConstraint()->value(), facets);
       
   900         if (!checker.valuesAreEqual(actualValue, actualConstraintValue, attributeType)) {
       
   901             error(QtXmlPatterns::tr("Content of attribute %1 does not match defined value constraint.").arg(formatKeyword(declaration->displayName(m_namePool))));
       
   902             return false;
       
   903         }
       
   904     }
       
   905 
       
   906     if (BuiltinTypes::xsID->wxsTypeMatches(declaration->type())) {
       
   907         addIdIdRefBinding(actualValue, declaration);
       
   908     }
       
   909 
       
   910     if (m_idRefsType->wxsTypeMatches(declaration->type())) {
       
   911         const QStringList idRefs = actualValue.split(QLatin1Char(' '), QString::SkipEmptyParts);
       
   912         for (int i = 0; i < idRefs.count(); ++i)
       
   913             m_idRefs.insert(idRefs.at(i));
       
   914     } else if (BuiltinTypes::xsIDREF->wxsTypeMatches(declaration->type())) {
       
   915         m_idRefs.insert(actualValue);
       
   916     }
       
   917 
       
   918     m_model->setAssignedType(index, declaration->type());
       
   919     m_model->setAssignedAttribute(index, declaration);
       
   920 
       
   921     return true;
       
   922 }
       
   923 
       
   924 bool XsdValidatingInstanceReader::validateAttributeWildcard(const QXmlName &attributeName, const XsdWildcard::Ptr &wildcard)
       
   925 {
       
   926     // @see http://www.w3.org/TR/xmlschema11-1/#cvc-wildcard
       
   927 
       
   928     // wildcards using XsdWildcard::absentNamespace, so we have to fix that here
       
   929     QXmlName name(attributeName);
       
   930     if (name.namespaceURI() == StandardNamespaces::empty) {
       
   931         name.setNamespaceURI(m_namePool->allocateNamespace(XsdWildcard::absentNamespace()));
       
   932     }
       
   933 
       
   934     return XsdSchemaHelper::wildcardAllowsExpandedName(name, wildcard, m_namePool);
       
   935 }
       
   936 
       
   937 bool XsdValidatingInstanceReader::validateIdentityConstraint(const XsdElement::Ptr &element, const QXmlItem &currentItem)
       
   938 {
       
   939     const XsdIdentityConstraint::List constraints = element->identityConstraints();
       
   940 
       
   941     for (int i = 0; i < constraints.count(); ++i) {
       
   942         const XsdIdentityConstraint::Ptr constraint = constraints.at(i);
       
   943 
       
   944         TargetNode::Set targetNodeSet, qualifiedNodeSet;
       
   945         selectNodeSets(element, currentItem, constraint, targetNodeSet, qualifiedNodeSet);
       
   946 
       
   947         if (constraint->category() == XsdIdentityConstraint::Unique) {
       
   948             if (!validateUniqueIdentityConstraint(element, constraint, qualifiedNodeSet))
       
   949                 return false;
       
   950         } else if (constraint->category() == XsdIdentityConstraint::Key) {
       
   951             if (!validateKeyIdentityConstraint(element, constraint, targetNodeSet, qualifiedNodeSet))
       
   952                 return false;
       
   953         }
       
   954     }
       
   955 
       
   956     // we do the keyref check in a separated run to make sure that all keys are available
       
   957     for (int i = 0; i < constraints.count(); ++i) {
       
   958         const XsdIdentityConstraint::Ptr constraint = constraints.at(i);
       
   959         if (constraint->category() == XsdIdentityConstraint::KeyReference) {
       
   960             TargetNode::Set targetNodeSet, qualifiedNodeSet;
       
   961             selectNodeSets(element, currentItem, constraint, targetNodeSet, qualifiedNodeSet);
       
   962 
       
   963             if (!validateKeyRefIdentityConstraint(element, constraint, qualifiedNodeSet))
       
   964                 return false;
       
   965         }
       
   966     }
       
   967 
       
   968     return true;
       
   969 }
       
   970 
       
   971 bool XsdValidatingInstanceReader::validateUniqueIdentityConstraint(const XsdElement::Ptr&, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &qualifiedNodeSet)
       
   972 {
       
   973     // @see http://www.w3.org/TR/xmlschema11-1/#d0e32243
       
   974 
       
   975     // 4.1
       
   976     const XsdSchemaSourceLocationReflection reflection(sourceLocation());
       
   977 
       
   978     QSetIterator<TargetNode> it(qualifiedNodeSet);
       
   979     while (it.hasNext()) {
       
   980         const TargetNode node = it.next();
       
   981         QSetIterator<TargetNode> innerIt(qualifiedNodeSet);
       
   982         while (innerIt.hasNext()) {
       
   983             const TargetNode innerNode = innerIt.next();
       
   984 
       
   985             if (node == innerNode) // do not compare with ourself
       
   986                 continue;
       
   987 
       
   988             if (node.fieldsAreEqual(innerNode, m_namePool, m_context, &reflection)) {
       
   989                 error(QtXmlPatterns::tr("Non-unique value found for constraint %1.").arg(formatKeyword(constraint->displayName(m_namePool))));
       
   990                 return false;
       
   991             }
       
   992         }
       
   993     }
       
   994 
       
   995     m_idcKeys.insert(constraint->name(m_namePool), qualifiedNodeSet);
       
   996 
       
   997     return true;
       
   998 }
       
   999 
       
  1000 bool XsdValidatingInstanceReader::validateKeyIdentityConstraint(const XsdElement::Ptr &element, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &targetNodeSet, const TargetNode::Set &qualifiedNodeSet)
       
  1001 {
       
  1002     // @see http://www.w3.org/TR/xmlschema11-1/#d0e32243
       
  1003 
       
  1004     // 4.2
       
  1005     const XsdSchemaSourceLocationReflection reflection(sourceLocation());
       
  1006 
       
  1007     // 4.2.1
       
  1008     if (targetNodeSet.count() != qualifiedNodeSet.count()) {
       
  1009         error(QtXmlPatterns::tr("Key constraint %1 contains absent fields.").arg(formatKeyword(constraint->displayName(m_namePool))));
       
  1010         return false;
       
  1011     }
       
  1012 
       
  1013     // 4.2.2
       
  1014     if (!validateUniqueIdentityConstraint(element, constraint, qualifiedNodeSet))
       
  1015         return false;
       
  1016 
       
  1017     // 4.2.3
       
  1018     QSetIterator<TargetNode> it(qualifiedNodeSet);
       
  1019     while (it.hasNext()) {
       
  1020         const TargetNode node = it.next();
       
  1021         const QVector<QXmlItem> fieldItems = node.fieldItems();
       
  1022         for (int i = 0; i < fieldItems.count(); ++i) {
       
  1023             const QXmlNodeModelIndex index = fieldItems.at(i).toNodeModelIndex();
       
  1024             if (m_model->kind(index) == QXmlNodeModelIndex::Element) {
       
  1025                 const XsdElement::Ptr declaration = m_model->assignedElement(index);
       
  1026                 if (declaration && declaration->isNillable()) {
       
  1027                     error(QtXmlPatterns::tr("Key constraint %1 contains references nillable element %2.")
       
  1028                                            .arg(formatKeyword(constraint->displayName(m_namePool)))
       
  1029                                            .arg(formatKeyword(declaration->displayName(m_namePool))));
       
  1030                     return false;
       
  1031                 }
       
  1032             }
       
  1033         }
       
  1034     }
       
  1035 
       
  1036     m_idcKeys.insert(constraint->name(m_namePool), qualifiedNodeSet);
       
  1037 
       
  1038     return true;
       
  1039 }
       
  1040 
       
  1041 bool XsdValidatingInstanceReader::validateKeyRefIdentityConstraint(const XsdElement::Ptr&, const XsdIdentityConstraint::Ptr &constraint, const TargetNode::Set &qualifiedNodeSet)
       
  1042 {
       
  1043     // @see http://www.w3.org/TR/xmlschema11-1/#d0e32243
       
  1044 
       
  1045     // 4.3
       
  1046     const XsdSchemaSourceLocationReflection reflection(sourceLocation());
       
  1047 
       
  1048     const TargetNode::Set keySet = m_idcKeys.value(constraint->referencedKey()->name(m_namePool));
       
  1049 
       
  1050     QSetIterator<TargetNode> it(qualifiedNodeSet);
       
  1051     while (it.hasNext()) {
       
  1052         const TargetNode node = it.next();
       
  1053 
       
  1054         bool foundMatching = false;
       
  1055 
       
  1056         QSetIterator<TargetNode> keyIt(keySet);
       
  1057         while (keyIt.hasNext()) {
       
  1058             const TargetNode keyNode = keyIt.next();
       
  1059 
       
  1060             if (node.fieldsAreEqual(keyNode, m_namePool, m_context, &reflection)) {
       
  1061                 foundMatching = true;
       
  1062                 break;
       
  1063             }
       
  1064         }
       
  1065 
       
  1066         if (!foundMatching) {
       
  1067             error(QtXmlPatterns::tr("No referenced value found for key reference %1.").arg(formatKeyword(constraint->displayName(m_namePool))));
       
  1068             return false;
       
  1069         }
       
  1070     }
       
  1071 
       
  1072     return true;
       
  1073 }
       
  1074 
       
  1075 QXmlQuery XsdValidatingInstanceReader::createXQuery(const QList<QXmlName> &namespaceBindings, const QXmlItem &contextNode, const QString &queryString) const
       
  1076 {
       
  1077     // create a public name pool from our name pool
       
  1078     QXmlNamePool namePool(m_namePool.data());
       
  1079 
       
  1080     // the QXmlQuery shall work with the same name pool as we do
       
  1081     QXmlQuery query(namePool);
       
  1082 
       
  1083     // add additional namespace bindings
       
  1084     QXmlQueryPrivate *queryPrivate = query.d;
       
  1085 
       
  1086     for (int i = 0; i < namespaceBindings.count(); ++i) {
       
  1087         if (!namespaceBindings.at(i).prefix() == StandardPrefixes::empty)
       
  1088             queryPrivate->addAdditionalNamespaceBinding(namespaceBindings.at(i));
       
  1089     }
       
  1090 
       
  1091     // set the context node for that query and the query string
       
  1092     query.setFocus(contextNode);
       
  1093     query.setQuery(queryString, m_documentUri);
       
  1094 
       
  1095     return query;
       
  1096 }
       
  1097 
       
  1098 bool XsdValidatingInstanceReader::selectNodeSets(const XsdElement::Ptr&, const QXmlItem &currentItem, const XsdIdentityConstraint::Ptr &constraint, TargetNode::Set &targetNodeSet, TargetNode::Set &qualifiedNodeSet)
       
  1099 {
       
  1100     // at first select all target nodes
       
  1101     const XsdXPathExpression::Ptr selector = constraint->selector();
       
  1102     const XsdXPathExpression::List fields = constraint->fields();
       
  1103 
       
  1104     QXmlQuery query = createXQuery(selector->namespaceBindings(), currentItem, selector->expression());
       
  1105 
       
  1106     QXmlResultItems resultItems;
       
  1107     query.evaluateTo(&resultItems);
       
  1108 
       
  1109     // now we iterate over all target nodes and select the fields for each node
       
  1110     QXmlItem item(resultItems.next());
       
  1111     while (!item.isNull()) {
       
  1112 
       
  1113         TargetNode targetNode(item);
       
  1114 
       
  1115         for (int i = 0; i < fields.count(); ++i) {
       
  1116             const XsdXPathExpression::Ptr field = fields.at(i);
       
  1117             QXmlQuery fieldQuery = createXQuery(field->namespaceBindings(), item, field->expression());
       
  1118 
       
  1119             QXmlResultItems fieldResultItems;
       
  1120             fieldQuery.evaluateTo(&fieldResultItems);
       
  1121 
       
  1122             // copy result into vetor for better testing...
       
  1123             QVector<QXmlItem> fieldVector;
       
  1124             QXmlItem fieldItem(fieldResultItems.next());
       
  1125             while (!fieldItem.isNull()) {
       
  1126                 fieldVector.append(fieldItem);
       
  1127                 fieldItem = fieldResultItems.next();
       
  1128             }
       
  1129 
       
  1130             if (fieldVector.count() > 1) {
       
  1131                 error(QtXmlPatterns::tr("More than one value found for field %1.").arg(formatData(field->expression())));
       
  1132                 return false;
       
  1133             }
       
  1134 
       
  1135             if (fieldVector.count() == 1) {
       
  1136                 fieldItem = fieldVector.first();
       
  1137 
       
  1138                 const QXmlNodeModelIndex index = fieldItem.toNodeModelIndex();
       
  1139                 const SchemaType::Ptr type = m_model->assignedType(index);
       
  1140 
       
  1141                 bool typeOk = true;
       
  1142                 if (type->isComplexType()) {
       
  1143                     if (type->isDefinedBySchema()) {
       
  1144                         if (XsdComplexType::Ptr(type)->contentType()->variety() != XsdComplexType::ContentType::Simple)
       
  1145                             typeOk = false;
       
  1146                     } else {
       
  1147                         typeOk = false;
       
  1148                     }
       
  1149                 }
       
  1150                 if (!typeOk) {
       
  1151                     error(QtXmlPatterns::tr("Field %1 has no simple type.").arg(formatData(field->expression())));
       
  1152                     return false;
       
  1153                 }
       
  1154 
       
  1155                 SchemaType::Ptr targetType = type;
       
  1156                 QString value = m_model->stringValue(fieldItem.toNodeModelIndex());
       
  1157 
       
  1158                 if (type->isDefinedBySchema()) {
       
  1159                     if (type->isSimpleType())
       
  1160                         targetType = XsdSimpleType::Ptr(type)->primitiveType();
       
  1161                     else
       
  1162                         targetType = XsdComplexType::Ptr(type)->contentType()->simpleType();
       
  1163                 } else {
       
  1164                     if (BuiltinTypes::xsAnySimpleType->name(m_namePool) == type->name(m_namePool)) {
       
  1165                         targetType = BuiltinTypes::xsString;
       
  1166                         value = QLatin1String("___anySimpleType_value");
       
  1167                     }
       
  1168                 }
       
  1169 
       
  1170                 // if it is xs:QName derived type, we normalize the name content
       
  1171                 // and do a string comparison
       
  1172                 if (BuiltinTypes::xsQName->wxsTypeMatches(type)) {
       
  1173                     targetType = BuiltinTypes::xsString;
       
  1174 
       
  1175                     const QXmlName qName = convertToQName(value.trimmed());
       
  1176                     value = QString::fromLatin1("%1:%2").arg(m_namePool->stringForNamespace(qName.namespaceURI())).arg(m_namePool->stringForLocalName(qName.localName()));
       
  1177                 }
       
  1178 
       
  1179                 targetNode.addField(fieldItem, value, targetType);
       
  1180             } else {
       
  1181                 // we add an empty entry here, that makes comparison easier later on
       
  1182                 targetNode.addField(QXmlItem(), QString(), SchemaType::Ptr());
       
  1183             }
       
  1184         }
       
  1185 
       
  1186         targetNodeSet.insert(targetNode);
       
  1187 
       
  1188         item = resultItems.next();
       
  1189     }
       
  1190 
       
  1191     // copy all items from target node set to qualified node set, that have no empty fields
       
  1192     QSetIterator<TargetNode> it(targetNodeSet);
       
  1193     while (it.hasNext()) {
       
  1194         const TargetNode node = it.next();
       
  1195         if (node.emptyFieldsCount() == 0)
       
  1196             qualifiedNodeSet.insert(node);
       
  1197     }
       
  1198 
       
  1199     return true;
       
  1200 }
       
  1201 
       
  1202 XsdElement::Ptr XsdValidatingInstanceReader::elementByName(const QXmlName &name) const
       
  1203 {
       
  1204     return m_schema->element(name);
       
  1205 }
       
  1206 
       
  1207 XsdAttribute::Ptr XsdValidatingInstanceReader::attributeByName(const QXmlName &name) const
       
  1208 {
       
  1209     return m_schema->attribute(name);
       
  1210 }
       
  1211 
       
  1212 SchemaType::Ptr XsdValidatingInstanceReader::typeByName(const QXmlName &name) const
       
  1213 {
       
  1214     const SchemaType::Ptr type = m_schema->type(name);
       
  1215     if (type)
       
  1216         return type;
       
  1217 
       
  1218     return m_context->schemaTypeFactory()->createSchemaType(name);
       
  1219 }
       
  1220 
       
  1221 void XsdValidatingInstanceReader::addIdIdRefBinding(const QString &id, const NamedSchemaComponent::Ptr &binding)
       
  1222 {
       
  1223     if (!m_model->idIdRefBindings(id).isEmpty()) {
       
  1224         error(QtXmlPatterns::tr("ID value '%1' is not unique.").arg(formatKeyword(id)));
       
  1225         return;
       
  1226     }
       
  1227 
       
  1228     m_model->addIdIdRefBinding(id, binding);
       
  1229 }
       
  1230 
       
  1231 QString XsdValidatingInstanceReader::qNameAttribute(const QXmlName &attributeName)
       
  1232 {
       
  1233     const QString value = attribute(attributeName).simplified();
       
  1234     if (!XPathHelper::isQName(value)) {
       
  1235         error(QtXmlPatterns::tr("'%1' attribute contains invalid QName content: %2.").arg(m_namePool->displayName(attributeName)).arg(formatData(value)));
       
  1236         return QString();
       
  1237     } else {
       
  1238         return value;
       
  1239     }
       
  1240 }
       
  1241 
       
  1242 XsdComplexType::Ptr XsdValidatingInstanceReader::anyType()
       
  1243 {
       
  1244     if (m_anyType)
       
  1245         return m_anyType;
       
  1246 
       
  1247     const XsdWildcard::Ptr wildcard(new XsdWildcard());
       
  1248     wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any);
       
  1249     wildcard->setProcessContents(XsdWildcard::Lax);
       
  1250 
       
  1251     const XsdParticle::Ptr outerParticle(new XsdParticle());
       
  1252     outerParticle->setMinimumOccurs(1);
       
  1253     outerParticle->setMaximumOccurs(1);
       
  1254 
       
  1255     const XsdParticle::Ptr innerParticle(new XsdParticle());
       
  1256     innerParticle->setMinimumOccurs(0);
       
  1257     innerParticle->setMaximumOccursUnbounded(true);
       
  1258     innerParticle->setTerm(wildcard);
       
  1259 
       
  1260     const XsdModelGroup::Ptr outerModelGroup(new XsdModelGroup());
       
  1261     outerModelGroup->setCompositor(XsdModelGroup::SequenceCompositor);
       
  1262     outerModelGroup->setParticles(XsdParticle::List() << innerParticle);
       
  1263     outerParticle->setTerm(outerModelGroup);
       
  1264 
       
  1265     m_anyType = XsdComplexType::Ptr(new XsdComplexType());
       
  1266     m_anyType->setName(BuiltinTypes::xsAnyType->name(m_namePool));
       
  1267     m_anyType->setDerivationMethod(XsdComplexType::DerivationRestriction);
       
  1268     m_anyType->contentType()->setVariety(XsdComplexType::ContentType::Mixed);
       
  1269     m_anyType->contentType()->setParticle(outerParticle);
       
  1270     m_anyType->setAttributeWildcard(wildcard);
       
  1271     m_anyType->setIsAbstract(false);
       
  1272 
       
  1273     return m_anyType;
       
  1274 }
       
  1275 
       
  1276 QT_END_NAMESPACE