/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** 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 Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /** * @file * @short This file is included by qcastingplatform_p.h. * If you need includes in this file, put them in CasttingPlatform.h, * outside of the namespace. */ template MaintainingReader::MaintainingReader(const typename ElementDescription::Hash &elementDescriptions, const QSet &standardAttributes, const ReportContext::Ptr &context, QIODevice *const queryDevice) : QXmlStreamReader(queryDevice) , m_hasHandledStandardAttributes(false) , m_context(context) , m_elementDescriptions(elementDescriptions) , m_standardAttributes(standardAttributes) { Q_ASSERT(m_context); Q_ASSERT(!m_elementDescriptions.isEmpty()); /* We start with stripping. */ m_stripWhitespace.push(true); } template MaintainingReader::~MaintainingReader() { } template QSourceLocation MaintainingReader::currentLocation() const { return QSourceLocation(documentURI(), lineNumber(), columnNumber()); } template QXmlStreamReader::TokenType MaintainingReader::readNext() { const TokenType retval = QXmlStreamReader::readNext(); switch(retval) { case StartElement: { m_currentElementName = TokenLookupClass::toToken(name()); m_currentAttributes = attributes(); m_hasHandledStandardAttributes = false; if(!m_currentAttributes.hasAttribute(QLatin1String("xml:space"))) m_stripWhitespace.push(m_stripWhitespace.top()); break; } case EndElement: m_currentElementName = TokenLookupClass::toToken(name()); m_stripWhitespace.pop(); break; default: break; } return retval; } template bool MaintainingReader::isWhitespace() const { return QXmlStreamReader::isWhitespace() || XPathHelper::isWhitespaceOnly(text()); } template void MaintainingReader::error(const QString &message, const ReportContext::ErrorCode code) const { m_context->error(message, code, currentLocation()); } template void MaintainingReader::warning(const QString &message) const { m_context->warning(message, currentLocation()); } template typename TokenLookupClass::NodeName MaintainingReader::currentElementName() const { return m_currentElementName; } template void MaintainingReader::validateElement(const LookupKey elementName) const { Q_ASSERT(tokenType() == QXmlStreamReader::StartElement); if(m_elementDescriptions.contains(elementName)) { // QHash::value breaks in Metrowerks Compiler const ElementDescription &desc = *m_elementDescriptions.find(elementName); const int attCount = m_currentAttributes.count(); QSet encounteredXSLTAtts; for(int i = 0; i < attCount; ++i) { const QXmlStreamAttribute &attr = m_currentAttributes.at(i); if(attr.namespaceUri().isEmpty()) { const typename TokenLookupClass::NodeName attrName(TokenLookupClass::toToken(attr.name())); encounteredXSLTAtts.insert(attrName); if(!desc.requiredAttributes.contains(attrName) && !desc.optionalAttributes.contains(attrName) && !m_standardAttributes.contains(attrName) && !isAnyAttributeAllowed()) { QString translationString; QList all(desc.requiredAttributes.toList() + desc.optionalAttributes.toList()); const int totalCount = all.count(); QStringList allowed; for(int i = 0; i < totalCount; ++i) allowed.append(QPatternist::formatKeyword(TokenLookupClass::toString(all.at(i)))); /* Note, we can't run toString() on attrName, because we're in this branch, * the token lookup doesn't have the string(!).*/ const QString stringedName(attr.name().toString()); if(totalCount == 0) { translationString = QtXmlPatterns::tr("Attribute %1 cannot appear on the element %2. Only the standard attributes can appear.") .arg(formatKeyword(stringedName), formatKeyword(name())); } else if(totalCount == 1) { translationString = QtXmlPatterns::tr("Attribute %1 cannot appear on the element %2. Only %3 is allowed, and the standard attributes.") .arg(formatKeyword(stringedName), formatKeyword(name()), allowed.first()); } else if(totalCount == 1) { /* Note, allowed has already had formatKeyword() applied. */ translationString = QtXmlPatterns::tr("Attribute %1 cannot appear on the element %2. Allowed is %3, %4, and the standard attributes.") .arg(formatKeyword(stringedName), formatKeyword(name()), allowed.first(), allowed.last()); } else { /* Note, allowed has already had formatKeyword() applied. */ translationString = QtXmlPatterns::tr("Attribute %1 cannot appear on the element %2. Allowed is %3, and the standard attributes.") .arg(formatKeyword(stringedName), formatKeyword(name()), allowed.join(QLatin1String(", "))); } m_context->error(translationString, ReportContext::XTSE0090, currentLocation()); } } else if(attr.namespaceUri() == namespaceUri()) { m_context->error(QtXmlPatterns::tr("XSL-T attributes on XSL-T elements must be in the null namespace, not in the XSL-T namespace which %1 is.") .arg(formatKeyword(attr.name())), ReportContext::XTSE0090, currentLocation()); } /* Else, attributes in other namespaces are allowed, continue. */ } const QSet requiredButMissing(QSet(desc.requiredAttributes).subtract(encounteredXSLTAtts)); if(!requiredButMissing.isEmpty()) { error(QtXmlPatterns::tr("The attribute %1 must appear on element %2.") .arg(QPatternist::formatKeyword(TokenLookupClass::toString(*requiredButMissing.constBegin())), formatKeyword(name())), ReportContext::XTSE0010); } } else { error(QtXmlPatterns::tr("The element with local name %1 does not exist in XSL-T.").arg(formatKeyword(name())), ReportContext::XTSE0010); } } template bool MaintainingReader::hasAttribute(const QString &namespaceURI, const QString &localName) const { Q_ASSERT(tokenType() == QXmlStreamReader::StartElement); return m_currentAttributes.hasAttribute(namespaceURI, localName); } template bool MaintainingReader::hasAttribute(const QString &localName) const { return hasAttribute(QString(), localName); } template QString MaintainingReader::readAttribute(const QString &localName, const QString &namespaceURI) const { Q_ASSERT(tokenType() == QXmlStreamReader::StartElement); Q_ASSERT_X(m_currentAttributes.hasAttribute(namespaceURI, localName), Q_FUNC_INFO, "Validation must be done before this function is called."); return m_currentAttributes.value(namespaceURI, localName).toString(); }