| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtXmlPatterns module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qxsdschemaparser_p.h" |
| |
| #include "private/qxmlutils_p.h" |
| #include "qacceltreeresourceloader_p.h" |
| #include "qautoptr_p.h" |
| #include "qboolean_p.h" |
| #include "qcommonnamespaces_p.h" |
| #include "qderivedinteger_p.h" |
| #include "qderivedstring_p.h" |
| #include "qqnamevalue_p.h" |
| #include "qxmlquery_p.h" |
| #include "qxpathhelper_p.h" |
| #include "qxsdattributereference_p.h" |
| #include "qxsdreference_p.h" |
| #include "qxsdschematoken_p.h" |
| |
| #include <QtCore/QFile> |
| #include <QtXmlPatterns/QXmlQuery> |
| |
| QT_BEGIN_NAMESPACE |
| |
| /** |
| * @page schema_overview Overview |
| * @section structure_and_components Structure and Components |
| * |
| * The schema validator code consists of 4 major components |
| * |
| * <dl> |
| * <dt>The schema parser (QPatternist::XsdSchemaParser)</dt> |
| * <dd>This component parses a XML document that is supplied via a QIODevice. It creates |
| * a so called (incomplete) 'compiled schema', which is a representation of the XML Schema |
| * structure as C++ objects. |
| * As the parser is a streaming parser, it can't resolve references to types or elements/attributes |
| * in place, therefore it creates resolver tasks which are passed to the schema resolver component |
| * for resolving at a later point in time. |
| * The parser does furthermore the basic XML structure constraint checking, e.g. if all required |
| * attributes are available or the order of the elements is correct.</dd> |
| * |
| * <dt>The schema resolver (QPatternist::XsdSchemaResolver)</dt> |
| * <dd>This component is activated after the schema parser component has been finished the parsing |
| * of all schemas. The resolver has been supplied with resolve tasks by the schema parser that |
| * it will resolve in this step now. Between working on the single resolver tasks, the resolver |
| * calls check methods from the schema checker component to make sure that some assertions are |
| * valid (e.g. no circular inheritance of types), so that the resolver can work without hassle. |
| * During resoving references to attribute or element groups it also checks for circular references |
| * of these groups. |
| * At the end of that phase we have a compiled schema that is fully resolved (not necessarily valid though).</dd> |
| * |
| * <dt>The schema checker (QPatternist::XsdSchemaChecker)</dt> |
| * <dd>This component does all the schema constraint checking as given by the Schema specification. |
| * At the end of that phase we have fully resolved and valid compiled schema that can be used for validation |
| * of instance documents.</dd> |
| * |
| * <dt>The validator (QPatternist::XsdValidatingInstanceReader)</dt> |
| * <dd>This component is responsible for validating a XML instance document, provided via a QIODevice, against |
| * a valid compiled schema.</dd> |
| * </dl> |
| * |
| * @ingroup Patternist_schema |
| */ |
| |
| using namespace QPatternist; |
| |
| namespace QPatternist |
| { |
| |
| /** |
| * @short A helper class for automatically handling namespace scopes of elements. |
| * |
| * This class should be instantiated at the beginning of each parse XYZ method. |
| */ |
| class ElementNamespaceHandler |
| { |
| public: |
| /** |
| * Creates a new element namespace handler object. |
| * |
| * It checks whether the @p parser is on the right @p tag and it creates a new namespace |
| * context that contains the inherited and local namespace declarations. |
| */ |
| ElementNamespaceHandler(const XsdSchemaToken::NodeName &tag, XsdSchemaParser *parser) |
| : m_parser(parser) |
| { |
| Q_ASSERT(m_parser->isStartElement() && (XsdSchemaToken::toToken(m_parser->name()) == tag) && (XsdSchemaToken::toToken(m_parser->namespaceUri()) == XsdSchemaToken::XML_NS_SCHEMA_URI)); |
| Q_UNUSED(tag) |
| m_parser->m_namespaceSupport.pushContext(); |
| m_parser->m_namespaceSupport.setPrefixes(m_parser->namespaceDeclarations()); |
| } |
| |
| /** |
| * Destroys the element namespace handler object. |
| * |
| * It destroys the local namespace context. |
| */ |
| ~ElementNamespaceHandler() |
| { |
| m_parser->m_namespaceSupport.popContext(); |
| } |
| |
| private: |
| XsdSchemaParser *m_parser; |
| }; |
| |
| /** |
| * A helper class that checks for the right occurrence of |
| * xml tags with the help of a DFA. |
| */ |
| class TagValidationHandler |
| { |
| public: |
| TagValidationHandler(XsdTagScope::Type tag, XsdSchemaParser *parser, const NamePool::Ptr &namePool) |
| : m_parser(parser), m_machine(namePool) |
| { |
| Q_ASSERT(m_parser->m_stateMachines.contains(tag)); |
| |
| m_machine = m_parser->m_stateMachines.value(tag); |
| m_machine.reset(); |
| } |
| |
| void validate(XsdSchemaToken::NodeName token) |
| { |
| if (token == XsdSchemaToken::NoKeyword) { |
| const QList<XsdSchemaToken::NodeName> tokens = m_machine.possibleTransitions(); |
| |
| QStringList elementNames; |
| for (int i = 0; i < tokens.count(); ++i) |
| elementNames.append(formatElement(XsdSchemaToken::toString(tokens.at(i)))); |
| |
| m_parser->error(QtXmlPatterns::tr("Can not process unknown element %1, expected elements are: %2.") |
| .arg(formatElement(m_parser->name().toString())) |
| .arg(elementNames.join(QLatin1String(", ")))); |
| return; |
| } |
| |
| if (!m_machine.proceed(token)) { |
| const QList<XsdSchemaToken::NodeName> tokens = m_machine.possibleTransitions(); |
| |
| QStringList elementNames; |
| for (int i = 0; i < tokens.count(); ++i) |
| elementNames.append(formatElement(XsdSchemaToken::toString(tokens.at(i)))); |
| |
| m_parser->error(QtXmlPatterns::tr("Element %1 is not allowed in this scope, possible elements are: %2.") |
| .arg(formatElement(XsdSchemaToken::toString(token))) |
| .arg(elementNames.join(QLatin1String(", ")))); |
| return; |
| } |
| } |
| |
| void finalize() const |
| { |
| if (!m_machine.inEndState()) { |
| const QList<XsdSchemaToken::NodeName> tokens = m_machine.possibleTransitions(); |
| |
| QStringList elementNames; |
| for (int i = 0; i < tokens.count(); ++i) |
| elementNames.append(formatElement(XsdSchemaToken::toString(tokens.at(i)))); |
| |
| m_parser->error(QtXmlPatterns::tr("Child element is missing in that scope, possible child elements are: %1.") |
| .arg(elementNames.join(QLatin1String(", ")))); |
| } |
| } |
| |
| private: |
| XsdSchemaParser *m_parser; |
| XsdStateMachine<XsdSchemaToken::NodeName> m_machine; |
| }; |
| |
| } |
| |
| /** |
| * Returns a list of all particles with group references that appear at any level of |
| * the given unresolved @p group. |
| */ |
| static XsdParticle::List collectGroupRef(const XsdModelGroup::Ptr &group) |
| { |
| XsdParticle::List refParticles; |
| |
| XsdParticle::List particles = group->particles(); |
| for (int i = 0; i < particles.count(); ++i) { |
| if (particles.at(i)->term()->isReference()) { |
| const XsdReference::Ptr reference(particles.at(i)->term()); |
| if (reference->type() == XsdReference::ModelGroup) |
| refParticles.append(particles.at(i)); |
| } |
| if (particles.at(i)->term()->isModelGroup()) { |
| refParticles << collectGroupRef(XsdModelGroup::Ptr(particles.at(i)->term())); |
| } |
| } |
| |
| return refParticles; |
| } |
| |
| /** |
| * Helper function that works around the limited facilities of |
| * QUrl/AnyURI::fromLexical to detect invalid URIs |
| */ |
| inline static bool isValidUri(const QString &string) |
| { |
| // an empty URI points to the current document as defined in RFC 2396 (4.2) |
| if (string.isEmpty()) |
| return true; |
| |
| // explicit check as that is not checked by the code below |
| if (string.startsWith(QLatin1String("##"))) |
| return false; |
| |
| const AnyURI::Ptr uri = AnyURI::fromLexical(string); |
| return (!(uri->hasError())); |
| } |
| |
| XsdSchemaParser::XsdSchemaParser(const XsdSchemaContext::Ptr &context, const XsdSchemaParserContext::Ptr &parserContext, QIODevice *device) |
| : MaintainingReader<XsdSchemaToken, XsdTagScope::Type>(parserContext->elementDescriptions(), QSet<XsdSchemaToken::NodeName>(), context, device) |
| , m_context(context) |
| , m_parserContext(parserContext) |
| , m_namePool(m_parserContext->namePool()) |
| , m_namespaceSupport(m_namePool) |
| , m_defaultOpenContentAppliesToEmpty(false) |
| { |
| m_schema = m_parserContext->schema(); |
| m_schemaResolver = m_parserContext->resolver(); |
| m_idCache = XsdIdCache::Ptr(new XsdIdCache()); |
| |
| setupStateMachines(); |
| setupBuiltinTypeNames(); |
| } |
| |
| void XsdSchemaParser::addIncludedSchemas(const NamespaceSet &schemas) |
| { |
| m_includedSchemas += schemas; |
| } |
| |
| void XsdSchemaParser::setIncludedSchemas(const NamespaceSet &schemas) |
| { |
| m_includedSchemas = schemas; |
| } |
| |
| void XsdSchemaParser::addImportedSchemas(const NamespaceSet &schemas) |
| { |
| m_importedSchemas += schemas; |
| } |
| |
| void XsdSchemaParser::setImportedSchemas(const NamespaceSet &schemas) |
| { |
| m_importedSchemas = schemas; |
| } |
| |
| void XsdSchemaParser::addRedefinedSchemas(const NamespaceSet &schemas) |
| { |
| m_redefinedSchemas += schemas; |
| } |
| |
| void XsdSchemaParser::setRedefinedSchemas(const NamespaceSet &schemas) |
| { |
| m_redefinedSchemas = schemas; |
| } |
| |
| void XsdSchemaParser::setTargetNamespace(const QString &targetNamespace) |
| { |
| m_targetNamespace = targetNamespace; |
| } |
| |
| void XsdSchemaParser::setTargetNamespaceExtended(const QString &targetNamespace) |
| { |
| m_targetNamespace = targetNamespace; |
| m_namespaceSupport.setTargetNamespace(m_namePool->allocateNamespace(m_targetNamespace)); |
| } |
| |
| void XsdSchemaParser::setDocumentURI(const QUrl &uri) |
| { |
| m_documentURI = uri; |
| |
| // prevent to get included/imported/redefined twice |
| m_includedSchemas.insert(uri); |
| m_importedSchemas.insert(uri); |
| m_redefinedSchemas.insert(uri); |
| } |
| |
| QUrl XsdSchemaParser::documentURI() const |
| { |
| return m_documentURI; |
| } |
| |
| bool XsdSchemaParser::isAnyAttributeAllowed() const |
| { |
| return false; |
| } |
| |
| bool XsdSchemaParser::parse(ParserType parserType) |
| { |
| m_componentLocationHash.clear(); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| if (isSchemaTag(XsdSchemaToken::Schema, token, namespaceToken)) { |
| parseSchema(parserType); |
| } else { |
| error(QtXmlPatterns::tr("Document is not a XML schema.")); |
| } |
| } |
| } |
| |
| m_schemaResolver->addComponentLocationHash(m_componentLocationHash); |
| m_schemaResolver->setDefaultOpenContent(m_defaultOpenContent, m_defaultOpenContentAppliesToEmpty); |
| |
| if (QXmlStreamReader::error() != QXmlStreamReader::NoError) |
| error(errorString()); |
| |
| return true; |
| } |
| |
| void XsdSchemaParser::error(const QString &msg) |
| { |
| MaintainingReader<XsdSchemaToken, XsdTagScope::Type>::error(msg, XsdSchemaContext::XSDError); |
| } |
| |
| void XsdSchemaParser::attributeContentError(const char *attributeName, const char *elementName, const QString &value, const SchemaType::Ptr &type) |
| { |
| if (type) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element contains invalid content: {%3} is not a value of type %4.") |
| .arg(formatAttribute(attributeName)) |
| .arg(formatElement(elementName)) |
| .arg(formatData(value)) |
| .arg(formatType(m_namePool, type))); |
| } else { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element contains invalid content: {%3}.") |
| .arg(formatAttribute(attributeName)) |
| .arg(formatElement(elementName)) |
| .arg(formatData(value))); |
| } |
| } |
| |
| void XsdSchemaParser::parseSchema(ParserType parserType) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Schema, this); |
| |
| validateElement(XsdTagScope::Schema); |
| |
| // parse attributes |
| |
| if (parserType == TopLevelParser) { |
| if (hasAttribute(QString::fromLatin1("targetNamespace"))) { |
| m_targetNamespace = readNamespaceAttribute(QString::fromLatin1("targetNamespace"), "schema"); |
| } |
| } else if (parserType == IncludeParser) { |
| // m_targetNamespace is set to the target namespace of the including schema at this point |
| |
| if (hasAttribute(QString::fromLatin1("targetNamespace"))) { |
| const QString targetNamespace = readNamespaceAttribute(QString::fromLatin1("targetNamespace"), "schema"); |
| |
| if (m_targetNamespace != targetNamespace) { |
| error(QtXmlPatterns::tr("Target namespace %1 of included schema is different from the target namespace %2 as defined by the including schema.") |
| .arg(formatURI(targetNamespace)).arg(formatURI(m_targetNamespace))); |
| return; |
| } |
| } |
| } else if (parserType == ImportParser) { |
| // m_targetNamespace is set to the target namespace from the namespace attribute of the <import> tag at this point |
| |
| QString targetNamespace; |
| if (hasAttribute(QString::fromLatin1("targetNamespace"))) { |
| targetNamespace = readNamespaceAttribute(QString::fromLatin1("targetNamespace"), "schema"); |
| } |
| |
| if (m_targetNamespace != targetNamespace) { |
| error(QtXmlPatterns::tr("Target namespace %1 of imported schema is different from the target namespace %2 as defined by the importing schema.") |
| .arg(formatURI(targetNamespace)).arg(formatURI(m_targetNamespace))); |
| return; |
| } |
| } else if (parserType == RedefineParser) { |
| // m_targetNamespace is set to the target namespace of the redefining schema at this point |
| |
| if (hasAttribute(QString::fromLatin1("targetNamespace"))) { |
| const QString targetNamespace = readNamespaceAttribute(QString::fromLatin1("targetNamespace"), "schema"); |
| |
| if (m_targetNamespace != targetNamespace) { |
| error(QtXmlPatterns::tr("Target namespace %1 of imported schema is different from the target namespace %2 as defined by the importing schema.") |
| .arg(formatURI(targetNamespace)).arg(formatURI(m_targetNamespace))); |
| return; |
| } |
| } |
| } |
| |
| if (hasAttribute(QString::fromLatin1("attributeFormDefault"))) { |
| const QString value = readAttribute(QString::fromLatin1("attributeFormDefault")); |
| if (value != QString::fromLatin1("qualified") && value != QString::fromLatin1("unqualified")) { |
| attributeContentError("attributeFormDefault", "schema", value); |
| return; |
| } |
| |
| m_attributeFormDefault = value; |
| } else { |
| m_attributeFormDefault = QString::fromLatin1("unqualified"); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("elementFormDefault"))) { |
| const QString value = readAttribute(QString::fromLatin1("elementFormDefault")); |
| if (value != QString::fromLatin1("qualified") && value != QString::fromLatin1("unqualified")) { |
| attributeContentError("elementFormDefault", "schema", value); |
| return; |
| } |
| |
| m_elementFormDefault = value; |
| } else { |
| m_elementFormDefault = QString::fromLatin1("unqualified"); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("blockDefault"))) { |
| const QString blockDefault = readAttribute(QString::fromLatin1("blockDefault")); |
| const QStringList blockDefaultList = blockDefault.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| for (int i = 0; i < blockDefaultList.count(); ++i) { |
| const QString value = blockDefaultList.at(i); |
| if (value != QString::fromLatin1("#all") && |
| value != QString::fromLatin1("extension") && |
| value != QString::fromLatin1("restriction") && |
| value != QString::fromLatin1("substitution")) { |
| attributeContentError("blockDefault", "schema", value); |
| return; |
| } |
| } |
| |
| m_blockDefault = blockDefault; |
| } |
| |
| if (hasAttribute(QString::fromLatin1("finalDefault"))) { |
| const QString finalDefault = readAttribute(QString::fromLatin1("finalDefault")); |
| const QStringList finalDefaultList = finalDefault.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| for (int i = 0; i < finalDefaultList.count(); ++i) { |
| const QString value = finalDefaultList.at(i); |
| if (value != QString::fromLatin1("#all") && |
| value != QString::fromLatin1("extension") && |
| value != QString::fromLatin1("restriction") && |
| value != QString::fromLatin1("list") && |
| value != QString::fromLatin1("union")) { |
| attributeContentError("finalDefault", "schema", value); |
| return; |
| } |
| } |
| |
| m_finalDefault = finalDefault; |
| } |
| |
| if (hasAttribute(QString::fromLatin1("xpathDefaultNamespace"))) { |
| const QString xpathDefaultNamespace = readAttribute(QString::fromLatin1("xpathDefaultNamespace")); |
| if (xpathDefaultNamespace != QString::fromLatin1("##defaultNamespace") && |
| xpathDefaultNamespace != QString::fromLatin1("##targetNamespace") && |
| xpathDefaultNamespace != QString::fromLatin1("##local")) { |
| if (!isValidUri(xpathDefaultNamespace)) { |
| attributeContentError("xpathDefaultNamespace", "schema", xpathDefaultNamespace); |
| return; |
| } |
| } |
| m_xpathDefaultNamespace = xpathDefaultNamespace; |
| } else { |
| m_xpathDefaultNamespace = QString::fromLatin1("##local"); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("defaultAttributes"))) { |
| const QString attrGroupName = readQNameAttribute(QString::fromLatin1("defaultAttributes"), "schema"); |
| convertName(attrGroupName, NamespaceSupport::ElementName, m_defaultAttributes); // translate qualified name into QXmlName |
| } |
| |
| if (hasAttribute(QString::fromLatin1("version"))) { |
| const QString version = readAttribute(QString::fromLatin1("version")); |
| } |
| |
| if (hasAttribute(CommonNamespaces::XML, QString::fromLatin1("lang"))) { |
| const QString value = readAttribute(QString::fromLatin1("lang"), CommonNamespaces::XML); |
| |
| QRegExp exp(QString::fromLatin1("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*")); |
| if (!exp.exactMatch(value)) { |
| attributeContentError("xml:lang", "schema", value); |
| return; |
| } |
| } |
| |
| validateIdAttribute("schema"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Schema, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Include, token, namespaceToken)) { |
| parseInclude(); |
| } else if (isSchemaTag(XsdSchemaToken::Import, token, namespaceToken)) { |
| parseImport(); |
| } else if (isSchemaTag(XsdSchemaToken::Redefine, token, namespaceToken)) { |
| parseRedefine(); |
| } else if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| m_schema->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::DefaultOpenContent, token, namespaceToken)) { |
| parseDefaultOpenContent(); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| const XsdSimpleType::Ptr type = parseGlobalSimpleType(); |
| addType(type); |
| } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { |
| const XsdComplexType::Ptr type = parseGlobalComplexType(); |
| addType(type); |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdModelGroup::Ptr group = parseNamedGroup(); |
| addElementGroup(group); |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| XsdAttributeGroup::Ptr attributeGroup = parseNamedAttributeGroup(); |
| addAttributeGroup(attributeGroup); |
| } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { |
| const XsdElement::Ptr element = parseGlobalElement(); |
| addElement(element); |
| } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { |
| const XsdAttribute::Ptr attribute = parseGlobalAttribute(); |
| addAttribute(attribute); |
| } else if (isSchemaTag(XsdSchemaToken::Notation, token, namespaceToken)) { |
| const XsdNotation::Ptr notation = parseNotation(); |
| addNotation(notation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| m_schema->setTargetNamespace(m_targetNamespace); |
| } |
| |
| void XsdSchemaParser::parseInclude() |
| { |
| Q_ASSERT(isStartElement() && XsdSchemaToken::toToken(name()) == XsdSchemaToken::Include && |
| XsdSchemaToken::toToken(namespaceUri()) == XsdSchemaToken::XML_NS_SCHEMA_URI); |
| |
| validateElement(XsdTagScope::Include); |
| |
| // parse attributes |
| const QString schemaLocation = readAttribute(QString::fromLatin1("schemaLocation")); |
| |
| QUrl url(schemaLocation); |
| if (url.isRelative()) { |
| Q_ASSERT(m_documentURI.isValid()); |
| |
| url = m_documentURI.resolved(url); |
| } |
| |
| if (m_includedSchemas.contains(url)) { |
| // we have included that file already, according to the schema spec we are |
| // allowed to silently skip it. |
| } else { |
| m_includedSchemas.insert(url); |
| |
| const AutoPtr<QNetworkReply> reply(AccelTreeResourceLoader::load(url, m_context->networkAccessManager(), |
| m_context, AccelTreeResourceLoader::ContinueOnError)); |
| if (reply) { |
| // parse the included schema by a different parser but with the same context |
| XsdSchemaParser parser(m_context, m_parserContext, reply.data()); |
| parser.setDocumentURI(url); |
| parser.setTargetNamespaceExtended(m_targetNamespace); |
| parser.setIncludedSchemas(m_includedSchemas); |
| parser.setImportedSchemas(m_importedSchemas); |
| parser.setRedefinedSchemas(m_redefinedSchemas); |
| if (!parser.parse(XsdSchemaParser::IncludeParser)) { |
| return; |
| } else { |
| // add indirectly loaded schemas to the list of already loaded ones |
| addIncludedSchemas(parser.m_includedSchemas); |
| addImportedSchemas(parser.m_importedSchemas); |
| addRedefinedSchemas(parser.m_redefinedSchemas); |
| } |
| } |
| } |
| |
| validateIdAttribute("include"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Include, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| m_schema->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| void XsdSchemaParser::parseImport() |
| { |
| Q_ASSERT(isStartElement() && XsdSchemaToken::toToken(name()) == XsdSchemaToken::Import && |
| XsdSchemaToken::toToken(namespaceUri()) == XsdSchemaToken::XML_NS_SCHEMA_URI); |
| |
| validateElement(XsdTagScope::Import); |
| |
| // parse attributes |
| QString importNamespace; |
| if (hasAttribute(QString::fromLatin1("namespace"))) { |
| importNamespace = readAttribute(QString::fromLatin1("namespace")); |
| if (importNamespace == m_targetNamespace) { |
| error(QtXmlPatterns::tr("%1 element is not allowed to have the same %2 attribute value as the target namespace %3.") |
| .arg(formatElement("import")) |
| .arg(formatAttribute("namespace")) |
| .arg(formatURI(m_targetNamespace))); |
| return; |
| } |
| } else { |
| if (m_targetNamespace.isEmpty()) { |
| error(QtXmlPatterns::tr("%1 element without %2 attribute is not allowed inside schema without target namespace.") |
| .arg(formatElement("import")) |
| .arg(formatAttribute("namespace"))); |
| return; |
| } |
| } |
| |
| if (hasAttribute(QString::fromLatin1("schemaLocation"))) { |
| const QString schemaLocation = readAttribute(QString::fromLatin1("schemaLocation")); |
| |
| QUrl url(schemaLocation); |
| if (url.isRelative()) { |
| Q_ASSERT(m_documentURI.isValid()); |
| |
| url = m_documentURI.resolved(url); |
| } |
| |
| if (m_importedSchemas.contains(url)) { |
| // we have imported that file already, according to the schema spec we are |
| // allowed to silently skip it. |
| } else { |
| m_importedSchemas.insert(url); |
| |
| // as it is possible that well known schemas (e.g. XSD for XML) are only referenced by |
| // namespace we should add it as well |
| m_importedSchemas.insert(importNamespace); |
| |
| AutoPtr<QNetworkReply> reply(AccelTreeResourceLoader::load(url, m_context->networkAccessManager(), |
| m_context, AccelTreeResourceLoader::ContinueOnError)); |
| if (reply) { |
| // parse the included schema by a different parser but with the same context |
| XsdSchemaParser parser(m_context, m_parserContext, reply.data()); |
| parser.setDocumentURI(url); |
| parser.setTargetNamespace(importNamespace); |
| parser.setIncludedSchemas(m_includedSchemas); |
| parser.setImportedSchemas(m_importedSchemas); |
| parser.setRedefinedSchemas(m_redefinedSchemas); |
| if (!parser.parse(XsdSchemaParser::ImportParser)) { |
| return; |
| } else { |
| // add indirectly loaded schemas to the list of already loaded ones |
| addIncludedSchemas(parser.m_includedSchemas); |
| addImportedSchemas(parser.m_importedSchemas); |
| addRedefinedSchemas(parser.m_redefinedSchemas); |
| } |
| } |
| } |
| } else { |
| // check whether it is a known namespace we have a builtin schema for |
| if (!importNamespace.isEmpty()) { |
| if (!m_importedSchemas.contains(importNamespace)) { |
| m_importedSchemas.insert(importNamespace); |
| |
| QFile file(QString::fromLatin1(":") + importNamespace); |
| if (file.open(QIODevice::ReadOnly)) { |
| XsdSchemaParser parser(m_context, m_parserContext, &file); |
| parser.setDocumentURI(importNamespace); |
| parser.setTargetNamespace(importNamespace); |
| parser.setIncludedSchemas(m_includedSchemas); |
| parser.setImportedSchemas(m_importedSchemas); |
| parser.setRedefinedSchemas(m_redefinedSchemas); |
| if (!parser.parse(XsdSchemaParser::ImportParser)) { |
| return; |
| } else { |
| // add indirectly loaded schemas to the list of already loaded ones |
| addIncludedSchemas(parser.m_includedSchemas); |
| addImportedSchemas(parser.m_importedSchemas); |
| addRedefinedSchemas(parser.m_redefinedSchemas); |
| } |
| } |
| } |
| } else { |
| // we don't import anything... that is valid according to the schema |
| } |
| } |
| |
| validateIdAttribute("import"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Import, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| m_schema->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| void XsdSchemaParser::parseRedefine() |
| { |
| Q_ASSERT(isStartElement() && XsdSchemaToken::toToken(name()) == XsdSchemaToken::Redefine && |
| XsdSchemaToken::toToken(namespaceUri()) == XsdSchemaToken::XML_NS_SCHEMA_URI); |
| |
| validateElement(XsdTagScope::Redefine); |
| |
| // parse attributes |
| validateIdAttribute("redefine"); |
| |
| const QString schemaLocation = readAttribute(QString::fromLatin1("schemaLocation")); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Redefine, this, m_namePool); |
| |
| XsdSimpleType::List redefinedSimpleTypes; |
| XsdComplexType::List redefinedComplexTypes; |
| XsdModelGroup::List redefinedGroups; |
| XsdAttributeGroup::List redefinedAttributeGroups; |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| m_schema->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| const XsdSimpleType::Ptr type = parseGlobalSimpleType(); |
| redefinedSimpleTypes.append(type); |
| |
| const QXmlName baseTypeName = m_parserContext->resolver()->baseTypeNameOfType(type); |
| if (baseTypeName != type->name(m_namePool)) { |
| error(QString::fromLatin1("redefined simple type %1 must have itself as base type").arg(formatType(m_namePool, type))); |
| return; |
| } |
| } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { |
| const XsdComplexType::Ptr type = parseGlobalComplexType(); |
| redefinedComplexTypes.append(type); |
| |
| // @see http://www.w3.org/TR/xmlschema11-1/#src-redefine |
| |
| // 5 |
| const QXmlName baseTypeName = m_parserContext->resolver()->baseTypeNameOfType(type); |
| if (baseTypeName != type->name(m_namePool)) { |
| error(QString::fromLatin1("redefined complex type %1 must have itself as base type").arg(formatType(m_namePool, type))); |
| return; |
| } |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdModelGroup::Ptr group = parseNamedGroup(); |
| redefinedGroups.append(group); |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| const XsdAttributeGroup::Ptr group = parseNamedAttributeGroup(); |
| redefinedAttributeGroups.append(group); |
| |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| bool locationMustResolve = false; |
| if (!redefinedSimpleTypes.isEmpty() || !redefinedComplexTypes.isEmpty() || |
| !redefinedGroups.isEmpty() || !redefinedAttributeGroups.isEmpty()) { |
| locationMustResolve = true; |
| } |
| |
| QUrl url(schemaLocation); |
| if (url.isRelative()) { |
| Q_ASSERT(m_documentURI.isValid()); |
| |
| url = m_documentURI.resolved(url); |
| } |
| |
| // we parse the schema given in the redefine tag into its own context |
| const XsdSchemaParserContext::Ptr redefinedContext(new XsdSchemaParserContext(m_namePool, m_context)); |
| |
| if (m_redefinedSchemas.contains(url)) { |
| // we have redefined that file already, according to the schema spec we are |
| // allowed to silently skip it. |
| } else { |
| m_redefinedSchemas.insert(url); |
| QNetworkReply *reply = AccelTreeResourceLoader::load(url, m_context->networkAccessManager(), |
| m_context, |
| (locationMustResolve ? AccelTreeResourceLoader::FailOnError : AccelTreeResourceLoader::ContinueOnError)); |
| if (reply) { |
| // parse the included schema by a different parser but with the same context |
| XsdSchemaParser parser(m_context, redefinedContext, reply); |
| parser.setDocumentURI(url); |
| parser.setTargetNamespaceExtended(m_targetNamespace); |
| parser.setIncludedSchemas(m_includedSchemas); |
| parser.setImportedSchemas(m_importedSchemas); |
| parser.setRedefinedSchemas(m_redefinedSchemas); |
| if (!parser.parse(XsdSchemaParser::RedefineParser)) { |
| return; |
| } else { |
| // add indirectly loaded schemas to the list of already loaded ones |
| addIncludedSchemas(parser.m_includedSchemas); |
| addImportedSchemas(parser.m_importedSchemas); |
| addRedefinedSchemas(parser.m_redefinedSchemas); |
| } |
| |
| delete reply; |
| } |
| } |
| |
| XsdSimpleType::List contextSimpleTypes = redefinedContext->schema()->simpleTypes(); |
| XsdComplexType::List contextComplexTypes = redefinedContext->schema()->complexTypes(); |
| XsdModelGroup::List contextGroups = redefinedContext->schema()->elementGroups(); |
| XsdAttributeGroup::List contextAttributeGroups = redefinedContext->schema()->attributeGroups(); |
| |
| // now we do the actual redefinition: |
| |
| // iterate over all redefined simple types |
| for (int i = 0; i < redefinedSimpleTypes.count(); ++i) { |
| XsdSimpleType::Ptr redefinedType = redefinedSimpleTypes.at(i); |
| |
| //TODONEXT: validation |
| |
| // search the definition they override in the context types |
| bool found = false; |
| for (int j = 0; j < contextSimpleTypes.count(); ++j) { |
| XsdSimpleType::Ptr contextType = contextSimpleTypes.at(j); |
| |
| if (redefinedType->name(m_namePool) == contextType->name(m_namePool)) { // we found the right type |
| found = true; |
| |
| // 1) set name of context type to empty name |
| contextType->setName(m_parserContext->createAnonymousName(QString())); |
| |
| // 2) set the context type as base type for the redefined type |
| redefinedType->setWxsSuperType(contextType); |
| |
| // 3) remove the base type resolving job from the resolver as |
| // we have set the base type here explicitly |
| m_parserContext->resolver()->removeSimpleRestrictionBase(redefinedType); |
| |
| // 4) add the redefined type to the schema |
| addType(redefinedType); |
| |
| // 5) add the context type as anonymous type, so the resolver |
| // can resolve it further. |
| addAnonymousType(contextType); |
| |
| // 6) remove the context type from the list |
| contextSimpleTypes.removeAt(j); |
| |
| break; |
| } |
| } |
| |
| if (!found) { |
| error(QString::fromLatin1("no matching type found to redefine simple type %1").arg(formatType(m_namePool, redefinedType))); |
| return; |
| } |
| } |
| |
| // add all remaining context simple types to the schema |
| for (int i = 0; i < contextSimpleTypes.count(); ++i) { |
| addType(contextSimpleTypes.at(i)); |
| } |
| |
| // iterate over all redefined complex types |
| for (int i = 0; i < redefinedComplexTypes.count(); ++i) { |
| XsdComplexType::Ptr redefinedType = redefinedComplexTypes.at(i); |
| |
| //TODONEXT: validation |
| |
| // search the definition they override in the context types |
| bool found = false; |
| for (int j = 0; j < contextComplexTypes.count(); ++j) { |
| XsdComplexType::Ptr contextType = contextComplexTypes.at(j); |
| |
| if (redefinedType->name(m_namePool) == contextType->name(m_namePool)) { // we found the right type |
| found = true; |
| |
| // 1) set name of context type to empty name |
| contextType->setName(m_parserContext->createAnonymousName(QString())); |
| |
| // 2) set the context type as base type for the redefined type |
| redefinedType->setWxsSuperType(contextType); |
| |
| // 3) remove the base type resolving job from the resolver as |
| // we have set the base type here explicitly |
| m_parserContext->resolver()->removeComplexBaseType(redefinedType); |
| |
| // 4) add the redefined type to the schema |
| addType(redefinedType); |
| |
| // 5) add the context type as anonymous type, so the resolver |
| // can resolve its attribute uses etc. |
| addAnonymousType(contextType); |
| |
| // 6) remove the context type from the list |
| contextComplexTypes.removeAt(j); |
| |
| break; |
| } |
| } |
| |
| if (!found) { |
| error(QString::fromLatin1("no matching type found to redefine complex type %1").arg(formatType(m_namePool, redefinedType))); |
| return; |
| } |
| } |
| |
| // iterate over all redefined element groups |
| for (int i = 0; i < redefinedGroups.count(); ++i) { |
| const XsdModelGroup::Ptr group(redefinedGroups.at(i)); |
| |
| // @see http://www.w3.org/TR/xmlschema11-1/#src-redefine |
| |
| // 6 |
| const XsdParticle::List particles = collectGroupRef(group); |
| XsdParticle::Ptr referencedParticle; |
| int sameNameCounter = 0; |
| for (int i = 0; i < particles.count(); ++i) { |
| const XsdReference::Ptr ref(particles.at(i)->term()); |
| if (ref->referenceName() == group->name(m_namePool)) { |
| referencedParticle = particles.at(i); |
| |
| if (referencedParticle->minimumOccurs() != 1 || referencedParticle->maximumOccurs() != 1 || referencedParticle->maximumOccursUnbounded()) { // 6.1.2 |
| error(QString::fromLatin1("redefined group %1 can not contain reference to itself with minOccurs or maxOccurs != 1").arg(formatKeyword(group->displayName(m_namePool)))); |
| return; |
| } |
| sameNameCounter++; |
| } |
| } |
| |
| // 6.1.1 |
| if (sameNameCounter > 1) { |
| error(QString::fromLatin1("redefined group %1 can not contain multiple references to itself").arg(formatKeyword(group->displayName(m_namePool)))); |
| return; |
| } |
| |
| // search the group definition in the included schema (S2) |
| XsdModelGroup::Ptr contextGroup; |
| for (int j = 0; j < contextGroups.count(); ++j) { |
| if (group->name(m_namePool) == contextGroups.at(j)->name(m_namePool)) { |
| contextGroup = contextGroups.at(j); |
| break; |
| } |
| } |
| |
| if (!contextGroup) { // 6.2.1 |
| error(QString::fromLatin1("redefined group %1 has no occurrence in included schema").arg(formatKeyword(group->displayName(m_namePool)))); |
| return; |
| } |
| |
| if (sameNameCounter == 1) { |
| // there was a self reference in the redefined group, so use the |
| // group from the included schema |
| |
| // set a anonymous name to the group of the included schema |
| contextGroup->setName(m_parserContext->createAnonymousName(m_namePool->stringForNamespace(contextGroup->name(m_namePool).namespaceURI()))); |
| |
| // replace the self-reference with the group from the included schema |
| referencedParticle->setTerm(contextGroup); |
| |
| addElementGroup(group); |
| |
| addElementGroup(contextGroup); |
| contextGroups.removeAll(contextGroup); |
| } else { |
| // there was no self reference in the redefined group |
| |
| // just add the redefined group... |
| addElementGroup(group); |
| |
| // we have to add them, otherwise it is not resolved and we can't validate it later |
| contextGroup->setName(m_parserContext->createAnonymousName(m_namePool->stringForNamespace(contextGroup->name(m_namePool).namespaceURI()))); |
| addElementGroup(contextGroup); |
| |
| m_schemaResolver->addRedefinedGroups(group, contextGroup); |
| |
| // ...and forget about the group from the included schema |
| contextGroups.removeAll(contextGroup); |
| } |
| } |
| |
| // iterate over all redefined attribute groups |
| for (int i = 0; i < redefinedAttributeGroups.count(); ++i) { |
| const XsdAttributeGroup::Ptr group(redefinedAttributeGroups.at(i)); |
| |
| // @see http://www.w3.org/TR/xmlschema11-1/#src-redefine |
| |
| // 7 |
| |
| // 7.1 |
| int sameNameCounter = 0; |
| for (int j = 0; j < group->attributeUses().count(); ++j) { |
| const XsdAttributeUse::Ptr attributeUse(group->attributeUses().at(j)); |
| if (attributeUse->isReference()) { |
| const XsdAttributeReference::Ptr reference(attributeUse); |
| if (reference->type() == XsdAttributeReference::AttributeGroup) { |
| if (group->name(m_namePool) == reference->referenceName()) |
| sameNameCounter++; |
| } |
| } |
| } |
| if (sameNameCounter > 1) { |
| error(QString::fromLatin1("redefined attribute group %1 can not contain multiple references to itself").arg(formatKeyword(group->displayName(m_namePool)))); |
| return; |
| } |
| |
| // search the attribute group definition in the included schema (S2) |
| XsdAttributeGroup::Ptr baseGroup; |
| for (int j = 0; j < contextAttributeGroups.count(); ++j) { |
| const XsdAttributeGroup::Ptr contextGroup(contextAttributeGroups.at(j)); |
| if (group->name(m_namePool) == contextGroup->name(m_namePool)) { |
| baseGroup = contextGroup; |
| break; |
| } |
| } |
| |
| if (!baseGroup) { // 7.2.1 |
| error(QString::fromLatin1("redefined attribute group %1 has no occurrence in included schema").arg(formatKeyword(group->displayName(m_namePool)))); |
| return; |
| } |
| |
| if (sameNameCounter == 1) { |
| |
| // first set an anonymous name to the attribute group from the included |
| // schema |
| baseGroup->setName(m_parserContext->createAnonymousName(m_namePool->stringForNamespace(baseGroup->name(m_namePool).namespaceURI()))); |
| |
| // iterate over the attribute uses of the redefined attribute group |
| // and replace the self-reference with the attribute group from the |
| // included schema |
| for (int j = 0; j < group->attributeUses().count(); ++j) { |
| const XsdAttributeUse::Ptr attributeUse(group->attributeUses().at(j)); |
| if (attributeUse->isReference()) { |
| const XsdAttributeReference::Ptr reference(attributeUse); |
| if (reference->type() == XsdAttributeReference::AttributeGroup) { |
| if (group->name(m_namePool) == reference->referenceName()) { |
| reference->setReferenceName(baseGroup->name(m_namePool)); |
| break; |
| } |
| } |
| } |
| } |
| |
| // add both groups to the target schema |
| addAttributeGroup(baseGroup); |
| addAttributeGroup(group); |
| |
| contextAttributeGroups.removeAll(baseGroup); |
| } |
| |
| if (sameNameCounter == 0) { // 7.2 |
| |
| // we have to add them, otherwise it is not resolved and we can't validate it later |
| baseGroup->setName(m_parserContext->createAnonymousName(m_namePool->stringForNamespace(baseGroup->name(m_namePool).namespaceURI()))); |
| addAttributeGroup(baseGroup); |
| |
| m_schemaResolver->addRedefinedAttributeGroups(group, baseGroup); |
| |
| // just add the redefined attribute group to the target schema... |
| addAttributeGroup(group); |
| |
| // ... and forget about the one from the included schema |
| contextAttributeGroups.removeAll(baseGroup); |
| } |
| } |
| |
| // add all remaining context complex types to the schema |
| for (int i = 0; i < contextComplexTypes.count(); ++i) { |
| addType(contextComplexTypes.at(i)); |
| } |
| |
| // add all remaining context element groups to the schema |
| for (int i = 0; i < contextGroups.count(); ++i) { |
| addElementGroup(contextGroups.at(i)); |
| } |
| |
| // add all remaining context attribute groups to the schema |
| for (int i = 0; i < contextAttributeGroups.count(); ++i) { |
| addAttributeGroup(contextAttributeGroups.at(i)); |
| } |
| |
| // copy all elements, attributes and notations |
| const XsdElement::List contextElements = redefinedContext->schema()->elements(); |
| for (int i = 0; i < contextElements.count(); ++i) { |
| addElement(contextElements.at(i)); |
| } |
| |
| const XsdAttribute::List contextAttributes = redefinedContext->schema()->attributes(); |
| for (int i = 0; i < contextAttributes.count(); ++i) { |
| addAttribute(contextAttributes.at(i)); |
| } |
| |
| const XsdNotation::List contextNotations = redefinedContext->schema()->notations(); |
| for (int i = 0; i < contextNotations.count(); ++i) { |
| addNotation(contextNotations.at(i)); |
| } |
| |
| // push all data to resolve from the context resolver to our resolver |
| redefinedContext->resolver()->copyDataTo(m_parserContext->resolver()); |
| |
| tagValidator.finalize(); |
| } |
| |
| XsdAnnotation::Ptr XsdSchemaParser::parseAnnotation() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Annotation, this); |
| |
| validateElement(XsdTagScope::Annotation); |
| |
| // parse attributes |
| validateIdAttribute("annotation"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Annotation, this, m_namePool); |
| |
| const XsdAnnotation::Ptr annotation(new XsdAnnotation()); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Appinfo, token, namespaceToken)) { |
| const XsdApplicationInformation::Ptr info = parseAppInfo(); |
| annotation->addApplicationInformation(info); |
| } else if (isSchemaTag(XsdSchemaToken::Documentation, token, namespaceToken)) { |
| const XsdDocumentation::Ptr documentation = parseDocumentation(); |
| annotation->addDocumentation(documentation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return annotation; |
| } |
| |
| XsdApplicationInformation::Ptr XsdSchemaParser::parseAppInfo() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Appinfo, this); |
| |
| validateElement(XsdTagScope::AppInfo); |
| |
| const XsdApplicationInformation::Ptr info(new XsdApplicationInformation()); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("source"))) { |
| const QString value = readAttribute(QString::fromLatin1("source")); |
| |
| if (!isValidUri(value)) { |
| attributeContentError("source", "appinfo", value, BuiltinTypes::xsAnyURI); |
| return info; |
| } |
| |
| if (!value.isEmpty()) { |
| const AnyURI::Ptr source = AnyURI::fromLexical(value); |
| info->setSource(source); |
| } |
| } |
| |
| while (!atEnd()) { //EVAL: can be anything... what to do? |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) |
| parseUnknownDocumentation(); |
| } |
| |
| return info; |
| } |
| |
| XsdDocumentation::Ptr XsdSchemaParser::parseDocumentation() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Documentation, this); |
| |
| validateElement(XsdTagScope::Documentation); |
| |
| const XsdDocumentation::Ptr documentation(new XsdDocumentation()); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("source"))) { |
| const QString value = readAttribute(QString::fromLatin1("source")); |
| |
| if (!isValidUri(value)) { |
| attributeContentError("source", "documentation", value, BuiltinTypes::xsAnyURI); |
| return documentation; |
| } |
| |
| if (!value.isEmpty()) { |
| const AnyURI::Ptr source = AnyURI::fromLexical(value); |
| documentation->setSource(source); |
| } |
| } |
| |
| if (hasAttribute(CommonNamespaces::XML, QString::fromLatin1("lang"))) { |
| const QString value = readAttribute(QString::fromLatin1("lang"), CommonNamespaces::XML); |
| |
| QRegExp exp(QString::fromLatin1("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*")); |
| if (!exp.exactMatch(value)) { |
| attributeContentError("xml:lang", "documentation", value); |
| return documentation; |
| } |
| } |
| |
| while (!atEnd()) { //EVAL: can by any... what to do? |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) |
| parseUnknownDocumentation(); |
| } |
| |
| return documentation; |
| } |
| |
| void XsdSchemaParser::parseDefaultOpenContent() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::DefaultOpenContent, this); |
| |
| validateElement(XsdTagScope::DefaultOpenContent); |
| |
| m_defaultOpenContent = XsdComplexType::OpenContent::Ptr(new XsdComplexType::OpenContent()); |
| |
| if (hasAttribute(QString::fromLatin1("appliesToEmpty"))) { |
| const QString value = readAttribute(QString::fromLatin1("appliesToEmpty")); |
| const Boolean::Ptr appliesToEmpty = Boolean::fromLexical(value); |
| if (appliesToEmpty->hasError()) { |
| attributeContentError("appliesToEmpty", "defaultOpenContent", value, BuiltinTypes::xsBoolean); |
| return; |
| } |
| |
| m_defaultOpenContentAppliesToEmpty = appliesToEmpty->as<Boolean>()->value(); |
| } else { |
| m_defaultOpenContentAppliesToEmpty = false; |
| } |
| |
| if (hasAttribute(QString::fromLatin1("mode"))) { |
| const QString mode = readAttribute(QString::fromLatin1("mode")); |
| |
| if (mode == QString::fromLatin1("interleave")) { |
| m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Interleave); |
| } else if (mode == QString::fromLatin1("suffix")) { |
| m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Suffix); |
| } else { |
| attributeContentError("mode", "defaultOpenContent", mode); |
| return; |
| } |
| } else { |
| m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Interleave); |
| } |
| |
| validateIdAttribute("defaultOpenContent"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::DefaultOpenContent, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| m_defaultOpenContent->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { |
| const XsdParticle::Ptr particle; |
| const XsdWildcard::Ptr wildcard = parseAny(particle); |
| m_defaultOpenContent->setWildcard(wildcard); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| XsdSimpleType::Ptr XsdSchemaParser::parseGlobalSimpleType() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::SimpleType, this); |
| |
| validateElement(XsdTagScope::GlobalSimpleType); |
| |
| const XsdSimpleType::Ptr simpleType(new XsdSimpleType()); |
| simpleType->setCategory(XsdSimpleType::SimpleTypeAtomic); // just to make sure it's not invalid |
| |
| // parse attributes |
| const SchemaType::DerivationConstraints allowedConstraints(SchemaType::ExtensionConstraint | SchemaType::RestrictionConstraint | SchemaType::ListConstraint | SchemaType::UnionConstraint); |
| simpleType->setDerivationConstraints(readDerivationConstraintAttribute(allowedConstraints, "simpleType")); |
| |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("simpleType")); |
| simpleType->setName(objectName); |
| |
| validateIdAttribute("simpleType"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::GlobalSimpleType, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| simpleType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Restriction, token, namespaceToken)) { |
| parseSimpleRestriction(simpleType); |
| } else if (isSchemaTag(XsdSchemaToken::List, token, namespaceToken)) { |
| parseList(simpleType); |
| } else if (isSchemaTag(XsdSchemaToken::Union, token, namespaceToken)) { |
| parseUnion(simpleType); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return simpleType; |
| } |
| |
| XsdSimpleType::Ptr XsdSchemaParser::parseLocalSimpleType() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::SimpleType, this); |
| |
| validateElement(XsdTagScope::LocalSimpleType); |
| |
| const XsdSimpleType::Ptr simpleType(new XsdSimpleType()); |
| simpleType->setCategory(XsdSimpleType::SimpleTypeAtomic); // just to make sure it's not invalid |
| simpleType->setName(m_parserContext->createAnonymousName(m_targetNamespace)); |
| |
| validateIdAttribute("simpleType"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::LocalSimpleType, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| simpleType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Restriction, token, namespaceToken)) { |
| parseSimpleRestriction(simpleType); |
| } else if (isSchemaTag(XsdSchemaToken::List, token, namespaceToken)) { |
| parseList(simpleType); |
| } else if (isSchemaTag(XsdSchemaToken::Union, token, namespaceToken)) { |
| parseUnion(simpleType); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return simpleType; |
| } |
| |
| void XsdSchemaParser::parseSimpleRestriction(const XsdSimpleType::Ptr &ptr) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Restriction, this); |
| |
| validateElement(XsdTagScope::SimpleRestriction); |
| |
| ptr->setDerivationMethod(XsdSimpleType::DerivationRestriction); |
| |
| // The base attribute and simpleType member are mutually exclusive, |
| // so we keep track of that |
| bool hasBaseAttribute = false; |
| bool hasBaseTypeSpecified = false; |
| |
| QXmlName baseName; |
| if (hasAttribute(QString::fromLatin1("base"))) { |
| const QString base = readQNameAttribute(QString::fromLatin1("base"), "restriction"); |
| convertName(base, NamespaceSupport::ElementName, baseName); // translate qualified name into QXmlName |
| m_schemaResolver->addSimpleRestrictionBase(ptr, baseName, currentSourceLocation()); // add to resolver |
| |
| hasBaseAttribute = true; |
| hasBaseTypeSpecified = true; |
| } |
| validateIdAttribute("restriction"); |
| |
| XsdFacet::Hash facets; |
| QList<XsdFacet::Ptr> patternFacets; |
| QList<XsdFacet::Ptr> enumerationFacets; |
| QList<XsdFacet::Ptr> assertionFacets; |
| |
| TagValidationHandler tagValidator(XsdTagScope::SimpleRestriction, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| ptr->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| if (hasBaseAttribute) { |
| error(QtXmlPatterns::tr("%1 element is not allowed inside %2 element if %3 attribute is present.") |
| .arg(formatElement("simpleType")) |
| .arg(formatElement("restriction")) |
| .arg(formatAttribute("base"))); |
| return; |
| } |
| |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| type->setContext(ptr); |
| ptr->setWxsSuperType(type); |
| ptr->setCategory(type->category()); |
| hasBaseTypeSpecified = true; |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| } else if (isSchemaTag(XsdSchemaToken::MinExclusive, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMinExclusiveFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::MinInclusive, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMinInclusiveFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::MaxExclusive, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMaxExclusiveFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::MaxInclusive, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMaxInclusiveFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::TotalDigits, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseTotalDigitsFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::FractionDigits, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseFractionDigitsFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::Length, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseLengthFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::MinLength, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMinLengthFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::MaxLength, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMaxLengthFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::Enumeration, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseEnumerationFacet(); |
| enumerationFacets.append(facet); |
| } else if (isSchemaTag(XsdSchemaToken::WhiteSpace, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseWhiteSpaceFacet(); |
| addFacet(facet, facets, ptr); |
| } else if (isSchemaTag(XsdSchemaToken::Pattern, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parsePatternFacet(); |
| patternFacets.append(facet); |
| } else if (isSchemaTag(XsdSchemaToken::Assertion, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseAssertionFacet(); |
| assertionFacets.append(facet); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| if (!hasBaseTypeSpecified) { |
| error(QtXmlPatterns::tr("%1 element has neither %2 attribute nor %3 child element.") |
| .arg(formatElement("restriction")) |
| .arg(formatAttribute("base")) |
| .arg(formatElement("simpleType"))); |
| return; |
| } |
| |
| // merge all pattern facets into one multi value facet |
| if (!patternFacets.isEmpty()) { |
| const XsdFacet::Ptr patternFacet(new XsdFacet()); |
| patternFacet->setType(XsdFacet::Pattern); |
| |
| AtomicValue::List multiValue; |
| for (int i = 0; i < patternFacets.count(); ++i) |
| multiValue << patternFacets.at(i)->multiValue(); |
| |
| patternFacet->setMultiValue(multiValue); |
| addFacet(patternFacet, facets, ptr); |
| } |
| |
| // merge all enumeration facets into one multi value facet |
| if (!enumerationFacets.isEmpty()) { |
| const XsdFacet::Ptr enumerationFacet(new XsdFacet()); |
| enumerationFacet->setType(XsdFacet::Enumeration); |
| |
| AtomicValue::List multiValue; |
| for (int i = 0; i < enumerationFacets.count(); ++i) |
| multiValue << enumerationFacets.at(i)->multiValue(); |
| |
| enumerationFacet->setMultiValue(multiValue); |
| addFacet(enumerationFacet, facets, ptr); |
| } |
| |
| // merge all assertion facets into one facet |
| if (!assertionFacets.isEmpty()) { |
| const XsdFacet::Ptr assertionFacet(new XsdFacet()); |
| assertionFacet->setType(XsdFacet::Assertion); |
| |
| XsdAssertion::List assertions; |
| for (int i = 0; i < assertionFacets.count(); ++i) |
| assertions << assertionFacets.at(i)->assertions(); |
| |
| assertionFacet->setAssertions(assertions); |
| addFacet(assertionFacet, facets, ptr); |
| } |
| |
| ptr->setFacets(facets); |
| |
| tagValidator.finalize(); |
| } |
| |
| void XsdSchemaParser::parseList(const XsdSimpleType::Ptr &ptr) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::List, this); |
| |
| validateElement(XsdTagScope::List); |
| |
| ptr->setCategory(XsdSimpleType::SimpleTypeList); |
| ptr->setDerivationMethod(XsdSimpleType::DerivationList); |
| ptr->setWxsSuperType(BuiltinTypes::xsAnySimpleType); |
| |
| // The itemType attribute and simpleType member are mutually exclusive, |
| // so we keep track of that |
| bool hasItemTypeAttribute = false; |
| bool hasItemTypeSpecified = false; |
| |
| if (hasAttribute(QString::fromLatin1("itemType"))) { |
| const QString itemType = readQNameAttribute(QString::fromLatin1("itemType"), "list"); |
| QXmlName typeName; |
| convertName(itemType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addSimpleListType(ptr, typeName, currentSourceLocation()); // add to resolver |
| |
| hasItemTypeAttribute = true; |
| hasItemTypeSpecified = true; |
| } |
| |
| validateIdAttribute("list"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::List, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| ptr->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| if (hasItemTypeAttribute) { |
| error(QtXmlPatterns::tr("%1 element is not allowed inside %2 element if %3 attribute is present.") |
| .arg(formatElement("simpleType")) |
| .arg(formatElement("list")) |
| .arg(formatAttribute("itemType"))); |
| return; |
| } |
| |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| type->setContext(ptr); |
| ptr->setItemType(type); |
| |
| hasItemTypeSpecified = true; |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| if (!hasItemTypeSpecified) { |
| error(QtXmlPatterns::tr("%1 element has neither %2 attribute nor %3 child element.") |
| .arg(formatElement("list")) |
| .arg(formatAttribute("itemType")) |
| .arg(formatElement("simpleType"))); |
| return; |
| } |
| |
| tagValidator.finalize(); |
| |
| // add the default white space facet that every simple type with list derivation has |
| const XsdFacet::Ptr defaultFacet(new XsdFacet()); |
| defaultFacet->setType(XsdFacet::WhiteSpace); |
| defaultFacet->setFixed(true); |
| defaultFacet->setValue(DerivedString<TypeString>::fromLexical(m_namePool, XsdSchemaToken::toString(XsdSchemaToken::Collapse))); |
| XsdFacet::Hash facets; |
| facets.insert(defaultFacet->type(), defaultFacet); |
| ptr->setFacets(facets); |
| } |
| |
| void XsdSchemaParser::parseUnion(const XsdSimpleType::Ptr &ptr) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Union, this); |
| |
| validateElement(XsdTagScope::Union); |
| |
| ptr->setCategory(XsdSimpleType::SimpleTypeUnion); |
| ptr->setDerivationMethod(XsdSimpleType::DerivationUnion); |
| ptr->setWxsSuperType(BuiltinTypes::xsAnySimpleType); |
| |
| // The memberTypes attribute is not allowed to be empty, |
| // so we keep track of that |
| bool hasMemberTypesSpecified = false; |
| |
| if (hasAttribute(QString::fromLatin1("memberTypes"))) { |
| const QStringList memberTypes = readAttribute(QString::fromLatin1("memberTypes")).split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| QList<QXmlName> typeNames; |
| |
| for (int i = 0; i < memberTypes.count(); ++i) { |
| QXmlName typeName; |
| convertName(memberTypes.at(i), NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| typeNames.append(typeName); |
| } |
| |
| if (!typeNames.isEmpty()) { |
| m_schemaResolver->addSimpleUnionTypes(ptr, typeNames, currentSourceLocation()); // add to resolver |
| hasMemberTypesSpecified = true; |
| } |
| } |
| |
| validateIdAttribute("union"); |
| |
| AnySimpleType::List memberTypes; |
| |
| TagValidationHandler tagValidator(XsdTagScope::Union, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| ptr->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| type->setContext(ptr); |
| memberTypes.append(type); |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| if (!memberTypes.isEmpty()) { |
| ptr->setMemberTypes(memberTypes); |
| hasMemberTypesSpecified = true; |
| } |
| |
| if (!hasMemberTypesSpecified) { |
| error(QtXmlPatterns::tr("%1 element has neither %2 attribute nor %3 child element.") |
| .arg(formatElement("union")) |
| .arg(formatAttribute("memberTypes")) |
| .arg(formatElement("simpleType"))); |
| return; |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseMinExclusiveFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MinExclusive, this); |
| |
| validateElement(XsdTagScope::MinExclusiveFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::MinimumExclusive); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "minExclusive", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| // as minExclusive can have a value of type anySimpleType, we just read |
| // the string here and store it for later intepretation |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| if (string->hasError()) { |
| attributeContentError("value", "minExclusive", value, BuiltinTypes::xsAnySimpleType); |
| return facet; |
| } else { |
| facet->setValue(string); |
| } |
| |
| validateIdAttribute("minExclusive"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::MinExclusiveFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseMinInclusiveFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MinInclusive, this); |
| |
| validateElement(XsdTagScope::MinInclusiveFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::MinimumInclusive); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "minInclusive", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| // as minInclusive can have a value of type anySimpleType, we just read |
| // the string here and store it for later intepretation |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| if (string->hasError()) { |
| attributeContentError("value", "minInclusive", value, BuiltinTypes::xsAnySimpleType); |
| return facet; |
| } else { |
| facet->setValue(string); |
| } |
| |
| validateIdAttribute("minInclusive"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::MinInclusiveFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseMaxExclusiveFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MaxExclusive, this); |
| |
| validateElement(XsdTagScope::MaxExclusiveFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::MaximumExclusive); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "maxExclusive", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| // as maxExclusive can have a value of type anySimpleType, we just read |
| // the string here and store it for later intepretation |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| if (string->hasError()) { |
| attributeContentError("value", "maxExclusive", value, BuiltinTypes::xsAnySimpleType); |
| return facet; |
| } else { |
| facet->setValue(string); |
| } |
| |
| validateIdAttribute("maxExclusive"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::MaxExclusiveFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseMaxInclusiveFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MaxInclusive, this); |
| |
| validateElement(XsdTagScope::MaxInclusiveFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::MaximumInclusive); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "maxInclusive", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| // as maxInclusive can have a value of type anySimpleType, we just read |
| // the string here and store it for later intepretation |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| if (string->hasError()) { |
| attributeContentError("value", "maxInclusive", value, BuiltinTypes::xsAnySimpleType); |
| return facet; |
| } else { |
| facet->setValue(string); |
| } |
| |
| validateIdAttribute("maxInclusive"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::MaxInclusiveFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseTotalDigitsFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::TotalDigits, this); |
| |
| validateElement(XsdTagScope::TotalDigitsFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::TotalDigits); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "totalDigits", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedInteger<TypePositiveInteger>::Ptr integer = DerivedInteger<TypePositiveInteger>::fromLexical(m_namePool, value); |
| if (integer->hasError()) { |
| attributeContentError("value", "totalDigits", value, BuiltinTypes::xsPositiveInteger); |
| return facet; |
| } else { |
| facet->setValue(integer); |
| } |
| |
| validateIdAttribute("totalDigits"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::TotalDigitsFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseFractionDigitsFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::FractionDigits, this); |
| |
| validateElement(XsdTagScope::FractionDigitsFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::FractionDigits); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "fractionDigits", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); |
| if (integer->hasError()) { |
| attributeContentError("value", "fractionDigits", value, BuiltinTypes::xsNonNegativeInteger); |
| return facet; |
| } else { |
| facet->setValue(integer); |
| } |
| |
| validateIdAttribute("fractionDigits"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::FractionDigitsFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseLengthFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Length, this); |
| |
| validateElement(XsdTagScope::LengthFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::Length); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "length", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); |
| if (integer->hasError()) { |
| attributeContentError("value", "length", value, BuiltinTypes::xsNonNegativeInteger); |
| return facet; |
| } else { |
| facet->setValue(integer); |
| } |
| |
| validateIdAttribute("length"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::LengthFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseMinLengthFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MinLength, this); |
| |
| validateElement(XsdTagScope::MinLengthFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::MinimumLength); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "minLength", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); |
| if (integer->hasError()) { |
| attributeContentError("value", "minLength", value, BuiltinTypes::xsNonNegativeInteger); |
| return facet; |
| } else { |
| facet->setValue(integer); |
| } |
| |
| validateIdAttribute("minLength"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::MinLengthFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseMaxLengthFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::MaxLength, this); |
| |
| validateElement(XsdTagScope::MaxLengthFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::MaximumLength); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "maxLength", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); |
| if (integer->hasError()) { |
| attributeContentError("value", "maxLength", value, BuiltinTypes::xsNonNegativeInteger); |
| return facet; |
| } else { |
| facet->setValue(integer); |
| } |
| |
| validateIdAttribute("maxLength"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::MaxLengthFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseEnumerationFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Enumeration, this); |
| |
| validateElement(XsdTagScope::EnumerationFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::Enumeration); |
| |
| // parse attributes |
| facet->setFixed(false); // not defined in schema, but can't hurt |
| |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| |
| // as enumeration can have a value of type anySimpleType, we just read |
| // the string here and store it for later intepretation |
| DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| if (string->hasError()) { |
| attributeContentError("value", "enumeration", value); |
| return facet; |
| } else { |
| AtomicValue::List multiValue; |
| multiValue << string; |
| facet->setMultiValue(multiValue); |
| } |
| m_schemaResolver->addEnumerationFacetValue(string, m_namespaceSupport); |
| |
| validateIdAttribute("enumeration"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::EnumerationFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseWhiteSpaceFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::WhiteSpace, this); |
| |
| validateElement(XsdTagScope::WhiteSpaceFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::WhiteSpace); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| const Boolean::Ptr fixed = Boolean::fromLexical(value); |
| if (fixed->hasError()) { |
| attributeContentError("fixed", "whiteSpace", value, BuiltinTypes::xsBoolean); |
| return facet; |
| } |
| |
| facet->setFixed(fixed->as<Boolean>()->value()); |
| } else { |
| facet->setFixed(false); // the default value |
| } |
| |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| if (value != XsdSchemaToken::toString(XsdSchemaToken::Collapse) && |
| value != XsdSchemaToken::toString(XsdSchemaToken::Preserve) && |
| value != XsdSchemaToken::toString(XsdSchemaToken::Replace)) { |
| attributeContentError("value", "whiteSpace", value); |
| return facet; |
| } else { |
| DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| if (string->hasError()) { |
| attributeContentError("value", "whiteSpace", value); |
| return facet; |
| } else { |
| facet->setValue(string); |
| } |
| } |
| |
| validateIdAttribute("whiteSpace"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::WhiteSpaceFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parsePatternFacet() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Pattern, this); |
| |
| validateElement(XsdTagScope::PatternFacet); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::Pattern); |
| |
| // parse attributes |
| |
| // as pattern can have a value of type anySimpleType, we just read |
| // the string here and store it for later intepretation |
| const QString value = readAttribute(QString::fromLatin1("value")); |
| DerivedString<TypeString>::Ptr string = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| if (string->hasError()) { |
| attributeContentError("value", "pattern", value); |
| return facet; |
| } else { |
| AtomicValue::List multiValue; |
| multiValue << string; |
| facet->setMultiValue(multiValue); |
| } |
| |
| validateIdAttribute("pattern"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::PatternFacet, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| facet->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return facet; |
| } |
| |
| XsdFacet::Ptr XsdSchemaParser::parseAssertionFacet() |
| { |
| // this is just a wrapper function around the parseAssertion() method |
| |
| const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assertion, XsdTagScope::Assertion); |
| |
| const XsdFacet::Ptr facet = XsdFacet::Ptr(new XsdFacet()); |
| facet->setType(XsdFacet::Assertion); |
| facet->setAssertions(XsdAssertion::List() << assertion); |
| |
| return facet; |
| } |
| |
| XsdComplexType::Ptr XsdSchemaParser::parseGlobalComplexType() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::ComplexType, this); |
| |
| validateElement(XsdTagScope::GlobalComplexType); |
| |
| bool hasTypeSpecified = false; |
| bool hasComplexContent = false; |
| |
| const XsdComplexType::Ptr complexType(new XsdComplexType()); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("abstract"))) { |
| const QString abstract = readAttribute(QString::fromLatin1("abstract")); |
| |
| const Boolean::Ptr value = Boolean::fromLexical(abstract); |
| if (value->hasError()) { |
| attributeContentError("abstract", "complexType", abstract, BuiltinTypes::xsBoolean); |
| return complexType; |
| } |
| |
| complexType->setIsAbstract(value->as<Boolean>()->value()); |
| } else { |
| complexType->setIsAbstract(false); // default value |
| } |
| |
| complexType->setProhibitedSubstitutions(readBlockingConstraintAttribute(NamedSchemaComponent::ExtensionConstraint | NamedSchemaComponent::RestrictionConstraint, "complexType")); |
| complexType->setDerivationConstraints(readDerivationConstraintAttribute(SchemaType::ExtensionConstraint | SchemaType::RestrictionConstraint, "complexType")); |
| |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("complexType")); |
| complexType->setName(objectName); |
| |
| bool effectiveMixed = false; |
| if (hasAttribute(QString::fromLatin1("mixed"))) { |
| const QString mixed = readAttribute(QString::fromLatin1("mixed")); |
| |
| const Boolean::Ptr value = Boolean::fromLexical(mixed); |
| if (value->hasError()) { |
| attributeContentError("mixed", "complexType", mixed, BuiltinTypes::xsBoolean); |
| return complexType; |
| } |
| |
| effectiveMixed = value->as<Boolean>()->value(); |
| } |
| |
| validateIdAttribute("complexType"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::GlobalComplexType, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| complexType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleContent, token, namespaceToken)) { |
| if (effectiveMixed) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("complexType")) |
| .arg(formatElement("simpleContent")) |
| .arg(formatAttribute("mixed"))); |
| return complexType; |
| } |
| |
| parseSimpleContent(complexType); |
| hasTypeSpecified = true; |
| } else if (isSchemaTag(XsdSchemaToken::ComplexContent, token, namespaceToken)) { |
| bool mixed; |
| parseComplexContent(complexType, &mixed); |
| hasTypeSpecified = true; |
| |
| effectiveMixed = (effectiveMixed || mixed); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::OpenContent, token, namespaceToken)) { |
| const XsdComplexType::OpenContent::Ptr openContent = parseOpenContent(); |
| complexType->contentType()->setOpenContent(openContent); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseReferredGroup(particle); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalAll(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalChoice(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalSequence(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); |
| complexType->addAttributeUse(attributeUse); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); |
| complexType->addAttributeUse(attributeUse); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { |
| const XsdWildcard::Ptr wildcard = parseAnyAttribute(); |
| complexType->setAttributeWildcard(wildcard); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { |
| const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); |
| complexType->addAssertion(assertion); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| if (!hasTypeSpecified) { |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } |
| |
| if (hasComplexContent == true) { |
| resolveComplexContentType(complexType, effectiveMixed); |
| } |
| |
| return complexType; |
| } |
| |
| XsdComplexType::Ptr XsdSchemaParser::parseLocalComplexType() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::ComplexType, this); |
| |
| validateElement(XsdTagScope::LocalComplexType); |
| |
| bool hasTypeSpecified = false; |
| bool hasComplexContent = true; |
| |
| const XsdComplexType::Ptr complexType(new XsdComplexType()); |
| complexType->setName(m_parserContext->createAnonymousName(m_targetNamespace)); |
| |
| // parse attributes |
| bool effectiveMixed = false; |
| if (hasAttribute(QString::fromLatin1("mixed"))) { |
| const QString mixed = readAttribute(QString::fromLatin1("mixed")); |
| |
| const Boolean::Ptr value = Boolean::fromLexical(mixed); |
| if (value->hasError()) { |
| attributeContentError("mixed", "complexType", mixed, BuiltinTypes::xsBoolean); |
| return complexType; |
| } |
| |
| effectiveMixed = value->as<Boolean>()->value(); |
| } |
| |
| validateIdAttribute("complexType"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::LocalComplexType, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| complexType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleContent, token, namespaceToken)) { |
| parseSimpleContent(complexType); |
| hasTypeSpecified = true; |
| } else if (isSchemaTag(XsdSchemaToken::ComplexContent, token, namespaceToken)) { |
| bool mixed; |
| parseComplexContent(complexType, &mixed); |
| hasTypeSpecified = true; |
| |
| effectiveMixed = (effectiveMixed || mixed); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::OpenContent, token, namespaceToken)) { |
| const XsdComplexType::OpenContent::Ptr openContent = parseOpenContent(); |
| complexType->contentType()->setOpenContent(openContent); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseReferredGroup(particle); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalAll(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalChoice(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalSequence(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); |
| complexType->addAttributeUse(attributeUse); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); |
| complexType->addAttributeUse(attributeUse); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { |
| const XsdWildcard::Ptr wildcard = parseAnyAttribute(); |
| complexType->setAttributeWildcard(wildcard); |
| |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { |
| const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); |
| complexType->addAssertion(assertion); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| if (!hasTypeSpecified) { |
| complexType->setWxsSuperType(BuiltinTypes::xsAnyType); |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| hasComplexContent = true; |
| } |
| |
| if (hasComplexContent == true) { |
| resolveComplexContentType(complexType, effectiveMixed); |
| } |
| |
| return complexType; |
| } |
| |
| void XsdSchemaParser::resolveComplexContentType(const XsdComplexType::Ptr &complexType, bool effectiveMixed) |
| { |
| // @see http://www.w3.org/TR/xmlschema11-1/#dcl.ctd.ctcc.common |
| |
| // 1 |
| // the effectiveMixed contains the effective mixed value |
| |
| // 2 |
| bool hasEmptyContent = false; |
| if (!complexType->contentType()->particle()) { |
| hasEmptyContent = true; // 2.1.1 |
| } else { |
| if (complexType->contentType()->particle()->term()->isModelGroup()) { |
| const XsdModelGroup::Ptr group = complexType->contentType()->particle()->term(); |
| if (group->compositor() == XsdModelGroup::SequenceCompositor || group->compositor() == XsdModelGroup::AllCompositor) { |
| if (group->particles().isEmpty()) |
| hasEmptyContent = true; // 2.1.2 |
| } else if (group->compositor() == XsdModelGroup::ChoiceCompositor) { |
| if ((complexType->contentType()->particle()->minimumOccurs() == 0) && group->particles().isEmpty()) |
| hasEmptyContent = true; // 2.1.3 |
| } |
| |
| if ((complexType->contentType()->particle()->maximumOccursUnbounded() == false) && (complexType->contentType()->particle()->maximumOccurs() == 0)) |
| hasEmptyContent = true; // 2.1.4 |
| } |
| } |
| |
| const XsdParticle::Ptr explicitContent = (hasEmptyContent ? XsdParticle::Ptr() : complexType->contentType()->particle()); |
| |
| // do all the other work (3, 4, 5 and 6) in the resolver, as they need access to the base type object |
| m_schemaResolver->addComplexContentType(complexType, explicitContent, effectiveMixed); |
| } |
| |
| void XsdSchemaParser::parseSimpleContent(const XsdComplexType::Ptr &complexType) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::SimpleContent, this); |
| |
| validateElement(XsdTagScope::SimpleContent); |
| |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::Simple); |
| |
| // parse attributes |
| validateIdAttribute("simpleContent"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::SimpleContent, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| complexType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Restriction, token, namespaceToken)) { |
| parseSimpleContentRestriction(complexType); |
| } else if (isSchemaTag(XsdSchemaToken::Extension, token, namespaceToken)) { |
| parseSimpleContentExtension(complexType); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| void XsdSchemaParser::parseSimpleContentRestriction(const XsdComplexType::Ptr &complexType) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Restriction, this); |
| |
| validateElement(XsdTagScope::SimpleContentRestriction); |
| |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| |
| // parse attributes |
| const QString baseType = readQNameAttribute(QString::fromLatin1("base"), "restriction"); |
| QXmlName typeName; |
| convertName(baseType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| |
| validateIdAttribute("restriction"); |
| |
| XsdFacet::Hash facets; |
| QList<XsdFacet::Ptr> patternFacets; |
| QList<XsdFacet::Ptr> enumerationFacets; |
| QList<XsdFacet::Ptr> assertionFacets; |
| |
| TagValidationHandler tagValidator(XsdTagScope::SimpleContentRestriction, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| complexType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| type->setContext(complexType); //TODO: investigate what the schema spec really wants here?!? |
| complexType->contentType()->setSimpleType(type); |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| } else if (isSchemaTag(XsdSchemaToken::MinExclusive, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMinExclusiveFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::MinInclusive, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMinInclusiveFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::MaxExclusive, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMaxExclusiveFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::MaxInclusive, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMaxInclusiveFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::TotalDigits, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseTotalDigitsFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::FractionDigits, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseFractionDigitsFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::Length, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseLengthFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::MinLength, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMinLengthFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::MaxLength, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseMaxLengthFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::Enumeration, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseEnumerationFacet(); |
| enumerationFacets.append(facet); |
| } else if (isSchemaTag(XsdSchemaToken::WhiteSpace, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseWhiteSpaceFacet(); |
| addFacet(facet, facets, complexType); |
| } else if (isSchemaTag(XsdSchemaToken::Pattern, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parsePatternFacet(); |
| patternFacets.append(facet); |
| } else if (isSchemaTag(XsdSchemaToken::Assertion, token, namespaceToken)) { |
| const XsdFacet::Ptr facet = parseAssertionFacet(); |
| assertionFacets.append(facet); |
| } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); |
| complexType->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); |
| complexType->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { |
| const XsdWildcard::Ptr wildcard = parseAnyAttribute(); |
| complexType->setAttributeWildcard(wildcard); |
| } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { |
| const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); |
| complexType->addAssertion(assertion); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| // merge all pattern facets into one multi value facet |
| if (!patternFacets.isEmpty()) { |
| const XsdFacet::Ptr patternFacet(new XsdFacet()); |
| patternFacet->setType(XsdFacet::Pattern); |
| |
| AtomicValue::List multiValue; |
| for (int i = 0; i < patternFacets.count(); ++i) |
| multiValue << patternFacets.at(i)->multiValue(); |
| |
| patternFacet->setMultiValue(multiValue); |
| addFacet(patternFacet, facets, complexType); |
| } |
| |
| // merge all enumeration facets into one multi value facet |
| if (!enumerationFacets.isEmpty()) { |
| const XsdFacet::Ptr enumerationFacet(new XsdFacet()); |
| enumerationFacet->setType(XsdFacet::Enumeration); |
| |
| AtomicValue::List multiValue; |
| for (int i = 0; i < enumerationFacets.count(); ++i) |
| multiValue << enumerationFacets.at(i)->multiValue(); |
| |
| enumerationFacet->setMultiValue(multiValue); |
| addFacet(enumerationFacet, facets, complexType); |
| } |
| |
| // merge all assertion facets into one facet |
| if (!assertionFacets.isEmpty()) { |
| const XsdFacet::Ptr assertionFacet(new XsdFacet()); |
| assertionFacet->setType(XsdFacet::Assertion); |
| |
| XsdAssertion::List assertions; |
| for (int i = 0; i < assertionFacets.count(); ++i) |
| assertions << assertionFacets.at(i)->assertions(); |
| |
| assertionFacet->setAssertions(assertions); |
| addFacet(assertionFacet, facets, complexType); |
| } |
| |
| m_schemaResolver->addComplexBaseType(complexType, typeName, currentSourceLocation(), facets); // add to resolver |
| } |
| |
| void XsdSchemaParser::parseSimpleContentExtension(const XsdComplexType::Ptr &complexType) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Extension, this); |
| |
| validateElement(XsdTagScope::SimpleContentExtension); |
| |
| complexType->setDerivationMethod(XsdComplexType::DerivationExtension); |
| |
| // parse attributes |
| const QString baseType = readQNameAttribute(QString::fromLatin1("base"), "extension"); |
| QXmlName typeName; |
| convertName(baseType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addComplexBaseType(complexType, typeName, currentSourceLocation()); // add to resolver |
| |
| validateIdAttribute("extension"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::SimpleContentExtension, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| complexType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); |
| complexType->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); |
| complexType->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { |
| const XsdWildcard::Ptr wildcard = parseAnyAttribute(); |
| complexType->setAttributeWildcard(wildcard); |
| } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { |
| const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); |
| complexType->addAssertion(assertion); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| void XsdSchemaParser::parseComplexContent(const XsdComplexType::Ptr &complexType, bool *mixed) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::ComplexContent, this); |
| |
| validateElement(XsdTagScope::ComplexContent); |
| |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::ElementOnly); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("mixed"))) { |
| const QString mixedStr = readAttribute(QString::fromLatin1("mixed")); |
| |
| const Boolean::Ptr value = Boolean::fromLexical(mixedStr); |
| if (value->hasError()) { |
| attributeContentError("mixed", "complexType", mixedStr, BuiltinTypes::xsBoolean); |
| return; |
| } |
| |
| *mixed = value->as<Boolean>()->value(); |
| } else { |
| *mixed = false; |
| } |
| |
| validateIdAttribute("complexContent"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::ComplexContent, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| complexType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Restriction, token, namespaceToken)) { |
| parseComplexContentRestriction(complexType); |
| } else if (isSchemaTag(XsdSchemaToken::Extension, token, namespaceToken)) { |
| parseComplexContentExtension(complexType); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| void XsdSchemaParser::parseComplexContentRestriction(const XsdComplexType::Ptr &complexType) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Restriction, this); |
| |
| validateElement(XsdTagScope::ComplexContentRestriction); |
| |
| complexType->setDerivationMethod(XsdComplexType::DerivationRestriction); |
| |
| // parse attributes |
| const QString baseType = readQNameAttribute(QString::fromLatin1("base"), "restriction"); |
| QXmlName typeName; |
| convertName(baseType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addComplexBaseType(complexType, typeName, currentSourceLocation()); // add to resolver |
| |
| validateIdAttribute("restriction"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::ComplexContentRestriction, this, m_namePool); |
| |
| bool hasContent = false; |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| complexType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::OpenContent, token, namespaceToken)) { |
| const XsdComplexType::OpenContent::Ptr openContent = parseOpenContent(); |
| complexType->contentType()->setOpenContent(openContent); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseReferredGroup(particle); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalAll(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalChoice(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalSequence(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); |
| complexType->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); |
| complexType->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { |
| const XsdWildcard::Ptr wildcard = parseAnyAttribute(); |
| complexType->setAttributeWildcard(wildcard); |
| } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { |
| const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); |
| complexType->addAssertion(assertion); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| if (!hasContent) |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::Empty); |
| |
| tagValidator.finalize(); |
| } |
| |
| void XsdSchemaParser::parseComplexContentExtension(const XsdComplexType::Ptr &complexType) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Extension, this); |
| |
| validateElement(XsdTagScope::ComplexContentExtension); |
| |
| complexType->setDerivationMethod(XsdComplexType::DerivationExtension); |
| |
| // parse attributes |
| const QString baseType = readQNameAttribute(QString::fromLatin1("base"), "extension"); |
| QXmlName typeName; |
| convertName(baseType, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addComplexBaseType(complexType, typeName, currentSourceLocation()); // add to resolver |
| |
| validateIdAttribute("extension"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::ComplexContentExtension, this, m_namePool); |
| |
| bool hasContent = false; |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| complexType->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::OpenContent, token, namespaceToken)) { |
| const XsdComplexType::OpenContent::Ptr openContent = parseOpenContent(); |
| complexType->contentType()->setOpenContent(openContent); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseReferredGroup(particle); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalAll(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalChoice(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalSequence(particle, complexType); |
| particle->setTerm(term); |
| complexType->contentType()->setParticle(particle); |
| hasContent = true; |
| } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(complexType); |
| complexType->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); |
| complexType->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { |
| const XsdWildcard::Ptr wildcard = parseAnyAttribute(); |
| complexType->setAttributeWildcard(wildcard); |
| } else if (isSchemaTag(XsdSchemaToken::Assert, token, namespaceToken)) { |
| const XsdAssertion::Ptr assertion = parseAssertion(XsdSchemaToken::Assert, XsdTagScope::Assert); |
| complexType->addAssertion(assertion); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| if (!hasContent) |
| complexType->contentType()->setVariety(XsdComplexType::ContentType::Empty); |
| |
| tagValidator.finalize(); |
| } |
| |
| |
| XsdAssertion::Ptr XsdSchemaParser::parseAssertion(const XsdSchemaToken::NodeName &nodeName, const XsdTagScope::Type &tag) |
| { |
| const ElementNamespaceHandler namespaceHandler(nodeName, this); |
| |
| validateElement(tag); |
| |
| const XsdAssertion::Ptr assertion(new XsdAssertion()); |
| |
| // parse attributes |
| |
| const XsdXPathExpression::Ptr expression = readXPathExpression("assertion"); |
| assertion->setTest(expression); |
| |
| const QString test = readXPathAttribute(QString::fromLatin1("test"), XPath20, "assertion"); |
| expression->setExpression(test); |
| |
| validateIdAttribute("assertion"); |
| |
| TagValidationHandler tagValidator(tag, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| assertion->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return assertion; |
| } |
| |
| XsdComplexType::OpenContent::Ptr XsdSchemaParser::parseOpenContent() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::OpenContent, this); |
| |
| validateElement(XsdTagScope::OpenContent); |
| |
| const XsdComplexType::OpenContent::Ptr openContent(new XsdComplexType::OpenContent()); |
| |
| if (hasAttribute(QString::fromLatin1("mode"))) { |
| const QString mode = readAttribute(QString::fromLatin1("mode")); |
| |
| if (mode == QString::fromLatin1("none")) { |
| m_defaultOpenContent->setMode(XsdComplexType::OpenContent::None); |
| } else if (mode == QString::fromLatin1("interleave")) { |
| m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Interleave); |
| } else if (mode == QString::fromLatin1("suffix")) { |
| m_defaultOpenContent->setMode(XsdComplexType::OpenContent::Suffix); |
| } else { |
| attributeContentError("mode", "openContent", mode); |
| return openContent; |
| } |
| } else { |
| openContent->setMode(XsdComplexType::OpenContent::Interleave); |
| } |
| |
| validateIdAttribute("openContent"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::OpenContent, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| openContent->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { |
| const XsdParticle::Ptr particle; |
| const XsdWildcard::Ptr wildcard = parseAny(particle); |
| openContent->setWildcard(wildcard); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return openContent; |
| } |
| |
| XsdModelGroup::Ptr XsdSchemaParser::parseNamedGroup() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Group, this); |
| |
| validateElement(XsdTagScope::NamedGroup); |
| |
| const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); |
| XsdModelGroup::Ptr group; |
| |
| QXmlName objectName; |
| if (hasAttribute(QString::fromLatin1("name"))) { |
| objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("group")); |
| } |
| |
| validateIdAttribute("group"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::NamedGroup, this, m_namePool); |
| |
| XsdAnnotation::Ptr annotation; |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| annotation = parseAnnotation(); |
| } else if (isSchemaTag(XsdSchemaToken::All, token, namespaceToken)) { |
| group = parseAll(modelGroup); |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| group = parseChoice(modelGroup); |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| group = parseSequence(modelGroup); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| group->setName(objectName); |
| |
| if (annotation) |
| group->addAnnotation(annotation); |
| |
| return group; |
| } |
| |
| XsdTerm::Ptr XsdSchemaParser::parseReferredGroup(const XsdParticle::Ptr &particle) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Group, this); |
| |
| validateElement(XsdTagScope::ReferredGroup); |
| |
| const XsdReference::Ptr reference(new XsdReference()); |
| reference->setType(XsdReference::ModelGroup); |
| reference->setSourceLocation(currentSourceLocation()); |
| |
| // parse attributes |
| if (!parseMinMaxConstraint(particle, "group")) { |
| return reference; |
| } |
| |
| const QString value = readQNameAttribute(QString::fromLatin1("ref"), "group"); |
| QXmlName referenceName; |
| convertName(value, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName |
| reference->setReferenceName(referenceName); |
| |
| validateIdAttribute("group"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::ReferredGroup, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| reference->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return reference; |
| } |
| |
| XsdModelGroup::Ptr XsdSchemaParser::parseAll(const NamedSchemaComponent::Ptr &parent) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::All, this); |
| |
| validateElement(XsdTagScope::All); |
| |
| const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); |
| modelGroup->setCompositor(XsdModelGroup::AllCompositor); |
| |
| validateIdAttribute("all"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::All, this, m_namePool); |
| |
| XsdParticle::List particles; |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| modelGroup->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalElement(particle, parent); |
| particle->setTerm(term); |
| |
| if (particle->maximumOccursUnbounded() || particle->maximumOccurs() > 1) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must be %3 or %4.") |
| .arg(formatAttribute("maxOccurs")) |
| .arg(formatElement("all")) |
| .arg(formatData("0")) |
| .arg(formatData("1"))); |
| return modelGroup; |
| } |
| |
| particles.append(particle); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| modelGroup->setParticles(particles); |
| |
| tagValidator.finalize(); |
| |
| return modelGroup; |
| } |
| |
| XsdModelGroup::Ptr XsdSchemaParser::parseLocalAll(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::All, this); |
| |
| validateElement(XsdTagScope::LocalAll); |
| |
| const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); |
| modelGroup->setCompositor(XsdModelGroup::AllCompositor); |
| |
| // parse attributes |
| if (!parseMinMaxConstraint(particle, "all")) { |
| return modelGroup; |
| } |
| if (particle->maximumOccursUnbounded() || particle->maximumOccurs() != 1) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must have a value of %3.") |
| .arg(formatAttribute("maxOccurs")) |
| .arg(formatElement("all")) |
| .arg(formatData("1"))); |
| return modelGroup; |
| } |
| if (particle->minimumOccurs() != 0 && particle->minimumOccurs() != 1) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must have a value of %3 or %4.") |
| .arg(formatAttribute("minOccurs")) |
| .arg(formatElement("all")) |
| .arg(formatData("0")) |
| .arg(formatData("1"))); |
| return modelGroup; |
| } |
| |
| validateIdAttribute("all"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::LocalAll, this, m_namePool); |
| |
| XsdParticle::List particles; |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| modelGroup->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalElement(particle, parent); |
| particle->setTerm(term); |
| |
| if (particle->maximumOccursUnbounded() || particle->maximumOccurs() > 1) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must have a value of %3 or %4.") |
| .arg(formatAttribute("maxOccurs")) |
| .arg(formatElement("all")) |
| .arg(formatData("0")) |
| .arg(formatData("1"))); |
| return modelGroup; |
| } |
| |
| particles.append(particle); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| modelGroup->setParticles(particles); |
| |
| tagValidator.finalize(); |
| |
| return modelGroup; |
| } |
| |
| XsdModelGroup::Ptr XsdSchemaParser::parseChoice(const NamedSchemaComponent::Ptr &parent) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Choice, this); |
| |
| validateElement(XsdTagScope::Choice); |
| |
| const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); |
| modelGroup->setCompositor(XsdModelGroup::ChoiceCompositor); |
| |
| validateIdAttribute("choice"); |
| |
| XsdParticle::List particles; |
| |
| TagValidationHandler tagValidator(XsdTagScope::Choice, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| modelGroup->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalElement(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseReferredGroup(particle); |
| m_schemaResolver->addAllGroupCheck(term); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalChoice(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalSequence(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseAny(particle); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| modelGroup->setParticles(particles); |
| |
| tagValidator.finalize(); |
| |
| return modelGroup; |
| } |
| |
| XsdModelGroup::Ptr XsdSchemaParser::parseLocalChoice(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Choice, this); |
| |
| validateElement(XsdTagScope::LocalChoice); |
| |
| const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); |
| modelGroup->setCompositor(XsdModelGroup::ChoiceCompositor); |
| |
| // parse attributes |
| if (!parseMinMaxConstraint(particle, "choice")) { |
| return modelGroup; |
| } |
| |
| validateIdAttribute("choice"); |
| |
| XsdParticle::List particles; |
| |
| TagValidationHandler tagValidator(XsdTagScope::LocalChoice, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| modelGroup->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalElement(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseReferredGroup(particle); |
| m_schemaResolver->addAllGroupCheck(term); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalChoice(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalSequence(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseAny(particle); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| modelGroup->setParticles(particles); |
| |
| tagValidator.finalize(); |
| |
| return modelGroup; |
| } |
| |
| XsdModelGroup::Ptr XsdSchemaParser::parseSequence(const NamedSchemaComponent::Ptr &parent) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Sequence, this); |
| |
| validateElement(XsdTagScope::Sequence); |
| |
| const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); |
| modelGroup->setCompositor(XsdModelGroup::SequenceCompositor); |
| |
| validateIdAttribute("sequence"); |
| |
| XsdParticle::List particles; |
| |
| TagValidationHandler tagValidator(XsdTagScope::Sequence, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| modelGroup->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalElement(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseReferredGroup(particle); |
| m_schemaResolver->addAllGroupCheck(term); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalChoice(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalSequence(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseAny(particle); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| modelGroup->setParticles(particles); |
| |
| tagValidator.finalize(); |
| |
| return modelGroup; |
| } |
| |
| XsdModelGroup::Ptr XsdSchemaParser::parseLocalSequence(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Sequence, this); |
| |
| validateElement(XsdTagScope::LocalSequence); |
| |
| const XsdModelGroup::Ptr modelGroup(new XsdModelGroup()); |
| modelGroup->setCompositor(XsdModelGroup::SequenceCompositor); |
| |
| // parse attributes |
| if (!parseMinMaxConstraint(particle, "sequence")) { |
| return modelGroup; |
| } |
| |
| validateIdAttribute("sequence"); |
| |
| XsdParticle::List particles; |
| |
| TagValidationHandler tagValidator(XsdTagScope::LocalSequence, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| modelGroup->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Element, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalElement(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Group, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseReferredGroup(particle); |
| m_schemaResolver->addAllGroupCheck(term); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Choice, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalChoice(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Sequence, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseLocalSequence(particle, parent); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else if (isSchemaTag(XsdSchemaToken::Any, token, namespaceToken)) { |
| const XsdParticle::Ptr particle(new XsdParticle()); |
| const XsdTerm::Ptr term = parseAny(particle); |
| particle->setTerm(term); |
| particles.append(particle); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| modelGroup->setParticles(particles); |
| |
| tagValidator.finalize(); |
| |
| return modelGroup; |
| } |
| |
| XsdAttribute::Ptr XsdSchemaParser::parseGlobalAttribute() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Attribute, this); |
| |
| validateElement(XsdTagScope::GlobalAttribute); |
| |
| const XsdAttribute::Ptr attribute(new XsdAttribute()); |
| attribute->setScope(XsdAttribute::Scope::Ptr(new XsdAttribute::Scope())); |
| attribute->scope()->setVariety(XsdAttribute::Scope::Global); |
| |
| if (hasAttribute(QString::fromLatin1("default")) && hasAttribute(QString::fromLatin1("fixed"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("attribute")) |
| .arg(formatAttribute("default")) |
| .arg(formatAttribute("fixed"))); |
| return attribute; |
| } |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("default"))) { |
| const QString value = readAttribute(QString::fromLatin1("default")); |
| attribute->setValueConstraint(XsdAttribute::ValueConstraint::Ptr(new XsdAttribute::ValueConstraint())); |
| attribute->valueConstraint()->setVariety(XsdAttribute::ValueConstraint::Default); |
| attribute->valueConstraint()->setValue(value); |
| } else if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| attribute->setValueConstraint(XsdAttribute::ValueConstraint::Ptr(new XsdAttribute::ValueConstraint())); |
| attribute->valueConstraint()->setVariety(XsdAttribute::ValueConstraint::Fixed); |
| attribute->valueConstraint()->setValue(value); |
| } |
| |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("attribute")); |
| if ((objectName.namespaceURI() == StandardNamespaces::xsi) && |
| (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("type")) && |
| (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("nil")) && |
| (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("schemaLocation")) && |
| (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("noNamespaceSchemaLocation"))) { |
| |
| error(QtXmlPatterns::tr("Content of %1 attribute of %2 element must not be from namespace %3.") |
| .arg(formatAttribute("name")) |
| .arg(formatElement("attribute")) |
| .arg(formatURI(CommonNamespaces::XSI))); |
| return attribute; |
| } |
| if (m_namePool->stringForLocalName(objectName.localName()) == QString::fromLatin1("xmlns")) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must not be %3.") |
| .arg(formatAttribute("name")) |
| .arg(formatElement("attribute")) |
| .arg(formatData("xmlns"))); |
| return attribute; |
| } |
| attribute->setName(objectName); |
| |
| bool hasTypeAttribute = false; |
| bool hasTypeSpecified = false; |
| |
| if (hasAttribute(QString::fromLatin1("type"))) { |
| hasTypeAttribute = true; |
| |
| const QString type = readQNameAttribute(QString::fromLatin1("type"), "attribute"); |
| QXmlName typeName; |
| convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addAttributeType(attribute, typeName, currentSourceLocation()); // add to resolver |
| hasTypeSpecified = true; |
| } |
| |
| validateIdAttribute("attribute"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::GlobalAttribute, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| attribute->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| if (hasTypeAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("attribute")) |
| .arg(formatElement("simpleType")) |
| .arg(formatAttribute("type"))); |
| break; |
| } |
| |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| type->setContext(attribute); |
| attribute->setType(type); |
| hasTypeSpecified = true; |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| if (!hasTypeSpecified) { |
| attribute->setType(BuiltinTypes::xsAnySimpleType); // default value |
| return attribute; |
| } |
| |
| tagValidator.finalize(); |
| |
| return attribute; |
| } |
| |
| XsdAttributeUse::Ptr XsdSchemaParser::parseLocalAttribute(const NamedSchemaComponent::Ptr &parent) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Attribute, this); |
| |
| validateElement(XsdTagScope::LocalAttribute); |
| |
| bool hasRefAttribute = false; |
| bool hasTypeAttribute = false; |
| bool hasTypeSpecified = false; |
| |
| XsdAttributeUse::Ptr attributeUse; |
| if (hasAttribute(QString::fromLatin1("ref"))) { |
| const XsdAttributeReference::Ptr reference = XsdAttributeReference::Ptr(new XsdAttributeReference()); |
| reference->setType(XsdAttributeReference::AttributeUse); |
| reference->setSourceLocation(currentSourceLocation()); |
| |
| attributeUse = reference; |
| hasRefAttribute = true; |
| } else { |
| attributeUse = XsdAttributeUse::Ptr(new XsdAttributeUse()); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("default")) && hasAttribute(QString::fromLatin1("fixed"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("attribute")) |
| .arg(formatAttribute("default")) |
| .arg(formatAttribute("fixed"))); |
| return attributeUse; |
| } |
| |
| if (hasRefAttribute) { |
| if (hasAttribute(QString::fromLatin1("form"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("attribute")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("form"))); |
| return attributeUse; |
| } |
| if (hasAttribute(QString::fromLatin1("name"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("attribute")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("name"))); |
| return attributeUse; |
| } |
| if (hasAttribute(QString::fromLatin1("type"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("attribute")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("type"))); |
| return attributeUse; |
| } |
| } |
| |
| // parse attributes |
| |
| // default, fixed and use are handled by both, attribute use and attribute reference |
| if (hasAttribute(QString::fromLatin1("default"))) { |
| const QString value = readAttribute(QString::fromLatin1("default")); |
| attributeUse->setValueConstraint(XsdAttributeUse::ValueConstraint::Ptr(new XsdAttributeUse::ValueConstraint())); |
| attributeUse->valueConstraint()->setVariety(XsdAttributeUse::ValueConstraint::Default); |
| attributeUse->valueConstraint()->setValue(value); |
| } else if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| attributeUse->setValueConstraint(XsdAttributeUse::ValueConstraint::Ptr(new XsdAttributeUse::ValueConstraint())); |
| attributeUse->valueConstraint()->setVariety(XsdAttributeUse::ValueConstraint::Fixed); |
| attributeUse->valueConstraint()->setValue(value); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("use"))) { |
| const QString value = readAttribute(QString::fromLatin1("use")); |
| if (value != QString::fromLatin1("optional") && |
| value != QString::fromLatin1("prohibited") && |
| value != QString::fromLatin1("required")) { |
| attributeContentError("use", "attribute", value); |
| return attributeUse; |
| } |
| |
| if (value == QString::fromLatin1("optional")) |
| attributeUse->setUseType(XsdAttributeUse::OptionalUse); |
| else if (value == QString::fromLatin1("prohibited")) |
| attributeUse->setUseType(XsdAttributeUse::ProhibitedUse); |
| else if (value == QString::fromLatin1("required")) |
| attributeUse->setUseType(XsdAttributeUse::RequiredUse); |
| |
| if (attributeUse->valueConstraint() && attributeUse->valueConstraint()->variety() == XsdAttributeUse::ValueConstraint::Default && value != QString::fromLatin1("optional")) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must have the value %3 because the %4 attribute is set.") |
| .arg(formatAttribute("use")) |
| .arg(formatElement("attribute")) |
| .arg(formatData("optional")) |
| .arg(formatElement("default"))); |
| return attributeUse; |
| } |
| } |
| |
| const XsdAttribute::Ptr attribute(new XsdAttribute()); |
| |
| attributeUse->setAttribute(attribute); |
| m_componentLocationHash.insert(attribute, currentSourceLocation()); |
| |
| attribute->setScope(XsdAttribute::Scope::Ptr(new XsdAttribute::Scope())); |
| attribute->scope()->setVariety(XsdAttribute::Scope::Local); |
| attribute->scope()->setParent(parent); |
| |
| // now make a difference between attribute reference and attribute use |
| if (hasRefAttribute) { |
| const QString reference = readQNameAttribute(QString::fromLatin1("ref"), "attribute"); |
| QXmlName referenceName; |
| convertName(reference, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName |
| |
| const XsdAttributeReference::Ptr attributeReference = attributeUse; |
| attributeReference->setReferenceName(referenceName); |
| } else { |
| if (hasAttribute(QString::fromLatin1("name"))) { |
| const QString attributeName = readNameAttribute("attribute"); |
| |
| QXmlName objectName; |
| if (hasAttribute(QString::fromLatin1("form"))) { |
| const QString value = readAttribute(QString::fromLatin1("form")); |
| if (value != QString::fromLatin1("qualified") && value != QString::fromLatin1("unqualified")) { |
| attributeContentError("form", "attribute", value); |
| return attributeUse; |
| } |
| |
| if (value == QString::fromLatin1("qualified")) { |
| objectName = m_namePool->allocateQName(m_targetNamespace, attributeName); |
| } else { |
| objectName = m_namePool->allocateQName(QString(), attributeName); |
| } |
| } else { |
| if (m_attributeFormDefault == QString::fromLatin1("qualified")) { |
| objectName = m_namePool->allocateQName(m_targetNamespace, attributeName); |
| } else { |
| objectName = m_namePool->allocateQName(QString(), attributeName); |
| } |
| } |
| |
| if ((objectName.namespaceURI() == StandardNamespaces::xsi) && |
| (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("type")) && |
| (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("nil")) && |
| (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("schemaLocation")) && |
| (m_namePool->stringForLocalName(objectName.localName()) != QString::fromLatin1("noNamespaceSchemaLocation"))) { |
| |
| error(QtXmlPatterns::tr("Content of %1 attribute of %2 element must not be from namespace %3.") |
| .arg(formatAttribute("name")) |
| .arg(formatElement("attribute")) |
| .arg(formatURI(CommonNamespaces::XSI))); |
| return attributeUse; |
| } |
| if (m_namePool->stringForLocalName(objectName.localName()) == QString::fromLatin1("xmlns")) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must not be %3.") |
| .arg(formatAttribute("name")) |
| .arg(formatElement("attribute")) |
| .arg(formatData("xmlns"))); |
| return attributeUse; |
| } |
| |
| attribute->setName(objectName); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("type"))) { |
| hasTypeAttribute = true; |
| |
| const QString type = readQNameAttribute(QString::fromLatin1("type"), "attribute"); |
| QXmlName typeName; |
| convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addAttributeType(attribute, typeName, currentSourceLocation()); // add to resolver |
| hasTypeSpecified = true; |
| } |
| |
| if (attributeUse->valueConstraint()) { |
| //TODO: check whether assigning the value constraint of the attribute use to the attribute is correct |
| if (!attribute->valueConstraint()) |
| attribute->setValueConstraint(XsdAttribute::ValueConstraint::Ptr(new XsdAttribute::ValueConstraint())); |
| |
| attribute->valueConstraint()->setVariety((XsdAttribute::ValueConstraint::Variety)attributeUse->valueConstraint()->variety()); |
| attribute->valueConstraint()->setValue(attributeUse->valueConstraint()->value()); |
| attribute->valueConstraint()->setLexicalForm(attributeUse->valueConstraint()->lexicalForm()); |
| } |
| } |
| |
| validateIdAttribute("attribute"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::LocalAttribute, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| attribute->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| if (hasTypeAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("attribute")) |
| .arg(formatElement("simpleType")) |
| .arg(formatAttribute("type"))); |
| break; |
| } |
| if (hasRefAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("attribute")) |
| .arg(formatElement("simpleType")) |
| .arg(formatAttribute("ref"))); |
| break; |
| } |
| |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| type->setContext(attribute); |
| attribute->setType(type); |
| hasTypeSpecified = true; |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| if (!hasTypeSpecified) { |
| attribute->setType(BuiltinTypes::xsAnySimpleType); // default value |
| } |
| |
| tagValidator.finalize(); |
| |
| return attributeUse; |
| } |
| |
| XsdAttributeGroup::Ptr XsdSchemaParser::parseNamedAttributeGroup() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::AttributeGroup, this); |
| |
| validateElement(XsdTagScope::NamedAttributeGroup); |
| |
| const XsdAttributeGroup::Ptr attributeGroup(new XsdAttributeGroup()); |
| |
| // parse attributes |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("attributeGroup")); |
| attributeGroup->setName(objectName); |
| |
| validateIdAttribute("attributeGroup"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::NamedAttributeGroup, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| attributeGroup->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Attribute, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseLocalAttribute(attributeGroup); |
| |
| if (attributeUse->useType() == XsdAttributeUse::ProhibitedUse) { |
| warning(QtXmlPatterns::tr("Specifying use='prohibited' inside an attribute group has no effect.")); |
| } else { |
| attributeGroup->addAttributeUse(attributeUse); |
| } |
| } else if (isSchemaTag(XsdSchemaToken::AttributeGroup, token, namespaceToken)) { |
| const XsdAttributeUse::Ptr attributeUse = parseReferredAttributeGroup(); |
| attributeGroup->addAttributeUse(attributeUse); |
| } else if (isSchemaTag(XsdSchemaToken::AnyAttribute, token, namespaceToken)) { |
| const XsdWildcard::Ptr wildcard = parseAnyAttribute(); |
| attributeGroup->setWildcard(wildcard); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return attributeGroup; |
| } |
| |
| XsdAttributeUse::Ptr XsdSchemaParser::parseReferredAttributeGroup() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::AttributeGroup, this); |
| |
| validateElement(XsdTagScope::ReferredAttributeGroup); |
| |
| const XsdAttributeReference::Ptr attributeReference(new XsdAttributeReference()); |
| attributeReference->setType(XsdAttributeReference::AttributeGroup); |
| attributeReference->setSourceLocation(currentSourceLocation()); |
| |
| // parse attributes |
| const QString reference = readQNameAttribute(QString::fromLatin1("ref"), "attributeGroup"); |
| QXmlName referenceName; |
| convertName(reference, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName |
| attributeReference->setReferenceName(referenceName); |
| |
| validateIdAttribute("attributeGroup"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::ReferredAttributeGroup, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| attributeReference->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return attributeReference; |
| } |
| |
| XsdElement::Ptr XsdSchemaParser::parseGlobalElement() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Element, this); |
| |
| validateElement(XsdTagScope::GlobalElement); |
| |
| const XsdElement::Ptr element(new XsdElement()); |
| element->setScope(XsdElement::Scope::Ptr(new XsdElement::Scope())); |
| element->scope()->setVariety(XsdElement::Scope::Global); |
| |
| bool hasTypeAttribute = false; |
| bool hasTypeSpecified = false; |
| bool hasSubstitutionGroup = false; |
| |
| // parse attributes |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("element")); |
| element->setName(objectName); |
| |
| if (hasAttribute(QString::fromLatin1("abstract"))) { |
| const QString abstract = readAttribute(QString::fromLatin1("abstract")); |
| |
| const Boolean::Ptr value = Boolean::fromLexical(abstract); |
| if (value->hasError()) { |
| attributeContentError("abstract", "element", abstract, BuiltinTypes::xsBoolean); |
| return element; |
| } |
| |
| element->setIsAbstract(value->as<Boolean>()->value()); |
| } else { |
| element->setIsAbstract(false); // the default value |
| } |
| |
| if (hasAttribute(QString::fromLatin1("default")) && hasAttribute(QString::fromLatin1("fixed"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("default")) |
| .arg(formatAttribute("fixed"))); |
| return element; |
| } |
| |
| if (hasAttribute(QString::fromLatin1("default"))) { |
| const QString value = readAttribute(QString::fromLatin1("default")); |
| element->setValueConstraint(XsdElement::ValueConstraint::Ptr(new XsdElement::ValueConstraint())); |
| element->valueConstraint()->setVariety(XsdElement::ValueConstraint::Default); |
| element->valueConstraint()->setValue(value); |
| } else if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| element->setValueConstraint(XsdElement::ValueConstraint::Ptr(new XsdElement::ValueConstraint())); |
| element->valueConstraint()->setVariety(XsdElement::ValueConstraint::Fixed); |
| element->valueConstraint()->setValue(value); |
| } |
| |
| element->setDisallowedSubstitutions(readBlockingConstraintAttribute(NamedSchemaComponent::ExtensionConstraint | NamedSchemaComponent::RestrictionConstraint | NamedSchemaComponent::SubstitutionConstraint, "element")); |
| element->setSubstitutionGroupExclusions(readDerivationConstraintAttribute(SchemaType::ExtensionConstraint | SchemaType::RestrictionConstraint, "element")); |
| |
| if (hasAttribute(QString::fromLatin1("nillable"))) { |
| const QString nillable = readAttribute(QString::fromLatin1("nillable")); |
| |
| const Boolean::Ptr value = Boolean::fromLexical(nillable); |
| if (value->hasError()) { |
| attributeContentError("nillable", "element", nillable, BuiltinTypes::xsBoolean); |
| return element; |
| } |
| |
| element->setIsNillable(value->as<Boolean>()->value()); |
| } else { |
| element->setIsNillable(false); // the default value |
| } |
| |
| if (hasAttribute(QString::fromLatin1("type"))) { |
| const QString type = readQNameAttribute(QString::fromLatin1("type"), "element"); |
| QXmlName typeName; |
| convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addElementType(element, typeName, currentSourceLocation()); // add to resolver |
| |
| hasTypeAttribute = true; |
| hasTypeSpecified = true; |
| } |
| |
| if (hasAttribute(QString::fromLatin1("substitutionGroup"))) { |
| QList<QXmlName> elementNames; |
| |
| const QString value = readAttribute(QString::fromLatin1("substitutionGroup")); |
| const QStringList substitutionGroups = value.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| if (substitutionGroups.isEmpty()) { |
| attributeContentError("substitutionGroup", "element", value, BuiltinTypes::xsQName); |
| return element; |
| } |
| |
| for (int i = 0; i < substitutionGroups.count(); ++i) { |
| const QString value = substitutionGroups.at(i).simplified(); |
| if (!XPathHelper::isQName(value)) { |
| attributeContentError("substitutionGroup", "element", value, BuiltinTypes::xsQName); |
| return element; |
| } |
| |
| QXmlName elementName; |
| convertName(value, NamespaceSupport::ElementName, elementName); // translate qualified name into QXmlName |
| elementNames.append(elementName); |
| } |
| |
| m_schemaResolver->addSubstitutionGroupAffiliation(element, elementNames, currentSourceLocation()); // add to resolver |
| |
| hasSubstitutionGroup = true; |
| } |
| |
| validateIdAttribute("element"); |
| |
| XsdAlternative::List alternatives; |
| |
| TagValidationHandler tagValidator(XsdTagScope::GlobalElement, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| element->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| if (hasTypeAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("simpleType")) |
| .arg(formatAttribute("type"))); |
| return element; |
| } |
| |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| type->setContext(element); |
| element->setType(type); |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| |
| hasTypeSpecified = true; |
| } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { |
| if (hasTypeAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("complexType")) |
| .arg(formatAttribute("type"))); |
| return element; |
| } |
| |
| const XsdComplexType::Ptr type = parseLocalComplexType(); |
| type->setContext(element); |
| element->setType(type); |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| |
| hasTypeSpecified = true; |
| } else if (isSchemaTag(XsdSchemaToken::Alternative, token, namespaceToken)) { |
| const XsdAlternative::Ptr alternative = parseAlternative(); |
| alternatives.append(alternative); |
| } else if (isSchemaTag(XsdSchemaToken::Unique, token, namespaceToken)) { |
| const XsdIdentityConstraint::Ptr constraint = parseUnique(); |
| element->addIdentityConstraint(constraint); |
| } else if (isSchemaTag(XsdSchemaToken::Key, token, namespaceToken)) { |
| const XsdIdentityConstraint::Ptr constraint = parseKey(); |
| element->addIdentityConstraint(constraint); |
| } else if (isSchemaTag(XsdSchemaToken::Keyref, token, namespaceToken)) { |
| const XsdIdentityConstraint::Ptr constraint = parseKeyRef(element); |
| element->addIdentityConstraint(constraint); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| if (!hasTypeSpecified) { |
| if (hasSubstitutionGroup) |
| m_schemaResolver->addSubstitutionGroupType(element); |
| else |
| element->setType(BuiltinTypes::xsAnyType); |
| } |
| |
| if (!alternatives.isEmpty()) { |
| element->setTypeTable(XsdElement::TypeTable::Ptr(new XsdElement::TypeTable())); |
| |
| for (int i = 0; i < alternatives.count(); ++i) { |
| if (alternatives.at(i)->test()) |
| element->typeTable()->addAlternative(alternatives.at(i)); |
| |
| if (i == (alternatives.count() - 1)) { // the final one |
| if (!alternatives.at(i)->test()) { |
| element->typeTable()->setDefaultTypeDefinition(alternatives.at(i)); |
| } else { |
| const XsdAlternative::Ptr alternative(new XsdAlternative()); |
| if (element->type()) |
| alternative->setType(element->type()); |
| else |
| m_schemaResolver->addAlternativeType(alternative, element); // add to resolver |
| |
| element->typeTable()->setDefaultTypeDefinition(alternative); |
| } |
| } |
| } |
| } |
| |
| return element; |
| } |
| |
| XsdTerm::Ptr XsdSchemaParser::parseLocalElement(const XsdParticle::Ptr &particle, const NamedSchemaComponent::Ptr &parent) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Element, this); |
| |
| validateElement(XsdTagScope::LocalElement); |
| |
| bool hasRefAttribute = false; |
| bool hasTypeAttribute = false; |
| bool hasTypeSpecified = false; |
| |
| XsdTerm::Ptr term; |
| XsdElement::Ptr element; |
| if (hasAttribute(QString::fromLatin1("ref"))) { |
| term = XsdReference::Ptr(new XsdReference()); |
| hasRefAttribute = true; |
| } else { |
| term = XsdElement::Ptr(new XsdElement()); |
| element = term; |
| } |
| |
| if (hasRefAttribute) { |
| if (hasAttribute(QString::fromLatin1("name"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("name"))); |
| return term; |
| } else if (hasAttribute(QString::fromLatin1("block"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("block"))); |
| return term; |
| } else if (hasAttribute(QString::fromLatin1("nillable"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("nillable"))); |
| return term; |
| } else if (hasAttribute(QString::fromLatin1("default"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("default"))); |
| return term; |
| } else if (hasAttribute(QString::fromLatin1("fixed"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("fixed"))); |
| return term; |
| } else if (hasAttribute(QString::fromLatin1("form"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("form"))); |
| return term; |
| } else if (hasAttribute(QString::fromLatin1("type"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("ref")) |
| .arg(formatAttribute("type"))); |
| return term; |
| } |
| } |
| |
| // parse attributes |
| if (!parseMinMaxConstraint(particle, "element")) { |
| return element; |
| } |
| |
| if (!hasAttribute(QString::fromLatin1("name")) && !hasAttribute(QString::fromLatin1("ref"))) { |
| error(QtXmlPatterns::tr("%1 element must have either %2 or %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("name")) |
| .arg(formatAttribute("ref"))); |
| return element; |
| } |
| |
| if (hasRefAttribute) { |
| const QString ref = readQNameAttribute(QString::fromLatin1("ref"), "element"); |
| QXmlName referenceName; |
| convertName(ref, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName |
| |
| const XsdReference::Ptr reference = term; |
| reference->setReferenceName(referenceName); |
| reference->setType(XsdReference::Element); |
| reference->setSourceLocation(currentSourceLocation()); |
| } else { |
| element->setScope(XsdElement::Scope::Ptr(new XsdElement::Scope())); |
| element->scope()->setVariety(XsdElement::Scope::Local); |
| element->scope()->setParent(parent.data()); |
| |
| if (hasAttribute(QString::fromLatin1("name"))) { |
| const QString elementName = readNameAttribute("element"); |
| |
| QXmlName objectName; |
| if (hasAttribute(QString::fromLatin1("form"))) { |
| const QString value = readAttribute(QString::fromLatin1("form")); |
| if (value != QString::fromLatin1("qualified") && value != QString::fromLatin1("unqualified")) { |
| attributeContentError("form", "element", value); |
| return element; |
| } |
| |
| if (value == QString::fromLatin1("qualified")) { |
| objectName = m_namePool->allocateQName(m_targetNamespace, elementName); |
| } else { |
| objectName = m_namePool->allocateQName(QString(), elementName); |
| } |
| } else { |
| if (m_elementFormDefault == QString::fromLatin1("qualified")) { |
| objectName = m_namePool->allocateQName(m_targetNamespace, elementName); |
| } else { |
| objectName = m_namePool->allocateQName(QString(), elementName); |
| } |
| } |
| |
| element->setName(objectName); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("nillable"))) { |
| const QString nillable = readAttribute(QString::fromLatin1("nillable")); |
| |
| const Boolean::Ptr value = Boolean::fromLexical(nillable); |
| if (value->hasError()) { |
| attributeContentError("nillable", "element", nillable, BuiltinTypes::xsBoolean); |
| return term; |
| } |
| |
| element->setIsNillable(value->as<Boolean>()->value()); |
| } else { |
| element->setIsNillable(false); // the default value |
| } |
| |
| if (hasAttribute(QString::fromLatin1("default")) && hasAttribute(QString::fromLatin1("fixed"))) { |
| error(QtXmlPatterns::tr("%1 element must not have %2 and %3 attribute together.") |
| .arg(formatElement("element")) |
| .arg(formatAttribute("default")) |
| .arg(formatAttribute("fixed"))); |
| return element; |
| } |
| |
| if (hasAttribute(QString::fromLatin1("default"))) { |
| const QString value = readAttribute(QString::fromLatin1("default")); |
| element->setValueConstraint(XsdElement::ValueConstraint::Ptr(new XsdElement::ValueConstraint())); |
| element->valueConstraint()->setVariety(XsdElement::ValueConstraint::Default); |
| element->valueConstraint()->setValue(value); |
| } else if (hasAttribute(QString::fromLatin1("fixed"))) { |
| const QString value = readAttribute(QString::fromLatin1("fixed")); |
| element->setValueConstraint(XsdElement::ValueConstraint::Ptr(new XsdElement::ValueConstraint())); |
| element->valueConstraint()->setVariety(XsdElement::ValueConstraint::Fixed); |
| element->valueConstraint()->setValue(value); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("type"))) { |
| const QString type = readQNameAttribute(QString::fromLatin1("type"), "element"); |
| QXmlName typeName; |
| convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addElementType(element, typeName, currentSourceLocation()); // add to resolver |
| |
| hasTypeAttribute = true; |
| hasTypeSpecified = true; |
| } |
| |
| element->setDisallowedSubstitutions(readBlockingConstraintAttribute(NamedSchemaComponent::ExtensionConstraint | NamedSchemaComponent::RestrictionConstraint | NamedSchemaComponent::SubstitutionConstraint, "element")); |
| } |
| |
| validateIdAttribute("element"); |
| |
| XsdAlternative::List alternatives; |
| |
| TagValidationHandler tagValidator(XsdTagScope::LocalElement, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| term->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| if (hasRefAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("simpleType")) |
| .arg(formatAttribute("ref"))); |
| return term; |
| } else if (hasTypeAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("simpleType")) |
| .arg(formatAttribute("type"))); |
| return term; |
| } |
| |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| type->setContext(element); |
| element->setType(type); |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| |
| hasTypeSpecified = true; |
| } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { |
| if (hasRefAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("complexType")) |
| .arg(formatAttribute("ref"))); |
| return term; |
| } else if (hasTypeAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("complexType")) |
| .arg(formatAttribute("type"))); |
| return term; |
| } |
| |
| const XsdComplexType::Ptr type = parseLocalComplexType(); |
| type->setContext(element); |
| element->setType(type); |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| |
| hasTypeSpecified = true; |
| } else if (isSchemaTag(XsdSchemaToken::Alternative, token, namespaceToken)) { |
| if (hasRefAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("alternative")) |
| .arg(formatAttribute("ref"))); |
| return term; |
| } |
| |
| const XsdAlternative::Ptr alternative = parseAlternative(); |
| alternatives.append(alternative); |
| } else if (isSchemaTag(XsdSchemaToken::Unique, token, namespaceToken)) { |
| if (hasRefAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("unique")) |
| .arg(formatAttribute("ref"))); |
| return term; |
| } |
| |
| const XsdIdentityConstraint::Ptr constraint = parseUnique(); |
| element->addIdentityConstraint(constraint); |
| } else if (isSchemaTag(XsdSchemaToken::Key, token, namespaceToken)) { |
| if (hasRefAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("key")) |
| .arg(formatAttribute("ref"))); |
| return term; |
| } |
| |
| const XsdIdentityConstraint::Ptr constraint = parseKey(); |
| element->addIdentityConstraint(constraint); |
| } else if (isSchemaTag(XsdSchemaToken::Keyref, token, namespaceToken)) { |
| if (hasRefAttribute) { |
| error(QtXmlPatterns::tr("%1 element with %2 child element must not have a %3 attribute.") |
| .arg(formatElement("element")) |
| .arg(formatElement("keyref")) |
| .arg(formatAttribute("ref"))); |
| return term; |
| } |
| |
| const XsdIdentityConstraint::Ptr constraint = parseKeyRef(element); |
| element->addIdentityConstraint(constraint); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| if (!hasTypeSpecified && !hasRefAttribute) |
| element->setType(BuiltinTypes::xsAnyType); |
| |
| if (!hasRefAttribute && !alternatives.isEmpty()) { |
| element->setTypeTable(XsdElement::TypeTable::Ptr(new XsdElement::TypeTable())); |
| |
| for (int i = 0; i < alternatives.count(); ++i) { |
| if (alternatives.at(i)->test()) |
| element->typeTable()->addAlternative(alternatives.at(i)); |
| |
| if (i == (alternatives.count() - 1)) { // the final one |
| if (!alternatives.at(i)->test()) { |
| element->typeTable()->setDefaultTypeDefinition(alternatives.at(i)); |
| } else { |
| const XsdAlternative::Ptr alternative(new XsdAlternative()); |
| if (element->type()) |
| alternative->setType(element->type()); |
| else |
| m_schemaResolver->addAlternativeType(alternative, element); // add to resolver |
| |
| element->typeTable()->setDefaultTypeDefinition(alternative); |
| } |
| } |
| } |
| } |
| |
| return term; |
| } |
| |
| XsdIdentityConstraint::Ptr XsdSchemaParser::parseUnique() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Unique, this); |
| |
| validateElement(XsdTagScope::Unique); |
| |
| const XsdIdentityConstraint::Ptr constraint(new XsdIdentityConstraint()); |
| constraint->setCategory(XsdIdentityConstraint::Unique); |
| |
| // parse attributes |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("unique")); |
| constraint->setName(objectName); |
| |
| validateIdAttribute("unique"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Unique, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| constraint->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Selector, token, namespaceToken)) { |
| parseSelector(constraint); |
| } else if (isSchemaTag(XsdSchemaToken::Field, token, namespaceToken)) { |
| parseField(constraint); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| // add constraint to schema for further checking |
| addIdentityConstraint(constraint); |
| |
| tagValidator.finalize(); |
| |
| return constraint; |
| } |
| |
| XsdIdentityConstraint::Ptr XsdSchemaParser::parseKey() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Key, this); |
| |
| validateElement(XsdTagScope::Key); |
| |
| const XsdIdentityConstraint::Ptr constraint(new XsdIdentityConstraint()); |
| constraint->setCategory(XsdIdentityConstraint::Key); |
| |
| // parse attributes |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("key")); |
| constraint->setName(objectName); |
| |
| validateIdAttribute("key"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Key, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| constraint->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Selector, token, namespaceToken)) { |
| parseSelector(constraint); |
| } else if (isSchemaTag(XsdSchemaToken::Field, token, namespaceToken)) { |
| parseField(constraint); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| // add constraint to schema for further checking |
| addIdentityConstraint(constraint); |
| |
| tagValidator.finalize(); |
| |
| return constraint; |
| } |
| |
| XsdIdentityConstraint::Ptr XsdSchemaParser::parseKeyRef(const XsdElement::Ptr &element) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Keyref, this); |
| |
| validateElement(XsdTagScope::KeyRef); |
| |
| const XsdIdentityConstraint::Ptr constraint(new XsdIdentityConstraint()); |
| constraint->setCategory(XsdIdentityConstraint::KeyReference); |
| |
| // parse attributes |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("keyref")); |
| constraint->setName(objectName); |
| |
| const QString refer = readQNameAttribute(QString::fromLatin1("refer"), "keyref"); |
| QXmlName referenceName; |
| convertName(refer, NamespaceSupport::ElementName, referenceName); // translate qualified name into QXmlName |
| m_schemaResolver->addKeyReference(element, constraint, referenceName, currentSourceLocation()); // add to resolver |
| |
| validateIdAttribute("keyref"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::KeyRef, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| constraint->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::Selector, token, namespaceToken)) { |
| parseSelector(constraint); |
| } else if (isSchemaTag(XsdSchemaToken::Field, token, namespaceToken)) { |
| parseField(constraint); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| // add constraint to schema for further checking |
| addIdentityConstraint(constraint); |
| |
| tagValidator.finalize(); |
| |
| return constraint; |
| } |
| |
| void XsdSchemaParser::parseSelector(const XsdIdentityConstraint::Ptr &ptr) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Selector, this); |
| |
| validateElement(XsdTagScope::Selector); |
| |
| // parse attributes |
| const XsdXPathExpression::Ptr expression = readXPathExpression("selector"); |
| |
| const QString xpath = readXPathAttribute(QString::fromLatin1("xpath"), XPathSelector, "selector"); |
| expression->setExpression(xpath); |
| |
| ptr->setSelector(expression); |
| |
| validateIdAttribute("selector"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Selector, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| expression->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| void XsdSchemaParser::parseField(const XsdIdentityConstraint::Ptr &ptr) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Field, this); |
| |
| validateElement(XsdTagScope::Field); |
| |
| // parse attributes |
| const XsdXPathExpression::Ptr expression = readXPathExpression("field"); |
| |
| const QString xpath = readXPathAttribute(QString::fromLatin1("xpath"), XPathField, "field"); |
| expression->setExpression(xpath); |
| |
| ptr->addField(expression); |
| |
| validateIdAttribute("field"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Field, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| expression->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| } |
| |
| XsdAlternative::Ptr XsdSchemaParser::parseAlternative() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Alternative, this); |
| |
| validateElement(XsdTagScope::Alternative); |
| |
| const XsdAlternative::Ptr alternative(new XsdAlternative()); |
| |
| bool hasTypeSpecified = false; |
| |
| if (hasAttribute(QString::fromLatin1("test"))) { |
| const XsdXPathExpression::Ptr expression = readXPathExpression("alternative"); |
| |
| const QString test = readXPathAttribute(QString::fromLatin1("test"), XPath20, "alternative"); |
| expression->setExpression(test); |
| |
| alternative->setTest(expression); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("type"))) { |
| const QString type = readQNameAttribute(QString::fromLatin1("type"), "alternative"); |
| QXmlName typeName; |
| convertName(type, NamespaceSupport::ElementName, typeName); // translate qualified name into QXmlName |
| m_schemaResolver->addAlternativeType(alternative, typeName, currentSourceLocation()); // add to resolver |
| |
| hasTypeSpecified = true; |
| } |
| |
| validateIdAttribute("alternative"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Alternative, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| alternative->addAnnotation(annotation); |
| } else if (isSchemaTag(XsdSchemaToken::SimpleType, token, namespaceToken)) { |
| const XsdSimpleType::Ptr type = parseLocalSimpleType(); |
| alternative->setType(type); |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| |
| hasTypeSpecified = true; |
| } else if (isSchemaTag(XsdSchemaToken::ComplexType, token, namespaceToken)) { |
| const XsdComplexType::Ptr type = parseLocalComplexType(); |
| alternative->setType(type); |
| |
| // add it to list of anonymous types as well |
| addAnonymousType(type); |
| |
| hasTypeSpecified = true; |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| if (!hasTypeSpecified) { |
| error(QtXmlPatterns::tr("%1 element must have either %2 attribute or %3 or %4 as child element.") |
| .arg(formatElement("alternative")) |
| .arg(formatAttribute("type")) |
| .arg(formatElement("simpleType")) |
| .arg(formatElement("complexType"))); |
| return alternative; |
| } |
| |
| return alternative; |
| } |
| |
| XsdNotation::Ptr XsdSchemaParser::parseNotation() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Notation, this); |
| |
| validateElement(XsdTagScope::Notation); |
| |
| const XsdNotation::Ptr notation(new XsdNotation()); |
| |
| // parse attributes |
| const QXmlName objectName = m_namePool->allocateQName(m_targetNamespace, readNameAttribute("notation")); |
| notation->setName(objectName); |
| |
| bool hasOptionalAttribute = false; |
| |
| if (hasAttribute(QString::fromLatin1("public"))) { |
| const QString value = readAttribute(QString::fromLatin1("public")); |
| if (!value.isEmpty()) { |
| const DerivedString<TypeToken>::Ptr publicId = DerivedString<TypeToken>::fromLexical(m_namePool, value); |
| if (publicId->hasError()) { |
| attributeContentError("public", "notation", value, BuiltinTypes::xsToken); |
| return notation; |
| } |
| notation->setPublicId(publicId); |
| } |
| |
| hasOptionalAttribute = true; |
| } |
| |
| if (hasAttribute(QString::fromLatin1("system"))) { |
| const QString value = readAttribute(QString::fromLatin1("system")); |
| if (!isValidUri(value)) { |
| attributeContentError("system", "notation", value, BuiltinTypes::xsAnyURI); |
| return notation; |
| } |
| |
| if (!value.isEmpty()) { |
| const AnyURI::Ptr systemId = AnyURI::fromLexical(value); |
| notation->setSystemId(systemId); |
| } |
| |
| hasOptionalAttribute = true; |
| } |
| |
| if (!hasOptionalAttribute) { |
| error(QtXmlPatterns::tr("%1 element requires either %2 or %3 attribute.") |
| .arg(formatElement("notation")) |
| .arg(formatAttribute("public")) |
| .arg(formatAttribute("system"))); |
| return notation; |
| } |
| |
| validateIdAttribute("notation"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Notation, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isCharacters() || isEntityReference()) { |
| if (!text().toString().trimmed().isEmpty()) { |
| error(QtXmlPatterns::tr("Text or entity references not allowed inside %1 element").arg(formatElement("notation."))); |
| return notation; |
| } |
| } |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| notation->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return notation; |
| } |
| |
| XsdWildcard::Ptr XsdSchemaParser::parseAny(const XsdParticle::Ptr &particle) |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::Any, this); |
| |
| validateElement(XsdTagScope::Any); |
| |
| const XsdWildcard::Ptr wildcard(new XsdWildcard()); |
| |
| // parse attributes |
| if (!parseMinMaxConstraint(particle, "any")) { |
| return wildcard; |
| } |
| |
| if (hasAttribute(QString::fromLatin1("namespace"))) { |
| const auto valueList = readAttribute(QString::fromLatin1("namespace")).split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| const QSet<QString> values(valueList.cbegin(), valueList.cend()); |
| if ((values.contains(QString::fromLatin1("##any")) || values.contains(QString::fromLatin1("##other"))) && values.count() != 1) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must contain %3, %4 or a list of URIs.") |
| .arg(formatAttribute("namespace")) |
| .arg(formatElement("any")) |
| .arg(formatData("##any")) |
| .arg(formatData("##other"))); |
| return wildcard; |
| } |
| |
| if (values.contains(QString::fromLatin1("##any"))) { |
| wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); |
| } else if (values.contains(QString::fromLatin1("##other"))) { |
| wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not); |
| if (!m_targetNamespace.isEmpty()) |
| wildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << m_targetNamespace); |
| else |
| wildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace()); |
| } else { |
| wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration); |
| QStringList newValues = values.values(); |
| |
| // replace the ##targetNamespace entry |
| for (int i = 0; i < newValues.count(); ++i) { |
| if (newValues.at(i) == QString::fromLatin1("##targetNamespace")) { |
| if (!m_targetNamespace.isEmpty()) |
| newValues[i] = m_targetNamespace; |
| else |
| newValues[i] = XsdWildcard::absentNamespace(); |
| } else if (newValues.at(i) == QString::fromLatin1("##local")) { |
| newValues[i] = XsdWildcard::absentNamespace(); |
| } |
| } |
| |
| // check for invalid URIs |
| for (int i = 0; i < newValues.count(); ++i) { |
| const QString stringValue = newValues.at(i); |
| if (stringValue == XsdWildcard::absentNamespace()) |
| continue; |
| |
| if (!isValidUri(stringValue)) { |
| attributeContentError("namespace", "any", stringValue, BuiltinTypes::xsAnyURI); |
| return wildcard; |
| } |
| } |
| |
| wildcard->namespaceConstraint()->setNamespaces(QSet<QString>(newValues.cbegin(), newValues.cend())); |
| } |
| } else { |
| wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("processContents"))) { |
| const QString value = readAttribute(QString::fromLatin1("processContents")); |
| if (value != QString::fromLatin1("lax") && |
| value != QString::fromLatin1("skip") && |
| value != QString::fromLatin1("strict")) { |
| attributeContentError("processContents", "any", value); |
| return wildcard; |
| } |
| |
| if (value == QString::fromLatin1("lax")) { |
| wildcard->setProcessContents(XsdWildcard::Lax); |
| } else if (value == QString::fromLatin1("skip")) { |
| wildcard->setProcessContents(XsdWildcard::Skip); |
| } else if (value == QString::fromLatin1("strict")) { |
| wildcard->setProcessContents(XsdWildcard::Strict); |
| } |
| } else { |
| wildcard->setProcessContents(XsdWildcard::Strict); |
| } |
| |
| validateIdAttribute("any"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::Any, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| wildcard->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return wildcard; |
| } |
| |
| XsdWildcard::Ptr XsdSchemaParser::parseAnyAttribute() |
| { |
| const ElementNamespaceHandler namespaceHandler(XsdSchemaToken::AnyAttribute, this); |
| |
| validateElement(XsdTagScope::AnyAttribute); |
| |
| const XsdWildcard::Ptr wildcard(new XsdWildcard()); |
| |
| // parse attributes |
| if (hasAttribute(QString::fromLatin1("namespace"))) { |
| const auto valueList = readAttribute(QString::fromLatin1("namespace")).split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| const QSet<QString> values(valueList.cbegin(), valueList.cend()); |
| if ((values.contains(QString::fromLatin1("##any")) || values.contains(QString::fromLatin1("##other"))) && values.count() != 1) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must contain %3, %4 or a list of URIs.") |
| .arg(formatAttribute("namespace")) |
| .arg(formatElement("anyAttribute")) |
| .arg(formatData("##any")) |
| .arg(formatData("##other"))); |
| return wildcard; |
| } |
| |
| if (values.contains(QString::fromLatin1("##any"))) { |
| wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); |
| } else if (values.contains(QString::fromLatin1("##other"))) { |
| wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Not); |
| if (!m_targetNamespace.isEmpty()) |
| wildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << m_targetNamespace); |
| else |
| wildcard->namespaceConstraint()->setNamespaces(QSet<QString>() << XsdWildcard::absentNamespace()); |
| } else { |
| wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Enumeration); |
| QStringList newValues = values.values(); |
| |
| // replace the ##targetNamespace entry |
| for (int i = 0; i < newValues.count(); ++i) { |
| if (newValues.at(i) == QString::fromLatin1("##targetNamespace")) { |
| if (!m_targetNamespace.isEmpty()) |
| newValues[i] = m_targetNamespace; |
| else |
| newValues[i] = XsdWildcard::absentNamespace(); |
| } else if (newValues.at(i) == QString::fromLatin1("##local")) { |
| newValues[i] = XsdWildcard::absentNamespace(); |
| } |
| } |
| |
| // check for invalid URIs |
| for (int i = 0; i < newValues.count(); ++i) { |
| const QString stringValue = newValues.at(i); |
| if (stringValue == XsdWildcard::absentNamespace()) |
| continue; |
| |
| if (!isValidUri(stringValue)) { |
| attributeContentError("namespace", "anyAttribute", stringValue, BuiltinTypes::xsAnyURI); |
| return wildcard; |
| } |
| } |
| |
| wildcard->namespaceConstraint()->setNamespaces(QSet<QString>(newValues.cbegin(), newValues.cend())); |
| } |
| } else { |
| wildcard->namespaceConstraint()->setVariety(XsdWildcard::NamespaceConstraint::Any); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("processContents"))) { |
| const QString value = readAttribute(QString::fromLatin1("processContents")); |
| if (value != QString::fromLatin1("lax") && |
| value != QString::fromLatin1("skip") && |
| value != QString::fromLatin1("strict")) { |
| attributeContentError("processContents", "anyAttribute", value); |
| return wildcard; |
| } |
| |
| if (value == QString::fromLatin1("lax")) { |
| wildcard->setProcessContents(XsdWildcard::Lax); |
| } else if (value == QString::fromLatin1("skip")) { |
| wildcard->setProcessContents(XsdWildcard::Skip); |
| } else if (value == QString::fromLatin1("strict")) { |
| wildcard->setProcessContents(XsdWildcard::Strict); |
| } |
| } else { |
| wildcard->setProcessContents(XsdWildcard::Strict); |
| } |
| |
| validateIdAttribute("anyAttribute"); |
| |
| TagValidationHandler tagValidator(XsdTagScope::AnyAttribute, this, m_namePool); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) { |
| const XsdSchemaToken::NodeName token = XsdSchemaToken::toToken(name()); |
| const XsdSchemaToken::NodeName namespaceToken = XsdSchemaToken::toToken(namespaceUri()); |
| |
| tagValidator.validate(token); |
| |
| if (isSchemaTag(XsdSchemaToken::Annotation, token, namespaceToken)) { |
| const XsdAnnotation::Ptr annotation = parseAnnotation(); |
| wildcard->addAnnotation(annotation); |
| } else { |
| parseUnknown(); |
| } |
| } |
| } |
| |
| tagValidator.finalize(); |
| |
| return wildcard; |
| } |
| |
| |
| void XsdSchemaParser::parseUnknownDocumentation() |
| { |
| Q_ASSERT(isStartElement()); |
| m_namespaceSupport.pushContext(); |
| m_namespaceSupport.setPrefixes(namespaceDeclarations()); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) |
| parseUnknownDocumentation(); |
| } |
| |
| m_namespaceSupport.popContext(); |
| } |
| |
| void XsdSchemaParser::parseUnknown() |
| { |
| Q_ASSERT(isStartElement()); |
| m_namespaceSupport.pushContext(); |
| m_namespaceSupport.setPrefixes(namespaceDeclarations()); |
| |
| error(QtXmlPatterns::tr("%1 element is not allowed in this context.").arg(formatElement(name().toString()))); |
| |
| while (!atEnd()) { |
| readNext(); |
| |
| if (isEndElement()) |
| break; |
| |
| if (isStartElement()) |
| parseUnknown(); |
| } |
| |
| m_namespaceSupport.popContext(); |
| } |
| |
| bool XsdSchemaParser::parseMinMaxConstraint(const XsdParticle::Ptr &particle, const char *elementName) |
| { |
| if (hasAttribute(QString::fromLatin1("minOccurs"))) { |
| const QString value = readAttribute(QString::fromLatin1("minOccurs")); |
| |
| DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); |
| if (integer->hasError()) { |
| attributeContentError("minOccurs", elementName, value, BuiltinTypes::xsNonNegativeInteger); |
| return false; |
| } else { |
| particle->setMinimumOccurs(integer->as< DerivedInteger<TypeNonNegativeInteger> >()->storedValue()); |
| } |
| } else { |
| particle->setMinimumOccurs(1); |
| } |
| |
| if (hasAttribute(QString::fromLatin1("maxOccurs"))) { |
| const QString value = readAttribute(QString::fromLatin1("maxOccurs")); |
| |
| if (value == QString::fromLatin1("unbounded")) { |
| particle->setMaximumOccursUnbounded(true); |
| } else { |
| particle->setMaximumOccursUnbounded(false); |
| DerivedInteger<TypeNonNegativeInteger>::Ptr integer = DerivedInteger<TypeNonNegativeInteger>::fromLexical(m_namePool, value); |
| if (integer->hasError()) { |
| attributeContentError("maxOccurs", elementName, value, BuiltinTypes::xsNonNegativeInteger); |
| return false; |
| } else { |
| particle->setMaximumOccurs(integer->as< DerivedInteger<TypeNonNegativeInteger> >()->storedValue()); |
| } |
| } |
| } else { |
| particle->setMaximumOccursUnbounded(false); |
| particle->setMaximumOccurs(1); |
| } |
| |
| if (!particle->maximumOccursUnbounded()) { |
| if (particle->maximumOccurs() < particle->minimumOccurs()) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element has larger value than %3 attribute.") |
| .arg(formatAttribute("minOccurs")) |
| .arg(formatElement(elementName)) |
| .arg(formatAttribute("maxOccurs"))); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| QSourceLocation XsdSchemaParser::currentSourceLocation() const |
| { |
| QSourceLocation location; |
| location.setLine(lineNumber()); |
| location.setColumn(columnNumber()); |
| location.setUri(m_documentURI); |
| |
| return location; |
| } |
| |
| void XsdSchemaParser::convertName(const QString &qualifiedName, NamespaceSupport::NameType type, QXmlName &name) |
| { |
| bool result = m_namespaceSupport.processName(qualifiedName, type, name); |
| if (!result) { |
| error(QtXmlPatterns::tr("Prefix of qualified name %1 is not defined.").arg(formatKeyword(qualifiedName))); |
| } |
| } |
| |
| QString XsdSchemaParser::readNameAttribute(const char *elementName) |
| { |
| const QString value = readAttribute(QString::fromLatin1("name")).simplified(); |
| if (!QXmlUtils::isNCName(value)) { |
| attributeContentError("name", elementName, value, BuiltinTypes::xsNCName); |
| return QString(); |
| } else { |
| return value; |
| } |
| } |
| |
| QString XsdSchemaParser::readQNameAttribute(const QString &typeAttribute, const char *elementName) |
| { |
| const QString value = readAttribute(typeAttribute).simplified(); |
| if (!XPathHelper::isQName(value)) { |
| attributeContentError(typeAttribute.toLatin1(), elementName, value, BuiltinTypes::xsQName); |
| return QString(); |
| } else { |
| return value; |
| } |
| } |
| |
| QString XsdSchemaParser::readNamespaceAttribute(const QString &attributeName, const char *elementName) |
| { |
| const QString value = readAttribute(attributeName); |
| if (value.isEmpty()) { |
| attributeContentError(attributeName.toLatin1(), elementName, value, BuiltinTypes::xsAnyURI); |
| return QString(); |
| } |
| |
| return value; |
| } |
| |
| SchemaType::DerivationConstraints XsdSchemaParser::readDerivationConstraintAttribute(const SchemaType::DerivationConstraints &allowedConstraints, const char *elementName) |
| { |
| // first convert the flags into strings for easier comparison |
| QSet<QString> allowedContent; |
| if (allowedConstraints & SchemaType::RestrictionConstraint) |
| allowedContent.insert(QString::fromLatin1("restriction")); |
| if (allowedConstraints & SchemaType::ExtensionConstraint) |
| allowedContent.insert(QString::fromLatin1("extension")); |
| if (allowedConstraints & SchemaType::ListConstraint) |
| allowedContent.insert(QString::fromLatin1("list")); |
| if (allowedConstraints & SchemaType::UnionConstraint) |
| allowedContent.insert(QString::fromLatin1("union")); |
| |
| // read content from the attribute if available, otherwise use the default definitions from the schema tag |
| QString content; |
| if (hasAttribute(QString::fromLatin1("final"))) { |
| content = readAttribute(QString::fromLatin1("final")); |
| |
| // split string into list to validate the content of the attribute |
| const QStringList values = content.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| for (int i = 0; i < values.count(); i++) { |
| const QString value = values.at(i); |
| if (!allowedContent.contains(value) && (value != QString::fromLatin1("#all"))) { |
| attributeContentError("final", elementName, value); |
| return SchemaType::DerivationConstraints(); |
| } |
| |
| if ((value == QString::fromLatin1("#all")) && values.count() != 1) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must either contain %3 or the other values.") |
| .arg(formatAttribute("final")) |
| .arg(formatElement(elementName)) |
| .arg(formatData("#all"))); |
| return SchemaType::DerivationConstraints(); |
| } |
| } |
| } else { |
| // content of the default value has been validated in parseSchema already |
| content = m_finalDefault; |
| } |
| |
| const auto &contentList = content.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| QSet<QString> contentSet(contentList.cbegin(), contentList.cend()); |
| |
| // if the '#all' tag is defined, we return all allowed values |
| if (contentSet.contains(QString::fromLatin1("#all"))) { |
| return allowedConstraints; |
| } else { // return the values from content set that intersects with the allowed values |
| contentSet.intersect(allowedContent); |
| |
| SchemaType::DerivationConstraints constraints; |
| |
| if (contentSet.contains(QString::fromLatin1("restriction"))) |
| constraints |= SchemaType::RestrictionConstraint; |
| if (contentSet.contains(QString::fromLatin1("extension"))) |
| constraints |= SchemaType::ExtensionConstraint; |
| if (contentSet.contains(QString::fromLatin1("list"))) |
| constraints |= SchemaType::ListConstraint; |
| if (contentSet.contains(QString::fromLatin1("union"))) |
| constraints |= SchemaType::UnionConstraint; |
| |
| return constraints; |
| } |
| } |
| |
| NamedSchemaComponent::BlockingConstraints XsdSchemaParser::readBlockingConstraintAttribute(const NamedSchemaComponent::BlockingConstraints &allowedConstraints, const char *elementName) |
| { |
| // first convert the flags into strings for easier comparison |
| QSet<QString> allowedContent; |
| if (allowedConstraints & NamedSchemaComponent::RestrictionConstraint) |
| allowedContent.insert(QString::fromLatin1("restriction")); |
| if (allowedConstraints & NamedSchemaComponent::ExtensionConstraint) |
| allowedContent.insert(QString::fromLatin1("extension")); |
| if (allowedConstraints & NamedSchemaComponent::SubstitutionConstraint) |
| allowedContent.insert(QString::fromLatin1("substitution")); |
| |
| // read content from the attribute if available, otherwise use the default definitions from the schema tag |
| QString content; |
| if (hasAttribute(QString::fromLatin1("block"))) { |
| content = readAttribute(QString::fromLatin1("block")); |
| |
| // split string into list to validate the content of the attribute |
| const QStringList values = content.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| for (int i = 0; i < values.count(); i++) { |
| const QString value = values.at(i); |
| if (!allowedContent.contains(value) && (value != QString::fromLatin1("#all"))) { |
| attributeContentError("block", elementName, value); |
| return NamedSchemaComponent::BlockingConstraints(); |
| } |
| |
| if ((value == QString::fromLatin1("#all")) && values.count() != 1) { |
| error(QtXmlPatterns::tr("%1 attribute of %2 element must either contain %3 or the other values.") |
| .arg(formatAttribute("block")) |
| .arg(formatElement(elementName)) |
| .arg(formatData("#all"))); |
| return NamedSchemaComponent::BlockingConstraints(); |
| } |
| } |
| } else { |
| // content of the default value has been validated in parseSchema already |
| content = m_blockDefault; |
| } |
| |
| const auto &contentList = content.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| QSet<QString> contentSet(contentList.cbegin(), contentList.cend()); |
| |
| // if the '#all' tag is defined, we return all allowed values |
| if (contentSet.contains(QString::fromLatin1("#all"))) { |
| return allowedConstraints; |
| } else { // return the values from content set that intersects with the allowed values |
| contentSet.intersect(allowedContent); |
| |
| NamedSchemaComponent::BlockingConstraints constraints; |
| |
| if (contentSet.contains(QString::fromLatin1("restriction"))) |
| constraints |= NamedSchemaComponent::RestrictionConstraint; |
| if (contentSet.contains(QString::fromLatin1("extension"))) |
| constraints |= NamedSchemaComponent::ExtensionConstraint; |
| if (contentSet.contains(QString::fromLatin1("substitution"))) |
| constraints |= NamedSchemaComponent::SubstitutionConstraint; |
| |
| return constraints; |
| } |
| } |
| |
| XsdXPathExpression::Ptr XsdSchemaParser::readXPathExpression(const char *elementName) |
| { |
| const XsdXPathExpression::Ptr expression(new XsdXPathExpression()); |
| |
| const QList<QXmlName> namespaceBindings = m_namespaceSupport.namespaceBindings(); |
| QXmlName emptyName; |
| for (int i = 0; i < namespaceBindings.count(); ++i) { |
| if (namespaceBindings.at(i).prefix() == StandardPrefixes::empty) |
| emptyName = namespaceBindings.at(i); |
| } |
| |
| expression->setNamespaceBindings(namespaceBindings); |
| |
| QString xpathDefaultNamespace; |
| if (hasAttribute(QString::fromLatin1("xpathDefaultNamespace"))) { |
| xpathDefaultNamespace = readAttribute(QString::fromLatin1("xpathDefaultNamespace")); |
| if (xpathDefaultNamespace != QString::fromLatin1("##defaultNamespace") && |
| xpathDefaultNamespace != QString::fromLatin1("##targetNamespace") && |
| xpathDefaultNamespace != QString::fromLatin1("##local")) { |
| if (!isValidUri(xpathDefaultNamespace)) { |
| attributeContentError("xpathDefaultNamespace", elementName, xpathDefaultNamespace, BuiltinTypes::xsAnyURI); |
| return expression; |
| } |
| } |
| } else { |
| xpathDefaultNamespace = m_xpathDefaultNamespace; |
| } |
| |
| AnyURI::Ptr namespaceURI; |
| if (xpathDefaultNamespace == QString::fromLatin1("##defaultNamespace")) { |
| if (!emptyName.isNull()) |
| namespaceURI = AnyURI::fromLexical(m_namePool->stringForNamespace(emptyName.namespaceURI())); |
| } else if (xpathDefaultNamespace == QString::fromLatin1("##targetNamespace")) { |
| if (!m_targetNamespace.isEmpty()) |
| namespaceURI = AnyURI::fromLexical(m_targetNamespace); |
| } else if (xpathDefaultNamespace == QString::fromLatin1("##local")) { |
| // it is absent |
| } else { |
| namespaceURI = AnyURI::fromLexical(xpathDefaultNamespace); |
| } |
| if (namespaceURI) { |
| if (namespaceURI->hasError()) { |
| attributeContentError("xpathDefaultNamespace", elementName, xpathDefaultNamespace, BuiltinTypes::xsAnyURI); |
| return expression; |
| } |
| |
| expression->setDefaultNamespace(namespaceURI); |
| } |
| |
| //TODO: read the base uri if qmaintaining reader support it |
| |
| return expression; |
| } |
| |
| QString XsdSchemaParser::readXPathAttribute(const QString &attributeName, XPathType type, const char *elementName) |
| { |
| const QString value = readAttribute(attributeName); |
| if (value.isEmpty() || value.startsWith(QLatin1Char('/'))) { |
| attributeContentError(attributeName.toLatin1(), elementName, value); |
| return QString(); |
| } |
| |
| QXmlNamePool namePool(m_namePool.data()); |
| |
| QXmlQuery::QueryLanguage language = QXmlQuery::XPath20; |
| switch (type) { |
| case XPath20: language = QXmlQuery::XPath20; break; |
| case XPathSelector: language = QXmlQuery::XmlSchema11IdentityConstraintSelector; break; |
| case XPathField: language = QXmlQuery::XmlSchema11IdentityConstraintField; break; |
| }; |
| |
| QXmlQuery query(language, namePool); |
| QXmlQueryPrivate *queryPrivate = query.d; |
| |
| const QList<QXmlName> namespaceBindings = m_namespaceSupport.namespaceBindings(); |
| for (int i = 0; i < namespaceBindings.count(); ++i) { |
| if (namespaceBindings.at(i).prefix() != StandardPrefixes::empty) |
| queryPrivate->addAdditionalNamespaceBinding(namespaceBindings.at(i)); |
| } |
| |
| query.setQuery(value, m_documentURI); |
| if (!query.isValid()) { |
| attributeContentError(attributeName.toLatin1(), elementName, value); |
| return QString(); |
| } |
| |
| return value; |
| } |
| |
| void XsdSchemaParser::validateIdAttribute(const char *elementName) |
| { |
| if (hasAttribute(QString::fromLatin1("id"))) { |
| const QString value = readAttribute(QString::fromLatin1("id")); |
| DerivedString<TypeID>::Ptr id = DerivedString<TypeID>::fromLexical(m_namePool, value); |
| if (id->hasError()) { |
| attributeContentError("id", elementName, value, BuiltinTypes::xsID); |
| } else { |
| if (m_idCache->hasId(value)) { |
| error(QtXmlPatterns::tr("Component with ID %1 has been defined previously.").arg(formatData(value))); |
| } else { |
| m_idCache->addId(value); |
| } |
| } |
| } |
| } |
| |
| bool XsdSchemaParser::isSchemaTag(XsdSchemaToken::NodeName tag, XsdSchemaToken::NodeName token, XsdSchemaToken::NodeName namespaceToken) const |
| { |
| return ((tag == token) && (namespaceToken == XsdSchemaToken::XML_NS_SCHEMA_URI)); |
| } |
| |
| void XsdSchemaParser::addElement(const XsdElement::Ptr &element) |
| { |
| const QXmlName objectName = element->name(m_namePool); |
| if (m_schema->element(objectName)) { |
| error(QtXmlPatterns::tr("Element %1 already defined.").arg(formatElement(m_namePool->displayName(objectName)))); |
| } else { |
| m_schema->addElement(element); |
| m_componentLocationHash.insert(element, currentSourceLocation()); |
| } |
| } |
| |
| void XsdSchemaParser::addAttribute(const XsdAttribute::Ptr &attribute) |
| { |
| const QXmlName objectName = attribute->name(m_namePool); |
| if (m_schema->attribute(objectName)) { |
| error(QtXmlPatterns::tr("Attribute %1 already defined.").arg(formatAttribute(m_namePool->displayName(objectName)))); |
| } else { |
| m_schema->addAttribute(attribute); |
| m_componentLocationHash.insert(attribute, currentSourceLocation()); |
| } |
| } |
| |
| void XsdSchemaParser::addType(const SchemaType::Ptr &type) |
| { |
| // we don't import redefinitions of builtin types, that just causes problems |
| if (m_builtinTypeNames.contains(type->name(m_namePool))) |
| return; |
| |
| const QXmlName objectName = type->name(m_namePool); |
| if (m_schema->type(objectName)) { |
| error(QtXmlPatterns::tr("Type %1 already defined.").arg(formatType(m_namePool, objectName))); |
| } else { |
| m_schema->addType(type); |
| if (type->isSimpleType()) |
| m_componentLocationHash.insert(XsdSimpleType::Ptr(type), currentSourceLocation()); |
| else |
| m_componentLocationHash.insert(XsdComplexType::Ptr(type), currentSourceLocation()); |
| } |
| } |
| |
| void XsdSchemaParser::addAnonymousType(const SchemaType::Ptr &type) |
| { |
| m_schema->addAnonymousType(type); |
| if (type->isSimpleType()) |
| m_componentLocationHash.insert(XsdSimpleType::Ptr(type), currentSourceLocation()); |
| else |
| m_componentLocationHash.insert(XsdComplexType::Ptr(type), currentSourceLocation()); |
| } |
| |
| void XsdSchemaParser::addAttributeGroup(const XsdAttributeGroup::Ptr &group) |
| { |
| const QXmlName objectName = group->name(m_namePool); |
| if (m_schema->attributeGroup(objectName)) { |
| error(QtXmlPatterns::tr("Attribute group %1 already defined.").arg(formatKeyword(m_namePool, objectName))); |
| } else { |
| m_schema->addAttributeGroup(group); |
| m_componentLocationHash.insert(group, currentSourceLocation()); |
| } |
| } |
| |
| void XsdSchemaParser::addElementGroup(const XsdModelGroup::Ptr &group) |
| { |
| const QXmlName objectName = group->name(m_namePool); |
| if (m_schema->elementGroup(objectName)) { |
| error(QtXmlPatterns::tr("Element group %1 already defined.").arg(formatKeyword(m_namePool, objectName))); |
| } else { |
| m_schema->addElementGroup(group); |
| m_componentLocationHash.insert(group, currentSourceLocation()); |
| } |
| } |
| |
| void XsdSchemaParser::addNotation(const XsdNotation::Ptr ¬ation) |
| { |
| const QXmlName objectName = notation->name(m_namePool); |
| if (m_schema->notation(objectName)) { |
| error(QtXmlPatterns::tr("Notation %1 already defined.").arg(formatKeyword(m_namePool, objectName))); |
| } else { |
| m_schema->addNotation(notation); |
| m_componentLocationHash.insert(notation, currentSourceLocation()); |
| } |
| } |
| |
| void XsdSchemaParser::addIdentityConstraint(const XsdIdentityConstraint::Ptr &constraint) |
| { |
| const QXmlName objectName = constraint->name(m_namePool); |
| if (m_schema->identityConstraint(objectName)) { |
| error(QtXmlPatterns::tr("Identity constraint %1 already defined.").arg(formatKeyword(m_namePool, objectName))); |
| } else { |
| m_schema->addIdentityConstraint(constraint); |
| m_componentLocationHash.insert(constraint, currentSourceLocation()); |
| } |
| } |
| |
| void XsdSchemaParser::addFacet(const XsdFacet::Ptr &facet, XsdFacet::Hash &facets, const SchemaType::Ptr &type) |
| { |
| // @see http://www.w3.org/TR/xmlschema-2/#src-single-facet-value |
| if (facets.contains(facet->type())) { |
| error(QtXmlPatterns::tr("Duplicated facets in simple type %1.").arg(formatType(m_namePool, type))); |
| return; |
| } |
| |
| facets.insert(facet->type(), facet); |
| } |
| |
| QT_END_NAMESPACE |