| /**************************************************************************** |
| ** |
| ** 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 <QtMath> |
| |
| #include "qxsdtypechecker_p.h" |
| |
| #include "qabstractdatetime_p.h" |
| #include "qbase64binary_p.h" |
| #include "qboolean_p.h" |
| #include "qdecimal_p.h" |
| #include "qderivedinteger_p.h" |
| #include "qduration_p.h" |
| #include "qgenericstaticcontext_p.h" |
| #include "qhexbinary_p.h" |
| #include "qnamespaceresolver_p.h" |
| #include "qpatternplatform_p.h" |
| #include "qqnamevalue_p.h" |
| #include "qvaluefactory_p.h" |
| #include "qxmlnamepool.h" |
| #include "qxsdschemahelper_p.h" |
| #include "qxsdschemamerger_p.h" |
| #include "qxsdstatemachine_p.h" |
| |
| #include "qxsdschemadebugger_p.h" |
| |
| QT_BEGIN_NAMESPACE |
| |
| using namespace QPatternist; |
| |
| XsdSchemaSourceLocationReflection::XsdSchemaSourceLocationReflection(const QSourceLocation &location) |
| : m_sourceLocation(location) |
| { |
| } |
| |
| const SourceLocationReflection* XsdSchemaSourceLocationReflection::actualReflection() const |
| { |
| return this; |
| } |
| |
| QSourceLocation XsdSchemaSourceLocationReflection::sourceLocation() const |
| { |
| return m_sourceLocation; |
| } |
| |
| |
| static AnySimpleType::Ptr comparableType(const AnySimpleType::Ptr &type) |
| { |
| if (!type->isDefinedBySchema()) { |
| return type; |
| } else { |
| const XsdSimpleType::Ptr simpleType(type); |
| if (type->category() == SchemaType::SimpleTypeAtomic) { |
| return simpleType->primitiveType(); |
| } else if (type->category() == SchemaType::SimpleTypeList) { |
| return simpleType->itemType(); |
| } else if (type->category() == SchemaType::SimpleTypeUnion) { |
| return simpleType->memberTypes().first(); |
| } |
| } |
| |
| Q_ASSERT(false); |
| return AnySimpleType::Ptr(); |
| } |
| |
| static int totalDigitsForSignedLongLong(long long value) |
| { |
| QString number = QString::number(value); |
| if (number.startsWith(QLatin1Char('-'))) |
| number = number.mid(1); |
| |
| return number.length(); |
| } |
| |
| static int totalDigitsForUnsignedLongLong(unsigned long long value) |
| { |
| const QString number = QString::number(value); |
| return number.length(); |
| } |
| |
| static int totalDigitsForDecimal(const QString &lexicalValue) |
| { |
| const QLatin1Char zeroChar('0'); |
| const int length = lexicalValue.length() - 1; |
| |
| // strip leading zeros |
| int pos = 0; |
| while (lexicalValue.at(pos) == zeroChar && (pos != length)) |
| pos++; |
| |
| QString value = lexicalValue.mid(pos); |
| |
| // if contains '.' strip trailing zeros |
| if (value.contains(QLatin1Char('.'))) { |
| pos = value.length() - 1; |
| while (value.at(pos) == zeroChar) { |
| pos--; |
| } |
| |
| value = value.left(pos + 1); |
| } |
| |
| // check number of digits of remaining string |
| int totalDigits = 0; |
| for (int i = 0; i < value.count(); ++i) |
| if (value.at(i).isDigit()) |
| ++totalDigits; |
| |
| if (totalDigits == 0) |
| totalDigits = 1; |
| |
| return totalDigits; |
| } |
| |
| static int fractionDigitsForDecimal(const QString &lexicalValue) |
| { |
| const int pos = lexicalValue.indexOf(QLatin1Char('.')); |
| if (pos == -1) |
| return 0; |
| const QStringRef fraction = QStringRef(&lexicalValue).mid(pos).trimmed(); |
| int i = fraction.length() - 1; // fraction[0] is '.' so fraction is not empty |
| while (fraction.at(i) == QLatin1Char('0')) |
| --i; |
| return i; // The significant fraction-digits are fraction[1 through i]. |
| } |
| |
| XsdTypeChecker::XsdTypeChecker(const XsdSchemaContext::Ptr &context, const QVector<QXmlName> &namespaceBindings, const QSourceLocation &location) |
| : m_context(context) |
| , m_namePool(m_context->namePool()) |
| , m_namespaceBindings(namespaceBindings) |
| , m_reflection(new XsdSchemaSourceLocationReflection(location)) |
| { |
| } |
| |
| XsdTypeChecker::~XsdTypeChecker() |
| { |
| delete m_reflection; |
| } |
| |
| QString XsdTypeChecker::normalizedValue(const QString &value, const XsdFacet::Hash &facets) |
| { |
| if (!facets.contains(XsdFacet::WhiteSpace)) |
| return value; |
| |
| const XsdFacet::Ptr whiteSpaceFacet = facets.value(XsdFacet::WhiteSpace); |
| |
| const DerivedString<TypeString>::Ptr facetValue = whiteSpaceFacet->value(); |
| const QString stringValue = facetValue->stringValue(); |
| if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Preserve)) |
| return value; |
| else if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Replace)) { |
| QString newValue(value); |
| newValue.replace(QLatin1Char('\t'), QLatin1Char(' ')); |
| newValue.replace(QLatin1Char('\n'), QLatin1Char(' ')); |
| newValue.replace(QLatin1Char('\r'), QLatin1Char(' ')); |
| |
| return newValue; |
| } else if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Collapse)) { |
| return value.simplified(); |
| } |
| |
| return value; |
| } |
| |
| XsdFacet::Hash XsdTypeChecker::mergedFacetsForType(const SchemaType::Ptr &type, const XsdSchemaContext::Ptr &context) |
| { |
| if (!type) |
| return XsdFacet::Hash(); |
| |
| const XsdFacet::Hash baseFacets = mergedFacetsForType(type->wxsSuperType(), context); |
| const XsdFacet::Hash facets = context->facetsForType(type); |
| |
| XsdFacet::Hash result = baseFacets; |
| for (auto it = facets.cbegin(), end = facets.cend(); it != end; ++it) |
| result.insert(it.key(), it.value()); |
| |
| return result; |
| } |
| |
| bool XsdTypeChecker::isValidString(const QString &normalizedString, const AnySimpleType::Ptr &type, QString &errorMsg, AnySimpleType::Ptr *boundType) const |
| { |
| if (type->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) { |
| if (boundType) |
| *boundType = type; |
| |
| return true; |
| } |
| |
| if (!type->isDefinedBySchema()) { |
| // special QName check |
| if (BuiltinTypes::xsQName->wxsTypeMatches(type)) { |
| if (!XPathHelper::isQName(normalizedString)) { |
| errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2.").arg(formatData(normalizedString)).arg(formatType(m_namePool, type)); |
| return false; |
| } |
| } |
| |
| const AtomicValue::Ptr value = fromLexical(normalizedString, type, m_context, m_reflection); |
| if (value->hasError()) { |
| errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2.").arg(formatData(normalizedString)).arg(formatType(m_namePool, type)); |
| return false; |
| } |
| |
| if (!checkConstrainingFacets(value, normalizedString, type, errorMsg)) { |
| return false; |
| } |
| |
| if (boundType) |
| *boundType = type; |
| |
| } else { |
| const XsdSimpleType::Ptr simpleType(type); |
| |
| if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) { |
| AnySimpleType::Ptr targetType = simpleType->primitiveType(); |
| if (!simpleType->wxsSuperType()->isDefinedBySchema()) |
| targetType = simpleType->wxsSuperType(); |
| |
| const AtomicValue::Ptr value = fromLexical(normalizedString, targetType, m_context, m_reflection); |
| if (value->hasError()) { |
| errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2.").arg(formatData(normalizedString)).arg(formatType(m_namePool, targetType)); |
| return false; |
| } |
| |
| if (!checkConstrainingFacets(value, normalizedString, type, errorMsg)) { |
| return false; |
| } |
| |
| if (boundType) |
| *boundType = type; |
| |
| } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) { |
| QStringList entries = normalizedString.split(QLatin1Char(' '), QString::SkipEmptyParts); |
| for (int i = 0; i < entries.count(); ++i) { |
| entries[i] = normalizedValue(entries.at(i), mergedFacetsForType(simpleType->itemType(), m_context)); |
| } |
| |
| if (!checkConstrainingFacetsList(entries, normalizedString, simpleType->itemType(), mergedFacetsForType(simpleType, m_context), errorMsg)) { |
| return false; |
| } |
| |
| for (int i = 0; i < entries.count(); ++i) { |
| if (!isValidString(entries.at(i), simpleType->itemType(), errorMsg)) { |
| return false; |
| } |
| } |
| |
| if (boundType) |
| *boundType = simpleType->itemType(); |
| |
| } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) { |
| if (!checkConstrainingFacetsUnion(normalizedString, normalizedString, simpleType, mergedFacetsForType(simpleType, m_context), errorMsg)) { |
| return false; |
| } |
| |
| const AnySimpleType::List memberTypes = simpleType->memberTypes(); |
| |
| bool foundValidType = false; |
| for (int i = 0; i < memberTypes.count(); ++i) { |
| const XsdFacet::Hash mergedFacets = mergedFacetsForType(memberTypes.at(i), m_context); |
| if (isValidString(normalizedValue(normalizedString, mergedFacets), memberTypes.at(i), errorMsg)) { |
| foundValidType = true; |
| |
| if (boundType) |
| *boundType = memberTypes.at(i); |
| |
| break; |
| } |
| } |
| |
| if (!foundValidType) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::valuesAreEqual(const QString &value, const QString &otherValue, const AnySimpleType::Ptr &type) const |
| { |
| const AnySimpleType::Ptr targetType = comparableType(type); |
| |
| // if the type is xs:anySimpleType we just do string comparison... |
| if (targetType->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) |
| return (value == otherValue); |
| |
| if (BuiltinTypes::xsQName->wxsTypeMatches(type)) { |
| const QXmlName valueName = convertToQName(value); |
| const QXmlName otherValueName = convertToQName(otherValue); |
| |
| if (valueName == otherValueName) |
| return true; |
| } |
| |
| if (type->category() == SchemaType::SimpleTypeAtomic) { |
| // ... otherwise we use the casting platform for value comparison |
| const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| const DerivedString<TypeString>::Ptr otherValueStr = DerivedString<TypeString>::fromLexical(m_namePool, otherValue); |
| |
| return XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, otherValueStr, targetType, m_context, m_reflection); |
| } else if (type->category() == SchemaType::SimpleTypeList) { |
| const QStringList values = value.split(QLatin1Char(' '), QString::SkipEmptyParts); |
| const QStringList otherValues = otherValue.split(QLatin1Char(' '), QString::SkipEmptyParts); |
| if (values.count() != otherValues.count()) |
| return false; |
| |
| for (int i = 0; i < values.count(); ++i) { |
| if (!valuesAreEqual(values.at(i), otherValues.at(i), XsdSimpleType::Ptr(type)->itemType())) |
| return false; |
| } |
| |
| return true; |
| } else if (type->category() == SchemaType::SimpleTypeUnion) { |
| const AnySimpleType::List memberTypes = XsdSimpleType::Ptr(type)->memberTypes(); |
| for (int i = 0; i < memberTypes.count(); ++i) { |
| if (valuesAreEqual(value, otherValue, memberTypes.at(i))) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| return false; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacets(const AtomicValue::Ptr &value, const QString &lexicalValue, const AnySimpleType::Ptr &type, QString &errorMsg) const |
| { |
| const XsdFacet::Hash facets = mergedFacetsForType(type, m_context); |
| |
| if (BuiltinTypes::xsString->wxsTypeMatches(type) || |
| BuiltinTypes::xsUntypedAtomic->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsString(value->stringValue(), facets, BuiltinTypes::xsString, errorMsg); |
| } else if (BuiltinTypes::xsAnyURI->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsString(value->stringValue(), facets, BuiltinTypes::xsAnyURI, errorMsg); |
| } else if (BuiltinTypes::xsNOTATION->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsNotation(value->as<QNameValue>()->qName(), facets, errorMsg); |
| } else if (BuiltinTypes::xsUnsignedByte->wxsTypeMatches(type) || |
| BuiltinTypes::xsUnsignedInt->wxsTypeMatches(type) || |
| BuiltinTypes::xsUnsignedLong->wxsTypeMatches(type) || |
| BuiltinTypes::xsUnsignedShort->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsUnsignedInteger(value->as<Numeric>()->toUnsignedInteger(), lexicalValue, facets, errorMsg); |
| } else if (BuiltinTypes::xsInteger->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsSignedInteger(value->as<Numeric>()->toInteger(), lexicalValue, facets, errorMsg); |
| } else if (BuiltinTypes::xsFloat->wxsTypeMatches(type) || |
| BuiltinTypes::xsDouble->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDouble(value->as<Numeric>()->toDouble(), lexicalValue, facets, errorMsg); |
| } else if (BuiltinTypes::xsDecimal->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDecimal(value, lexicalValue, facets, errorMsg); |
| } else if (BuiltinTypes::xsDateTime->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsDateTime, errorMsg); |
| } else if (BuiltinTypes::xsDate->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsDate, errorMsg); |
| } else if (BuiltinTypes::xsGYear->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGYear, errorMsg); |
| } else if (BuiltinTypes::xsGYearMonth->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGYearMonth, errorMsg); |
| } else if (BuiltinTypes::xsGMonth->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGMonth, errorMsg); |
| } else if (BuiltinTypes::xsGMonthDay->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGMonthDay, errorMsg); |
| } else if (BuiltinTypes::xsGDay->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGDay, errorMsg); |
| } else if (BuiltinTypes::xsTime->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsTime, errorMsg); |
| } else if (BuiltinTypes::xsDuration->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsDuration(value, lexicalValue, facets, errorMsg); |
| } else if (BuiltinTypes::xsBoolean->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsBoolean(value->as<Boolean>()->value(), lexicalValue, facets, errorMsg); |
| } else if (BuiltinTypes::xsHexBinary->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsBinary(value->as<Base64Binary>()->asByteArray(), facets, BuiltinTypes::xsHexBinary, errorMsg); |
| } else if (BuiltinTypes::xsBase64Binary->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsBinary(value->as<Base64Binary>()->asByteArray(), facets, BuiltinTypes::xsBase64Binary, errorMsg); |
| } else if (BuiltinTypes::xsQName->wxsTypeMatches(type)) { |
| return checkConstrainingFacetsQName(value->as<QNameValue>()->qName(), lexicalValue, facets, errorMsg); |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsString(const QString &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::Length)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Length); |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); |
| if (length->toInteger() != value.length()) { |
| errorMsg = QtXmlPatterns::tr("String content does not match the length facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumLength)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumLength); |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); |
| if (length->toInteger() > value.length()) { |
| errorMsg = QtXmlPatterns::tr("String content does not match the minLength facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MaximumLength)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumLength); |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); |
| if (length->toInteger() < value.length()) { |
| errorMsg = QtXmlPatterns::tr("String content does not match the maxLength facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(value)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("String content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| if (XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), type, m_context, m_reflection)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("String content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsSignedInteger(long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::MaximumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection); |
| if (facetValue->toInteger() < value) { |
| errorMsg = QtXmlPatterns::tr("Signed integer content does not match the maxInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MaximumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection); |
| if (facetValue->toInteger() <= value) { |
| errorMsg = QtXmlPatterns::tr("Signed integer content does not match the maxExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection); |
| if (facetValue->toInteger() > value) { |
| errorMsg = QtXmlPatterns::tr("Signed integer content does not match the minInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection); |
| if (facetValue->toInteger() >= value) { |
| errorMsg = QtXmlPatterns::tr("Signed integer content does not match the minExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, QString::number(value)); |
| |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| if (XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsLong, m_context, m_reflection)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Signed integer content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Signed integer content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::TotalDigits)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits); |
| const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value(); |
| |
| if (totalDigitsForSignedLongLong(value) > facetValue->toInteger()) { |
| errorMsg = QtXmlPatterns::tr("Signed integer content does not match in the totalDigits facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsUnsignedInteger(unsigned long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::MaximumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection); |
| if (facetValue->toUnsignedInteger() < value) { |
| errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match the maxInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MaximumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection); |
| if (facetValue->toUnsignedInteger() <= value) { |
| errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match the maxExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection); |
| if (facetValue->toUnsignedInteger() > value) { |
| errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match the minInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection); |
| if (facetValue->toUnsignedInteger() >= value) { |
| errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match the minExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, QString::number(value)); |
| |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| if (XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsUnsignedLong, m_context, m_reflection)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Unsigned integer content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::TotalDigits)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits); |
| const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value(); |
| |
| if (totalDigitsForUnsignedLongLong(value) > facetValue->toInteger()) { |
| errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match in the totalDigits facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsDouble(double value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::MaximumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection); |
| if (facetValue->toDouble() < value) { |
| errorMsg = QtXmlPatterns::tr("Double content does not match the maxInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MaximumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection); |
| if (facetValue->toDouble() <= value) { |
| errorMsg = QtXmlPatterns::tr("Double content does not match the maxExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection); |
| if (facetValue->toDouble() > value) { |
| errorMsg = QtXmlPatterns::tr("Double content does not match the minInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); |
| const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection); |
| if (facetValue->toDouble() >= value) { |
| errorMsg = QtXmlPatterns::tr("Double content does not match the minExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, QString::number(value)); |
| |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| if (XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsDouble, m_context, m_reflection)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Double content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Double content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsDecimal(const AtomicValue::Ptr &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::FractionDigits)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::FractionDigits); |
| const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value(); |
| |
| if (fractionDigitsForDecimal(lexicalValue) > facetValue->toInteger()) { |
| errorMsg = QtXmlPatterns::tr("Decimal content does not match in the fractionDigits facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::TotalDigits)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits); |
| const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value(); |
| |
| if (totalDigitsForDecimal(lexicalValue) > facetValue->toInteger()) { |
| errorMsg = QtXmlPatterns::tr("Decimal content does not match in the totalDigits facet."); |
| return false; |
| } |
| } |
| |
| return checkConstrainingFacetsDouble(value->as<Decimal>()->toDouble(), lexicalValue, facets, errorMsg); |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsDateTime(const QDateTime &value, const QString &lexicalValue, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::MaximumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); |
| const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); |
| if (facetValue->toDateTime() < value) { |
| errorMsg = QtXmlPatterns::tr("Date time content does not match the maxInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MaximumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); |
| const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); |
| if (facetValue->toDateTime() <= value) { |
| errorMsg = QtXmlPatterns::tr("Date time content does not match the maxExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); |
| const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); |
| if (facetValue->toDateTime() > value) { |
| errorMsg = QtXmlPatterns::tr("Date time content does not match the minInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); |
| const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); |
| if (facetValue->toDateTime() >= value) { |
| errorMsg = QtXmlPatterns::tr("Date time content does not match the minExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); |
| if (facetValue->toDateTime() == value) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Date time content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Date time content does not match pattern facet."); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsDuration(const AtomicValue::Ptr&, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::MaximumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive); |
| const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); |
| |
| if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MaximumInclusive)->value(), AtomicComparator::OperatorLessThan, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { |
| errorMsg = QtXmlPatterns::tr("Duration content does not match the maxInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MaximumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive); |
| const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); |
| |
| if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MaximumExclusive)->value(), AtomicComparator::OperatorLessOrEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { |
| errorMsg = QtXmlPatterns::tr("Duration content does not match the maxExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumInclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive); |
| const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); |
| |
| if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MinimumInclusive)->value(), AtomicComparator::OperatorGreaterThan, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { |
| errorMsg = QtXmlPatterns::tr("Duration content does not match the minInclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumExclusive)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive); |
| const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); |
| |
| if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MinimumExclusive)->value(), AtomicComparator::OperatorGreaterOrEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { |
| errorMsg = QtXmlPatterns::tr("Duration content does not match the minExclusive facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue); |
| |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| if (XsdSchemaHelper::constructAndCompare(multiValue.at(j), AtomicComparator::OperatorEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Duration content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Duration content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsBoolean(bool, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Boolean content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsBinary(const QByteArray &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::Length)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Length); |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); |
| if (length->toInteger() != value.length()) { |
| errorMsg = QtXmlPatterns::tr("Binary content does not match the length facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumLength)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumLength); |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); |
| if (length->toInteger() > value.length()) { |
| errorMsg = QtXmlPatterns::tr("Binary content does not match the minLength facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MaximumLength)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumLength); |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value(); |
| if (length->toInteger() < value.length()) { |
| errorMsg = QtXmlPatterns::tr("Binary content does not match the maxLength facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const Base64Binary::Ptr binary = ValueFactory::fromLexical(multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection); |
| const QByteArray facetValue = binary->as<Base64Binary>()->asByteArray(); |
| if (value == facetValue) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Binary content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| //TODO: implement |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsQName(const QXmlName &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::Length)) { |
| // always true |
| } |
| if (facets.contains(XsdFacet::MinimumLength)) { |
| // always true |
| } |
| if (facets.contains(XsdFacet::MaximumLength)) { |
| // always true |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| if (!XPathHelper::isQName(lexicalValue)) { |
| errorMsg = QtXmlPatterns::tr("Invalid QName content: %1.").arg(formatData(lexicalValue)); |
| return false; |
| } |
| |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QXmlName facetValue = multiValue.at(j)->as<QNameValue>()->qName(); |
| |
| if (value == facetValue) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("QName content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("QName content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsNotation(const QXmlName &value, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::Length)) { |
| // deprecated by spec |
| } |
| if (facets.contains(XsdFacet::MinimumLength)) { |
| // deprecated by spec |
| } |
| if (facets.contains(XsdFacet::MaximumLength)) { |
| // deprecated by spec |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QXmlName facetValue = multiValue.at(j)->as<QNameValue>()->qName(); |
| |
| if (value == facetValue) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Notation content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| //TODO: implement |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsList(const QStringList &values, const QString &lexicalValue, const AnySimpleType::Ptr &itemType, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::Length)) { |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::Length)->value(); |
| if (value->toInteger() != values.count()) { |
| errorMsg = QtXmlPatterns::tr("List content does not match length facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MinimumLength)) { |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::MinimumLength)->value(); |
| if (value->toInteger() > values.count()) { |
| errorMsg = QtXmlPatterns::tr("List content does not match minLength facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::MaximumLength)) { |
| const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::MaximumLength)->value(); |
| if (value->toInteger() < values.count()) { |
| errorMsg = QtXmlPatterns::tr("List content does not match maxLength facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Enumeration)) { |
| |
| bool found = false; |
| |
| // we have to handle lists with QName derived items differently |
| if (BuiltinTypes::xsQName->wxsTypeMatches(itemType) || BuiltinTypes::xsNOTATION->wxsTypeMatches(itemType)) { |
| // first convert the string values from the instance document to a list of QXmlName |
| QList<QXmlName> instanceValues; |
| for (int i = 0; i < values.count(); ++i) { |
| instanceValues.append(convertToQName(values.at(i))); |
| } |
| |
| // fetch the values from the facet and create a list of QXmlNames for each of them |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| |
| const AtomicValue::List multiValue = facet->multiValue(); |
| for (int i = 0; i < multiValue.count(); ++i) { |
| const QStringList facetValueList = multiValue.at(i)->as<DerivedString<TypeString> >()->stringValue().split(QLatin1Char(' '), QString::SkipEmptyParts); |
| |
| // create the list of atomic string values |
| QList<QXmlName> facetValues; |
| for (int j = 0; j < facetValueList.count(); ++j) { |
| facetValues.append(convertToQName(facetValueList.at(j))); |
| } |
| |
| // check if both lists have the same length |
| if (instanceValues.count() != facetValues.count()) |
| continue; |
| |
| // check if both lists are equal, that means the contain equal items in the same order |
| bool matchesAll = true; |
| for (int j = 0; j < instanceValues.count(); ++j) { |
| if (instanceValues.at(j) != facetValues.at(j)) { |
| matchesAll = false; |
| break; |
| } |
| } |
| |
| if (matchesAll) { |
| found = true; |
| break; |
| } |
| } |
| } else { |
| // first convert the string values from the instance document to atomic values of type string |
| AtomicValue::List instanceValues; |
| for (int i = 0; i < values.count(); ++i) { |
| instanceValues.append(DerivedString<TypeString>::fromLexical(m_namePool, values.at(i))); |
| } |
| |
| // fetch the values from the facet and create a list of atomic string values for each of them |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| |
| const AnySimpleType::Ptr targetType = comparableType(itemType); |
| |
| const AtomicValue::List multiValue = facet->multiValue(); |
| for (int i = 0; i < multiValue.count(); ++i) { |
| const QStringList facetValueList = multiValue.at(i)->as<DerivedString<TypeString> >()->stringValue().split(QLatin1Char(' '), QString::SkipEmptyParts); |
| |
| // create the list of atomic string values |
| AtomicValue::List facetValues; |
| for (int j = 0; j < facetValueList.count(); ++j) { |
| facetValues.append(DerivedString<TypeString>::fromLexical(m_namePool, facetValueList.at(j))); |
| } |
| |
| // check if both lists have the same length |
| if (instanceValues.count() != facetValues.count()) |
| continue; |
| |
| // check if both lists are equal, that means the contain equal items in the same order |
| bool matchesAll = true; |
| for (int j = 0; j < instanceValues.count(); ++j) { |
| if (!XsdSchemaHelper::constructAndCompare(instanceValues.at(j), AtomicComparator::OperatorEqual, facetValues.at(j), targetType, m_context, m_reflection)) { |
| matchesAll = false; |
| break; |
| } |
| } |
| |
| if (matchesAll) { |
| found = true; |
| break; |
| } |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("List content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("List content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| bool XsdTypeChecker::checkConstrainingFacetsUnion(const QString &value, const QString &lexicalValue, const XsdSimpleType::Ptr &simpleType, const XsdFacet::Hash &facets, QString &errorMsg) const |
| { |
| if (facets.contains(XsdFacet::Enumeration)) { |
| const AnySimpleType::List memberTypes = simpleType->memberTypes(); |
| |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration); |
| |
| // convert the instance value into an atomic string value |
| const DerivedString<TypeString>::Ptr valueString = DerivedString<TypeString>::fromLexical(m_namePool, value); |
| |
| // collect the facet values into a list of atomic string values |
| const AtomicValue::List facetValues = facet->multiValue(); |
| |
| // compare the instance value against the facetValues for each member type and |
| // search for a match |
| |
| bool found = false; |
| for (int i = 0; i < memberTypes.count(); ++i) { |
| const AnySimpleType::Ptr targetType = comparableType(memberTypes.at(i)); |
| for (int j = 0; j < facetValues.count(); ++j) { |
| if (XsdSchemaHelper::constructAndCompare(valueString, AtomicComparator::OperatorEqual, facetValues.at(j), targetType, m_context, m_reflection)) { |
| found = true; |
| break; |
| } |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Union content is not listed in the enumeration facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Pattern)) { |
| const XsdFacet::Ptr facet = facets.value(XsdFacet::Pattern); |
| const AtomicValue::List multiValue = facet->multiValue(); |
| bool found = false; |
| for (int j = 0; j < multiValue.count(); ++j) { |
| const QString pattern = multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(); |
| QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection); |
| if (exp.exactMatch(lexicalValue)) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| errorMsg = QtXmlPatterns::tr("Union content does not match pattern facet."); |
| return false; |
| } |
| } |
| if (facets.contains(XsdFacet::Assertion)) { |
| //TODO: implement |
| } |
| |
| return true; |
| } |
| |
| AtomicValue::Ptr XsdTypeChecker::fromLexical(const QString &value, const SchemaType::Ptr &type, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const |
| { |
| if (type->name(m_namePool) == BuiltinTypes::xsNOTATION->name(m_namePool) || type->name(m_namePool) == BuiltinTypes::xsQName->name(m_namePool)) { |
| if (value.simplified().isEmpty()) |
| return ValidationError::createError(QtXmlPatterns::tr("Data of type %1 are not allowed to be empty.").arg(formatType(m_namePool, BuiltinTypes::xsNOTATION))); |
| |
| const QXmlName valueName = convertToQName(value); |
| return QNameValue::fromValue(m_namePool, valueName); |
| } else { |
| return ValueFactory::fromLexical(value, type, context, reflection); |
| } |
| } |
| |
| QXmlName XsdTypeChecker::convertToQName(const QString &name) const |
| { |
| const int pos = name.indexOf(QLatin1Char(':')); |
| |
| QXmlName::PrefixCode prefixCode = 0; |
| QXmlName::NamespaceCode namespaceCode; |
| QXmlName::LocalNameCode localNameCode; |
| if (pos != -1) { |
| prefixCode = m_context->namePool()->allocatePrefix(name.left(pos)); |
| namespaceCode = StandardNamespaces::empty; |
| for (int i = 0; i < m_namespaceBindings.count(); ++i) { |
| if (m_namespaceBindings.at(i).prefix() == prefixCode) { |
| namespaceCode = m_namespaceBindings.at(i).namespaceURI(); |
| break; |
| } |
| } |
| localNameCode = m_context->namePool()->allocateLocalName(name.mid(pos + 1)); |
| } else { |
| prefixCode = StandardPrefixes::empty; |
| namespaceCode = StandardNamespaces::empty; |
| for (int i = 0; i < m_namespaceBindings.count(); ++i) { |
| if (m_namespaceBindings.at(i).prefix() == prefixCode) { |
| namespaceCode = m_namespaceBindings.at(i).namespaceURI(); |
| break; |
| } |
| } |
| localNameCode = m_context->namePool()->allocateLocalName(name); |
| } |
| |
| return QXmlName(namespaceCode, localNameCode, prefixCode); |
| } |
| |
| QT_END_NAMESPACE |