diff options
Diffstat (limited to 'src/xmlpatterns/api')
60 files changed, 12995 insertions, 0 deletions
diff --git a/src/xmlpatterns/api/api.pri b/src/xmlpatterns/api/api.pri new file mode 100644 index 0000000..a0adf75 --- /dev/null +++ b/src/xmlpatterns/api/api.pri @@ -0,0 +1,57 @@ +HEADERS += $$PWD/qabstractxmlforwarditerator_p.h \ + $$PWD/qabstractmessagehandler.h \ + $$PWD/qabstracturiresolver.h \ + $$PWD/qabstractxmlnodemodel.h \ + $$PWD/qabstractxmlnodemodel_p.h \ + $$PWD/qabstractxmlpullprovider_p.h \ + $$PWD/qabstractxmlreceiver.h \ + $$PWD/qabstractxmlreceiver_p.h \ + $$PWD/qdeviceresourceloader_p.h \ + $$PWD/qiodevicedelegate_p.h \ + $$PWD/qnetworkaccessdelegator_p.h \ + $$PWD/qpullbridge_p.h \ + $$PWD/qresourcedelegator_p.h \ + $$PWD/qsimplexmlnodemodel.h \ + $$PWD/qsourcelocation.h \ + $$PWD/quriloader_p.h \ + $$PWD/qvariableloader_p.h \ + $$PWD/qxmlformatter.h \ + $$PWD/qxmlname.h \ + $$PWD/qxmlnamepool.h \ + $$PWD/qxmlquery.h \ + $$PWD/qxmlquery_p.h \ + $$PWD/qxmlresultitems.h \ + $$PWD/qxmlresultitems_p.h \ + $$PWD/qxmlschema.h \ + $$PWD/qxmlschema_p.h \ + $$PWD/qxmlschemavalidator.h \ + $$PWD/qxmlschemavalidator_p.h \ + $$PWD/qxmlserializer.h \ + $$PWD/qxmlserializer_p.h \ + $$PWD/qcoloringmessagehandler_p.h \ + $$PWD/qcoloroutput_p.h \ + $$PWD/qxmlpatternistcli_p.h +SOURCES += $$PWD/qvariableloader.cpp \ + $$PWD/qabstractmessagehandler.cpp \ + $$PWD/qabstracturiresolver.cpp \ + $$PWD/qabstractxmlnodemodel.cpp \ + $$PWD/qabstractxmlpullprovider.cpp \ + $$PWD/qabstractxmlreceiver.cpp \ + $$PWD/qiodevicedelegate.cpp \ + $$PWD/qnetworkaccessdelegator.cpp \ + $$PWD/qpullbridge.cpp \ + $$PWD/qresourcedelegator.cpp \ + $$PWD/qsimplexmlnodemodel.cpp \ + $$PWD/qsourcelocation.cpp \ + $$PWD/quriloader.cpp \ + $$PWD/qxmlformatter.cpp \ + $$PWD/qxmlname.cpp \ + $$PWD/qxmlnamepool.cpp \ + $$PWD/qxmlquery.cpp \ + $$PWD/qxmlresultitems.cpp \ + $$PWD/qxmlschema.cpp \ + $$PWD/qxmlschema_p.cpp \ + $$PWD/qxmlschemavalidator.cpp \ + $$PWD/qxmlserializer.cpp \ + $$PWD/qcoloringmessagehandler.cpp \ + $$PWD/qcoloroutput.cpp diff --git a/src/xmlpatterns/api/qabstractmessagehandler.cpp b/src/xmlpatterns/api/qabstractmessagehandler.cpp new file mode 100644 index 0000000..63a963b --- /dev/null +++ b/src/xmlpatterns/api/qabstractmessagehandler.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QMutex> + +#include "private/qobject_p.h" +#include "qabstractmessagehandler.h" + +QT_BEGIN_NAMESPACE + +class QAbstractMessageHandlerPrivate : public QObjectPrivate +{ +public: + QMutex mutex; +}; + +/*! + \class QAbstractMessageHandler + \threadsafe + \since 4.4 + \ingroup xml-tools + + \brief The QAbstractMessageHandler class provides a callback interface for handling messages. + + QAbstractMessageHandler is an abstract base class that provides a + callback interface for handling messages. For example, class + QXmlQuery parses and runs an XQuery. When it detects a compile + or runtime error, it generates an appropriate error message, + but rather than output the message itself, it passes the message to + the message() function of its QAbstractMessageHandler. + See QXmlQuery::setMessageHandler(). + + You create a message handler by subclassing QAbstractMessageHandler + and implementing handleMessage(). You then pass a pointer to an + instance of your subclass to any classes that must generate + messages. The messages are sent to the message handler via the + message() function, which forwards them to your handleMessge(). + The effect is to serialize the handling of all messages, which + means your QAbstractMessageHandler subclass is thread safe. + + A single instance of QAbstractMessageHandler can be called on to + handle messages from multiple sources. Hence, the content of a + message, which is the \e description parameter passed to message() + and handleMessage(), must be interpreted in light of the context + that required the message to be sent. That context is specified by + the \e identifier and \e sourceLocation parameters to message() + handleMessage(). + */ + +/*! + Constructs a QAbstractMessageHandler. The \a parent is passed + to the QObject base class constructor. + */ +QAbstractMessageHandler::QAbstractMessageHandler(QObject *parent) : QObject(*new QAbstractMessageHandlerPrivate(), parent) +{ +} + +/*! + Destructs this QAbstractMessageHandler. + */ +QAbstractMessageHandler::~QAbstractMessageHandler() +{ +} + +/*! + Sends a message to this message handler. \a type is the kind of + message being sent. \a description is the message content. The \a + identifier is a URI that identifies the message and is the key to + interpreting the other arguments. + + Typically, this class is used for reporting errors, as is the case + for QXmlQuery, which uses a QAbstractMessageHandler to report + compile and runtime XQuery errors. Hence, using a QUrl as the + message \a identifier is was inspired by the explanation of \l{error + handling in the XQuery language}. Because the \a identifier is + composed of a namespace URI and a local part, identifiers with the + same local part are unique. The caller is responsible for ensuring + that \a identifier is either a valid QUrl or a default constructed + QUrl. + + \a sourceLocation identifies a location in a resource (i.e., file or + document) where the need for reporting a message was detected. + + This function unconditionally calls handleMessage(), passing all + its parameters unmodified. + + \sa {http://www.w3.org/TR/xquery/#errors} + */ +void QAbstractMessageHandler::message(QtMsgType type, + const QString &description, + const QUrl &identifier, + const QSourceLocation &sourceLocation) +{ + Q_D(QAbstractMessageHandler); + QMutexLocker(&d->mutex); + handleMessage(type, description, identifier, sourceLocation); +} + +/*! + \fn void QAbstractMessageHandler::handleMessage(QtMsgType type, + const QString &description, + const QUrl &identifier = QUrl(), + const QSourceLocation &sourceLocation = QSourceLocation()) = 0 + + This function must be implemented by the sub-class. message() will + call this function, passing in its parameters, \a type, + \a description, \a identifier and \a sourceLocation unmodified. + */ + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qabstractmessagehandler.h b/src/xmlpatterns/api/qabstractmessagehandler.h new file mode 100644 index 0000000..a5fe0ff --- /dev/null +++ b/src/xmlpatterns/api/qabstractmessagehandler.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMESSAGEHANDLER_H +#define QABSTRACTMESSAGEHANDLER_H + +#include <QtXmlPatterns/QSourceLocation> +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QAbstractMessageHandlerPrivate; +class Q_XMLPATTERNS_EXPORT QAbstractMessageHandler : public QObject +{ + Q_OBJECT +public: + QAbstractMessageHandler(QObject *parent = 0); + virtual ~QAbstractMessageHandler(); + + void message(QtMsgType type, + const QString &description, + const QUrl &identifier = QUrl(), + const QSourceLocation &sourceLocation = QSourceLocation()); + +protected: + virtual void handleMessage(QtMsgType type, + const QString &description, + const QUrl &identifier, + const QSourceLocation &sourceLocation) = 0; +private: + Q_DECLARE_PRIVATE(QAbstractMessageHandler) + Q_DISABLE_COPY(QAbstractMessageHandler) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qabstracturiresolver.cpp b/src/xmlpatterns/api/qabstracturiresolver.cpp new file mode 100644 index 0000000..baa65b3 --- /dev/null +++ b/src/xmlpatterns/api/qabstracturiresolver.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QUrl> + +#include "qabstracturiresolver.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractUriResolver + \brief The QAbstractUriResolver class is a callback interface for resolving Uniform Resource Identifiers. + \since 4.4 + \reentrant + \ingroup xml-tools + + A Uniform Resource Identifier (URI) is a string that uniquely + identifies a resource. URIs are versatile global identifiers. It is + often useful to transform a URI that identifies something logical + into a URI that locates something physical (a URL), or to simply map + a URI to a different URI. QAbstractUriResolver::resolve() provides + this functionality. + + For example, one could write a QAbstractUriResolver subclass that + rewrites library ISBN number URIs as book title URLs, e.g., + \e{urn:isbn:0-345-33973-8} would be rewritten as + \e{file:///books/returnOfTheKing.doc}. Or a QAbstractUriResolver + subclass could be written for a web browser to let the web browser + protect the user's private files by mapping incoming requests for + them to null URIs. + + \sa {http://en.wikipedia.org/wiki/Uniform_Resource_Identifier} +*/ + +/*! + Constructs a QAbstractUriResolver with the specified \a parent. + */ +QAbstractUriResolver::QAbstractUriResolver(QObject *parent) : QObject(parent) +{ +} + +/*! + Destructor. + */ +QAbstractUriResolver::~QAbstractUriResolver() +{ +} + +/*! + \fn QUrl QAbstractUriResolver::resolve(const QUrl &relative, const QUrl &baseURI) const + + Returns the \a relative URI resolved using the \a baseURI. + + The caller guarantees that both \a relative and \a baseURI are + valid, and that \a baseURI is absolute. \a relative can be relative, + absolute, or empty. + + The returned QUrl can be a default constructed QUrl. If it is not a + default constructed QUrl, it will be absolute and valid. If a default + constructed QUrl is returned, it means the \a relative URI was not + accepted to be resolved. + + If the reimplemented resolve() function decides it has nothing to do + about resolving the \a relative URI, it should simply return the \a + relative URI resolved against the \a baseURI, i.e.: + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qabstracturiresolver.cpp 0 + + \sa QUrl::isRelative(), QUrl::isValid() + */ + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qabstracturiresolver.h b/src/xmlpatterns/api/qabstracturiresolver.h new file mode 100644 index 0000000..bbe4a90 --- /dev/null +++ b/src/xmlpatterns/api/qabstracturiresolver.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTURIRESOLVER_H +#define QABSTRACTURIRESOLVER_H + +#include <QtCore/QObject> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QUrl; +class QAbstractUriResolverPrivate; + +class Q_XMLPATTERNS_EXPORT QAbstractUriResolver : public QObject +{ + Q_OBJECT +public: + QAbstractUriResolver(QObject *parent = 0); + virtual ~QAbstractUriResolver(); + + virtual QUrl resolve(const QUrl &relative, + const QUrl &baseURI) const = 0; + +private: + Q_DISABLE_COPY(QAbstractUriResolver) + Q_DECLARE_PRIVATE(QAbstractUriResolver) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qabstractxmlforwarditerator.cpp b/src/xmlpatterns/api/qabstractxmlforwarditerator.cpp new file mode 100644 index 0000000..046b9e4 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlforwarditerator.cpp @@ -0,0 +1,269 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QAbstractXmlForwardIterator + \brief The QAbstractXmlForwardIterator class is a base class for forward iterators. + \reentrant + \since 4.4 + \ingroup xml-tools + \internal + + This abstract base class is for creating iterators for + traversing custom data structures modeled to look like XML. + An item can be instantiated in QAbstractXmlForwardIterator if: + \list + + \o It has a default constructor, a copy constructor, and an + assignment operator, and + + \o It has an appropriate qIsForwardIteratorEnd() function. + \endlist + + @ingroup Patternist_iterators + @author Frans Englich <frans.englich@nokia.com> + */ + +/*! + \typedef QAbstractXmlForwardIterator::Ptr + + A smart pointer wrapping an instance of a QAbstractXmlForwardIterator subclass. + */ + +/*! + \typedef QAbstractXmlForwardIterator::List + A QList containing QAbstractXmlForwardIterator::Ptr instances. + */ + +/*! + \typedef QAbstractXmlForwardIterator::Vector + A QVector containing QAbstractXmlForwardIterator::Ptr instances. + */ + +/*! + \fn QAbstractXmlForwardIterator::QAbstractXmlForwardIterator() + + Default constructor. + */ + +/*! + \fn QAbstractXmlForwardIterator::~QAbstractXmlForwardIterator() + + Destructor. + */ + +/*! + \fn T QAbstractXmlForwardIterator::next() = 0; + + Returns the next item in the sequence, or + a null object if the end has been reached. + */ + +/*! + \fn T QAbstractXmlForwardIterator::current() const = 0; + + Returns the current item in the sequence. If this function is called + before the first call to next(), a null object is returned. If the + end of the sequence has been reached, a null object is returned. + */ + +/*! + \fn qint64 QAbstractXmlForwardIterator::position() const = 0; + + Returns the current position in the sequence represented + by \e this. + + The first position is 1, not 0. If next() hasn't been called, 0 is + returned. If \e this has reached the end, -1 is returned. + */ + +/*! + \fn bool qIsForwardIteratorEnd(const T &unit) + \since 4.4 + \relates QAbstractXmlForwardIterator + + The Callback QAbstractXmlForwardIterator uses for determining + whether \a unit is the end of a sequence. + + If \a unit is a value that would signal the end of a sequence + (typically a default constructed value), this function returns \c + true, otherwise \c false. + + This implementation works for any type that has a boolean operator. + For example, this function should work satisfactory for pointers. + */ + +/*! + \fn qint64 QAbstractXmlForwardIterator::count() + \internal + + Determines the number of items this QAbstractXmlForwardIterator + represents. + + Note that this function is not \c const. It modifies the + QAbstractXmlForwardIterator. The reason for this is efficiency. If + this QAbstractXmlForwardIterator must not be changed, get a copy() + before performing the count. + + The default implementation simply calls next() until the end is + reached. Hence, it may be of interest to override this function if + the sub-class knows a better way of computing its count. + + The number of items in the sequence is returned. + */ + +/*! + \fn QAbstractXmlForwardIterator<T>::Ptr QAbstractXmlForwardIterator::toReversed(); + \internal + + Returns a reverse iterator for the sequence. + + This function may modify the iterator, it can be considered a + function that evaluates this QAbstractXmlForwardIterator. It is not + a \e getter, but potentially alters the iterator in the same way the + next() function does. If this QAbstractXmlForwardIterator must not + be modified, such that it can be used for evaluation with next(), + use a copy(). + */ + +/*! + \fn QList<T> QAbstractXmlForwardIterator<T>::toList(); + \internal + + Performs a copy of this QAbstractXmlForwardIterator(with copy()), + and returns its items in a QList. Thus, this function acts as a + conversion function, converting the sequence to a QList. + + This function may modify the iterator. It is not a \e getter, but + potentially alters the iterator in the same way the next() function + does. If this QAbstractXmlForwardIterator must not be modified, + such that it can be used for evaluation with next(), use a copy(). + */ + +/*! + \fn T QAbstractXmlForwardIterator::last(); + \internal + + Returns the item at the end of this QAbstractXmlForwardIterator. + The default implementation calls next() until the end is reached. + */ + +/*! + \fn T QAbstractXmlForwardIterator::isEmpty(); + \internal + Returns true if the sequence is empty. + */ + +/*! + \fn qint64 QAbstractXmlForwardIterator::sizeHint() const; + \internal + + Gives a hint to the size of the contained sequence. The hint is + assumed to be as close as possible to the actual size. + + If no sensible estimate can be computed, -1 should be returned. + */ + +/*! + \fn typename QAbstractXmlForwardIterator<T>::Ptr QAbstractXmlForwardIterator::copy() const; + \internal + + Copies this QAbstractXmlForwardIterator and returns the copy. + + A copy and the original instance are completely independent of each + other. Because evaluating an QAbstractXmlForwardIterator modifies + it, one should always use a copy when an + QAbstractXmlForwardIterator needs to be used several times. + */ + +/*! + \class QPatternist::ListIteratorPlatform + \brief Helper class for ListIterator, and should only be instantiated through sub-classing. + \reentrant + \since 4.4 + \internal + \ingroup xml-tools + + ListIteratorPlatform iterates an InputList with instances + of InputType. For every item in it, it returns an item from it, + that is converted to OutputType by calling a function on Derived + that has the following signature: + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qabstractxmlforwarditerator.cpp 0 + + TODO Document why this class doesn't duplicate ItemMappingIterator. + */ + +/*! + \fn QPatternist::ListIteratorPlatform::ListIteratorPlatform(const ListType &list); + + Constructs a ListIteratorPlatform that walks the given \a list. + */ + +/*! + \class QPatternist::ListIterator + \brief Bridges values in Qt's QList container class into an QAbstractXmlForwardIterator. + \reentrant + \since 4.4 + \internal + \ingroup xml-tools + + ListIterator takes a reference to a QList<T> instance and allows + access to that list via its QAbstractXmlForwardIterator interface. + ListIterator is parameterized with the type to iterate over, e.g., + Item or Expression::Ptr. + + ListIterator is used by the ExpressionSequence to create an + iterator over its operands. The iterator will be passed to a + MappingIterator. + */ + +/*! + \fn QPatternist::makeListIterator(const QList<T> &qList) + \relates QPatternist::ListIterator + + An object generator for ListIterator. + + makeListIterator() is a convenience function to avoid specifying + the full template instantiation for ListIterator. Conceptually, it + is identical to Qt's qMakePair(). + + */ diff --git a/src/xmlpatterns/api/qabstractxmlforwarditerator_p.h b/src/xmlpatterns/api/qabstractxmlforwarditerator_p.h new file mode 100644 index 0000000..3e222e8 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlforwarditerator_p.h @@ -0,0 +1,341 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QABSTRACTXMLFORWARDITERATOR_H +#define QABSTRACTXMLFORWARDITERATOR_H + +#include <QtCore/QList> +#include <QtCore/QVector> +#include <QtCore/QSharedData> +#include <QtCore/QString> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +template<typename T> class QVector; + +/* In this file we in some cases do not use QAbstractXmlForwardIterator's Ptr typedef. + * This is a compiler workaround for MS VS 6.0. */ + +template<typename T> +inline bool qIsForwardIteratorEnd(const T &unit) +{ + return !unit; +} + +/** + * @short Helper class for StringSplitter + * + * Needed by the QAbstractXmlForwardIterator sub-class. + * + * @relates StringSplitter + */ +template<> +inline bool qIsForwardIteratorEnd(const QString &unit) +{ + return unit.isNull(); +} + +template<typename T> class QAbstractXmlForwardIterator; + +class QAbstractXmlForwardIteratorPrivate; + +template<typename T> +class QAbstractXmlForwardIterator : public QSharedData +{ +public: + typedef QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<T> > Ptr; + typedef QList<QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<T> > > List; + typedef QVector<QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<T> > > Vector; + + inline QAbstractXmlForwardIterator() : d_ptr(0) {} + virtual ~QAbstractXmlForwardIterator() {} + + virtual T next() = 0; + virtual T current() const = 0; + + virtual qint64 position() const = 0; + + virtual typename QAbstractXmlForwardIterator<T>::Ptr toReversed(); + virtual QList<T> toList(); + virtual typename QAbstractXmlForwardIterator<T>::Ptr copy() const; + virtual T last(); + virtual bool isEmpty(); + virtual qint64 count(); + virtual qint64 sizeHint() const; + +private: + Q_DISABLE_COPY(QAbstractXmlForwardIterator<T>) + + QAbstractXmlForwardIteratorPrivate *d_ptr; /* Currently not used. */ +}; + +/* The namespace QPatternist and its members are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ +namespace QPatternist +{ + class DeduplicateIterator; + + template<typename InputType, + typename OutputType, + typename Derived, + typename ListType = QList<InputType> > + class ListIteratorPlatform : public QAbstractXmlForwardIterator<OutputType> + { + /* This declaration is a workaround for a set of GCC versions on OS X, + * amongst others powerpc-apple-darwin8-gcc-4.0.1 (GCC) 4.0.1. In + * DeduplicateIterator, it fails to see the protected inheritance. */ + friend class DeduplicateIterator; + + public: + virtual OutputType next() + { + if(m_position == -1) + return OutputType(); + + if(m_position == m_list.count()) + { + m_position = -1; + m_current = OutputType(); + return OutputType(); + } + + m_current = static_cast<const Derived *>(this)->inputToOutputItem(m_list.at(m_position)); + ++m_position; + return m_current; + } + + virtual OutputType current() const + { + return m_current; + } + + virtual qint64 position() const + { + return m_position; + } + + virtual qint64 count() + { + return m_list.count(); + } + + virtual typename QAbstractXmlForwardIterator<OutputType>::Ptr copy() const + { + return QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<OutputType> >(new ListIteratorPlatform<InputType, OutputType, Derived, ListType>(m_list)); + } + + protected: + inline ListIteratorPlatform(const ListType &list) : m_list(list) + , m_position(0) + { + } + + const ListType m_list; + qint64 m_position; + OutputType m_current; + }; + + template<typename T, + typename ListType = QList<T> > + class ListIterator : public ListIteratorPlatform<T, T, ListIterator<T, ListType>, ListType> + { + /* + * This declaration is needed for MSVC 2005, 14.00.50727.42 for 80x86. + */ + friend class IteratorVector; + + using ListIteratorPlatform<T, T, ListIterator<T, ListType>, ListType>::m_list; + + static inline QVector<T> toVector(const QVector<T> &vector) + { + return vector; + } + + static inline QVector<T> toVector(const QList<T> &list) + { + return list.toVector(); + } + + static inline QList<T> toList(const QVector<T> &vector) + { + return vector.toList(); + } + + static inline QList<T> toList(const QList<T> &list) + { + return list; + } + + public: + inline ListIterator(const ListType &list) : ListIteratorPlatform<T, T, ListIterator<T, ListType>, ListType>(list) + { + } + + virtual QList<T> toList() + { + return toList(m_list); + } + + virtual QVector<T> toVector() + { + return toVector(m_list); + } + + private: + inline const T &inputToOutputItem(const T &inputType) const + { + return inputType; + } + friend class ListIteratorPlatform<T, T, ListIterator<T, ListType>, ListType>; + + // needed for MSVC 2005 + friend class DeduplicateIterator; + }; + + template<typename T> + inline + typename QAbstractXmlForwardIterator<T>::Ptr + makeListIterator(const QList<T> &list) + { + return typename ListIterator<T>::Ptr(new ListIterator<T>(list)); + } + + template<typename T> + inline + typename QAbstractXmlForwardIterator<T>::Ptr + makeVectorIterator(const QVector<T> &vector) + { + return typename ListIterator<T, QVector<T> >::Ptr(new ListIterator<T, QVector<T> >(vector)); + } +} + +template<typename T> +QList<T> QAbstractXmlForwardIterator<T>::toList() +{ + QList<T> result; + T item(next()); + + while(!qIsForwardIteratorEnd(item)) + { + result.append(item); + item = next(); + } + + return result; +} + +template<typename T> +qint64 QAbstractXmlForwardIterator<T>::count() +{ + qint64 retval = 0; + + while(!qIsForwardIteratorEnd(next())) + ++retval; + + return retval; +} + +template<typename T> +typename QAbstractXmlForwardIterator<T>::Ptr QAbstractXmlForwardIterator<T>::toReversed() +{ + T item(next()); + QList<T> result; + + while(!qIsForwardIteratorEnd(item)) + { + result.prepend(item); + item = next(); + } + + return QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<T> >(new QPatternist::ListIterator<T>(result)); +} + +template<typename T> +T QAbstractXmlForwardIterator<T>::last() +{ + T item(next()); + + while(!qIsForwardIteratorEnd(item)) + item = next(); + + return item; +} + +template<typename T> +typename QAbstractXmlForwardIterator<T>::Ptr QAbstractXmlForwardIterator<T>::copy() const +{ + Q_ASSERT_X(false, Q_FUNC_INFO, + "This function is internal, unsupported, and should never be called."); + return typename QAbstractXmlForwardIterator<T>::Ptr(); +} + +template<typename T> +bool QAbstractXmlForwardIterator<T>::isEmpty() +{ + return qIsForwardIteratorEnd(next()); +} + +template<typename T> +qint64 QAbstractXmlForwardIterator<T>::sizeHint() const +{ + Q_ASSERT_X(false, Q_FUNC_INFO, "This function is currently not expected to be used."); + return -1; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qabstractxmlnodemodel.cpp b/src/xmlpatterns/api/qabstractxmlnodemodel.cpp new file mode 100644 index 0000000..c2000bb --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlnodemodel.cpp @@ -0,0 +1,1683 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QVector> + +#include "qabstractxmlnodemodel_p.h" +#include "qabstractxmlreceiver.h" +#include "qcommonvalues_p.h" +#include "qemptyiterator_p.h" +#include "qitemmappingiterator_p.h" +#include "qitem_p.h" +#include "qnamespaceresolver_p.h" +#include "qsequencemappingiterator_p.h" +#include "qsingletoniterator_p.h" + +#include "qabstractxmlnodemodel.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +typedef QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > QXmlNodeModelIndexIteratorPointer; + +/** + * @file + * @short Contains the implementation of QAbstractXmlNodeModel. + */ + +bool QAbstractXmlNodeModel::isIgnorableInDeepEqual(const QXmlNodeModelIndex &n) +{ + Q_ASSERT(!n.isNull()); + const QXmlNodeModelIndex::NodeKind nk = n.kind(); + return nk == QXmlNodeModelIndex::ProcessingInstruction || + nk == QXmlNodeModelIndex::Comment; +} + + +/*! + \class QAbstractXmlNodeModel + \brief The QAbstractXmlNodeModel class is an abstract base class for modeling non-XML data to look like XML for QXmlQuery. + \threadsafe + \since 4.4 + \ingroup xml-tools + + The QAbstractXmlNodeModel specifies the interface that a node model + must implement for that node model be accessible to the query engine + for processing XQuery queries. A node model represents data as a + structure that can be queried as if the data were XML. + + The node model represented by a subclass of QAbstractXmlNodeModel is + meant to be accessed by the QtXmlPatterns query engine. If the API + seems a little strange in a few places, it is because the member + functions are called by the query engine as it evaluates an + XQuery. They aren't meant to be used programatically. + + \section1 Usage + + QAbstractXmlNodeModel bridges the gap between the arbitrary structure + of the non-XML data to be queried and the well-defined structure of + XML data understood by QXmlQuery. + + Consider a chemistry application that reads the file \c + chemistryData, which contains non-XML data that represents a + chemical structure composed of molecules and atoms. The application + will query this chemistry data with an XQuery it reads from file \c + queryFile. We write a custom subclass of QAbstractXmlNodeModel (\c + ChemistryNodeModel) that reads \c chemistryData and builds a data + structure, perhaps composed of objects of our own classes \c + molecule and \c atom. Clearly, this data structure is not XML. Our + custom subclass will know how to traverse this non-XML structure and + present it through the \l + {http://www.w3.org/TR/xpath-datamodel/}{XPath Data Model interface}. + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qabstractxmlnodemodel.cpp 1 + + The application first creates an instance of QXmlQuery and calls \l + {QXmlQuery::setQuery()}{setQuery()} to read \c queryFile containing + the XQuery we want to run. Then it creates an instance of our custom + node model class, \c ChemistryNodeModel, which is a subclass of + QAbstractXmlNodeModel. Its constructor is called with the \l + {QXmlNamePool} {name pool} obtained from our QXmlQuery, and with the + \c chemistryFile containing the structure of molecules and atoms to + be queried. The \l {QXmlNamePool} {name pool} is required because + our custom node model has the member function \l + {QAbstractXmlNodeModel::name()} {name()}, which returns the \l + {QXmlName} {name} of any node in the model. The \l {QXmlQuery} + {query} and the custom node model must use the same name pool for + constructing these \l {QXmlName} {names}. The constructor would then + read \c chemistryFile and build the custom node model structure. + + To connect the \c query to the custom node model, we must bind a + variable name used in the query to a node in the model. The variable + can then be used in the query as a starting node. First, an \l + {QXmlNodeModelIndex} {index} for the desired starting node is + retrieved by calling QAbstractXmlNodeModel::createIndex(). Then the + index is bound to a variable name, in this case \c queryRoot, by + passing the name and the index to QXmlQuery::bindVariable(). The + query can then use a variable reference \c $queryRoot to refer to + the starting node. Note that if the \l {QXmlQuery} {query} uses + multiple variable references, a call to QXmlQuery::bindVariable() + is required to bind each different variable name to a node in the + model. + + The query is executed when the application calls one of the + QXmlQuery evaluation functions. The application uses + QXmlQuery::evaluateTo(QAbstractXmlReceiver *), because it then uses + a \l {QXmlSerializer} {serializer} to out the query result as XML to + \c stdout. We could have used QXmlQuery::evaluateTo(QXmlResultItems + *) to get a list of result items, or + QXmlQuery::evaluateTo(QStringList *) if the query evaluated to a + sequence of \c {xs:string} values. + + During query execution, the engine iterates over the node model + using nextFromSimpleAxis() to get the \l {QXmlNodeModelIndex} + {index} of the next node to be visited. The engine can get the name + of a node by calling name() with the node's \l {QXmlNodeModelIndex} + {index}. stringValue(), baseUri(), documentUri() and kind() are also + called as needed with a node \l {QXmlNodeModelIndex} {index}. + + The example demonstrates the standard pattern for using a subclass + of QAbstractXmlNodeModel in combination with QXmlQuery to perform + an XQuery. + + \list 1 + + \o Instantiate QXmlQuery and give it the XQuery to be run; + + \o Instantiate a subclass of QAbstractXmlNodeModel or + QSimpleXmlNodeModel; + + \o Retrieve a QXmlNodeModelIndex for the node in the model where + the QXmlQuery should start the query; + + \o Use QXmlQuery::bindVariable() to bind the QXmlNodeModelIndex + to \c {$variable name}; + + \o Call one of the QXmlQuery evaluation functions to run the + query. + + \endlist + + \section1 Subclassing + + Because the \l {http://www.w3.org/TR/xpath-datamodel/}{XPath Data Model + interface} presented by QAbstractXmlNodeModel allows QXmlQuery to + operate on non-XML data as if it were XML, implementing subclasses + of QAbstractXmlNodeModel can involve a significant amount of + work. The QSimpleXmlNodeModel class is provided to simplify the + implementation for many common use cases. + + \section1 Thread Safety + + Because the node model can be accessed concurrently by threads in + the QtXmlPatterns module, subclasses of QAbstractXmlNodeModel must + be written to be \l{Reentrancy and Thread-Safety}{thread-safe}. + Classes that simplify implementing thread-safety include QReadLocker + and QWriteLocker. + + See the example \l{File System Example} for a demonstration. + */ + +/*! + \enum QXmlNodeModelIndex::Constants + + \value ForwardAxis All forward axes include this flag. + \value ReverseAxis All reverse axes include this flag. + */ + +/*! + \enum QXmlNodeModelIndex::DocumentOrder + + Identifies the specific node comparison operator that should be + used. + + \value Precedes Signifies the \c \<\< operator. Test whether the + first operand precedes the second in the document. + + \value Follows Signifies the \c \>\> operator. Test whether the + first operand follows the second in the document. + + \value Is Signifies the \c is operator. Test whether two nodes have + the same node identity. + */ + +/*! + \enum QAbstractXmlNodeModel::SimpleAxis + + Four axes that each contain one node only. + + \value Parent The parent of the context node + \value FirstChild The first child of the context node + \value PreviousSibling The previous child of the context node + \value NextSibling The next child of the context node +*/ + +/*! + \enum QXmlNodeModelIndex::Axis + \internal + + Identify the axes emanating from a node. + + The axes AxisChild, AxisDescendant, AxisAttribute, AxisSelf, + AxisDescendantOrSelf, AxisFollowingSibling, and AxisFollowing are + forward axes. + + The axes AxisParent, AxisAncestor, AxisPrecedingSibling, + AxisPreceding and AxisAncestorOrSelf are reverse axes. + + \sa {http://www.w3.org/TR/xquery/#axes}{XQuery 1.0: An XML Query Language, 3.2.1.1 Axes} + + \value AxisChild The \c child axis. + + \value AxisDescendant The \c descendant axis. + + \value AxisAttribute The \c attribute axis. Note: There + is a node kind named \c{Attribute}. + + \value AxisSelf The \c self axis. + + \value AxisDescendantOrSelf The \c descendant-or-self axis. + + \value AxisFollowingSibling The \c following-sibling axis. + + \value AxisNamespace The \c namespace axis. Note: Does + not exist in XQuery; deprecated in + XPath 2.0 (optionally supported); + mandatory in XPath 1.0. + + \value AxisFollowing The \c following axis. + + \value AxisParent The \c parent axis. + + \value AxisAncestor The \c ancestor axis. + + \value AxisPrecedingSibling The \c preceding-sibling axis. + + \value AxisPreceding The \c preceding axis. + + \value AxisAncestorOrSelf The \c ancestor-or-self axis. +*/ + +using namespace QPatternist; + +/*! + Default constructor. + */ +QAbstractXmlNodeModel::QAbstractXmlNodeModel() : d_ptr(0) +{ +} + +/*! + \internal + + Takes the d-pointer. + + */ +QAbstractXmlNodeModel::QAbstractXmlNodeModel(QAbstractXmlNodeModelPrivate *d) : d_ptr(d) +{ +} + +/*! + Destructor. + */ +QAbstractXmlNodeModel::~QAbstractXmlNodeModel() +{ +} + +/*! + \typedef QAbstractXmlNodeModel::List + + A \l{QList}{list} of \l{QExplicitlySharedDataPointer} {smart + pointers} to instances of QAbstractXmlNodeModel. + + \sa QExplicitlySharedDataPointer + */ + +/*! + \typedef QAbstractXmlNodeModel::Ptr + + A \l {QExplicitlySharedDataPointer} {smart pointer} to an + instance of QAbstractXmlNodeModel. + + \sa QExplicitlySharedDataPointer + */ + +/*! + \fn QUrl QAbstractXmlNodeModel::baseUri(const QXmlNodeModelIndex &n) const + + Returns the base URI for the node whose index is \a n. The caller + guarantees that \a n is not \c null and that it belongs to a node + in this node model. + + The base URI of a node can be extracted using the \c fn:base-uri() + function. The base URI is typically used for resolving relative URIs + that appear in the node or its children. It is conformant to just + return the document URI, although that might not properly reflect + the underlying data. + + This function maps to the \c dm:base-uri accessor, which returns + a base URI according to the following: + + \list + + \o For document nodes, the base URI and the document URI are the same. + + \o For elements, the base URI is the URI appearing in the element's + \c xml:base attribute, if present, or it is resolved to the + parent element's base URI. + + \o Namespace nodes have no base URI. + + \o The base URI for a processing instruction, comment, attribute, + or text node is the base URI of the node's parent element. + + \endlist + + The implementation guarantees to return a valid QUrl, or a default + constructed QUrl. If a node has no base URI, as in the case where a + comment has no parent, a default constructed QUrl is returned. + + \sa {http://www.w3.org/TR/xpath-datamodel/#dm-base-uri}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.2 base-uri Accessor} + */ + +/*! + \fn QUrl QAbstractXmlNodeModel::documentUri(const QXmlNodeModelIndex &n) const + + Returns the document URI of \a n. The document URI identifies the + resource which is the document. For example, the document could be a + regular file, e.g., \c{file:/}, or it could be the \c{http://} URL of + the location of a file. The document URI is used for resolving URIs + and to simply know where the document is. + + If the node model maps to a URI in a natural way, return that URI. + Otherwise, return the company or product URI. The document URI can + be any URI as long as its valid and absolute. + + The caller guarantees that \a n is not \c null and that it belongs + to this QAbstractXmlNodeModel. + + This function maps to the \c dm:document-uri accessor, which + returns a document URI according to the following: + + \list + + \o If \a n is a document node, return an absolute QUrl containing + the document URI, or a default constructed QUrl. The latter + signals that no document URI is available for the document node. + + \o For all other nodes, return a default constructed QUrl. + + \endlist + + \sa {http://www.w3.org/TR/xpath-datamodel/#dm-document-uri}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.4 document-uri Accessor} + \sa QUrl::isValid(), QUrl::isRelative() + */ + +/* +### Qt 5: + +Add the function: + + virtual QSourceLocation sourceLocation(const QXmlNodeModelIndex &nodeIndex) const = 0; + +Such that the data model can communicate back source locations. + */ + +/*! + \fn QXmlNodeModelIndex::NodeKind QAbstractXmlNodeModel::kind(const QXmlNodeModelIndex &ni) const + + Returns a value indicating the kind of node identified by \a ni. + The caller guarantees that \a ni is not null and that it identifies + a node in this node model. This function maps to the \c + dm:node-kind() accessor. + + \sa {http://www.w3.org/TR/xpath-datamodel/#dm-node-kind}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.10 node-kind Accessor} + */ + +/*! + \fn QXmlNodeModelIndex::DocumentOrder QAbstractXmlNodeModel::compareOrder(const QXmlNodeModelIndex &ni1, const QXmlNodeModelIndex &ni2) const + + This function returns the relative document order for the + nodes indexed by \a ni1 and \a ni2. It is used for the \c Is + operator and for sorting nodes in document order. + + The caller guarantees that \a ni1 and \a ni2 are not \c null and + that both identify nodes in this node model. + + If \a ni1 is identical to \a ni2, QXmlNodeModelIndex::Is is returned. + If \a ni1 precedes \a ni2 in document order, QXmlNodeModelIndex::Precedes + is returned. If \a ni1 follows \a ni2 in document order, + QXmlNodeModelIndex::Follows is returned. + + \sa {http://www.w3.org/TR/xpath-datamodel/#document-order}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 2.4 Document Order} + */ + +/*! + \fn QXmlNodeModelIndex QAbstractXmlNodeModel::root(const QXmlNodeModelIndex &n) const + + Returns the root node of the tree that contains the node whose index + is \a n. The caller guarantees that \a n is not \c null and that it + identifies a node in this node model. + + If \a n identifies a node that is a direct child of the root, + parent() would return the same QXmlNodeModelIndex returned by + this function. + */ + +namespace QPatternist +{ + class MergeIterator + { + public: + inline MergeIterator() + { + } + + inline + QXmlNodeModelIndexIteratorPointer + mapToSequence(const QXmlNodeModelIndexIteratorPointer &it, + const DynamicContext::Ptr &) const + { + return it; + } + + private: + Q_DISABLE_COPY(MergeIterator) + }; + + static const MergeIterator mergeIterator; + + /** + * One might wonder, why not use makeVectorIterator() directly on a QVector + * with iterators? + * + * A problem emerges QAbstractXmlForwardIterator::copy(). All "meta + * iterators" that contain other iterators and so forth, propagate the + * copy() call such that all involved iterators are copied. However, if we + * have a ListIterator of iterators it isn't aware of that it contains + * iterators. Hence, we have this class which is specialized(not in the + * template sense) on iterators, and hence copies them appropriately. + */ + class IteratorVector : public ListIterator<QXmlNodeModelIndexIteratorPointer, QVector<QXmlNodeModelIndexIteratorPointer> > + { + typedef QVector<QXmlNodeModelIndexIteratorPointer> ItVector; + public: + typedef QAbstractXmlForwardIterator<QXmlNodeModelIndexIteratorPointer>::Ptr Ptr; + + IteratorVector(const ItVector &in) : ListIterator<QXmlNodeModelIndexIteratorPointer, QVector<QXmlNodeModelIndexIteratorPointer> >(in) + { + } + + virtual QAbstractXmlForwardIterator<QXmlNodeModelIndexIteratorPointer>::Ptr copy() const + { + ItVector result; + + for(int i = 0; i < m_list.count(); ++i) + result.append(m_list.at(i)->copy()); + + return Ptr(new IteratorVector(result)); + } + }; +} + +/*! + \internal + This function is not a private member of QAbstractXmlNodeModel + because it would be messy to forward declare the required types. +*/ +static inline QXmlNodeModelIndexIteratorPointer mergeIterators(const QXmlNodeModelIndex &node, + const QXmlNodeModelIndexIteratorPointer &it2) +{ + QVector<QXmlNodeModelIndexIteratorPointer> iterators; + iterators.append(makeSingletonIterator(node)); + iterators.append(it2); + + return makeSequenceMappingIterator<QXmlNodeModelIndex>(&mergeIterator, + IteratorVector::Ptr(new IteratorVector(iterators)), + DynamicContext::Ptr()); +} + +inline QAbstractXmlForwardIterator<QXmlNodeModelIndex>::Ptr +QAbstractXmlNodeModel::mapToSequence(const QXmlNodeModelIndex &ni, + const DynamicContext::Ptr &) const +{ + Q_ASSERT(!ni.isNull()); + /* Since we pass in this here, mapToSequence is used recursively. */ + return mergeIterators(ni, makeSequenceMappingIterator<QXmlNodeModelIndex>(this, + ni.iterate(QXmlNodeModelIndex::AxisChild), + DynamicContext::Ptr())); +} + +/*! + \fn QVector<QXmlNodeModelIndex> QAbstractXmlNodeModel::attributes(const QXmlNodeModelIndex &element) const + + Returns the attributes of \a element. The caller guarantees + that \a element is an element in this node model. + */ + +/*! + \internal + + Performs navigation, starting from \a ni, by returning an + QAbstractXmlForwardIterator that returns nodes the \a axis emanating + from \a ni. + + The implementation returns the nodes on the \a axis, without + duplicates and in \a axis order. This means that if \a axis is a + reverse axis, which is the case for the \c parent, \c ancestor, \c + ancestor-or-self, \c preceding, and \c preceding-sibling, the nodes + are delivered in reverse document order. Otherwise the nodes are + delivered in document order. + + The implementor guarantees that the nodes delivered for the axes are + consistent with the XPath Data Model. This just implies common + sense, e.g., The child axis for a comment node can't contain any + children; a document node can't be a child of an element, etc. + Attributes aren't considered children of an element, but are only + available on AxisAttribute. + + The value past in \a axis is not guaranteed based on what is used in + a query. QtXmlPatterns may call this function arbitrarily with any + value for \a axis. This is because QtXmlPatterns may rewrite queries + to be more efficient, using axes in different ways from the original + query. + + QAbstractXmlNodeModel::Axis has a good overview of the axes and what + they select. + + The caller guarantees that \a ni is not \c null and that it belongs + to this QAbstractXmlNodeModel instance. + + Implementing iterate() can involve significant work, since it + requires different iterators for all the axes used. In the worst + case, it could require writing as many QAbstractXmlForwardIterator + subclasses as there are axes, but the number can often be reduced + with clever use of lists and template classes. It is better to use + or subclass QSimpleXmlNodeModel, which makes it easier to write the + node navigation code without loss of efficiency or flexibility. + + \sa QSimpleXmlNodeModel + \sa QXmlNodeModelIndex::Axis + \sa {http://www.w3.org/TR/xquery/#axes}{XQuery 1.0: An XML Query Language, 3.2.1.1 Axes} + \sa {http://www.w3.org/TR/xpath-datamodel/}{W3CXQuery 1.0 and XPath 2.0 Data Model (XDM)} + */ +QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > +QAbstractXmlNodeModel::iterate(const QXmlNodeModelIndex &ni, + QXmlNodeModelIndex::Axis axis) const +{ + /* Returns iterators that track state and calls nextFromSimpleAxis() + * iteratively. Typically, when sub-classing QSimpleXmlNodeModel, + * you don't reimplement this function, but instead implement + * nextFromSimpleAxis(). */ + + switch(axis) + { + case QXmlNodeModelIndex::AxisSelf: + return makeSingletonIterator(ni); + case QXmlNodeModelIndex::AxisParent: + { + if(kind(ni) == QXmlNodeModelIndex::Document) + return makeEmptyIterator<QXmlNodeModelIndex>(); + else + return makeSingletonIterator(nextFromSimpleAxis(Parent, ni)); + } + case QXmlNodeModelIndex::AxisNamespace: + return makeEmptyIterator<QXmlNodeModelIndex>(); + case QXmlNodeModelIndex::AxisAncestor: + { + QList<QXmlNodeModelIndex> ancestors; + QXmlNodeModelIndex ancestor = nextFromSimpleAxis(Parent, ni); + + while(!ancestor.isNull()) + { + ancestors.append(ancestor); + ancestor = nextFromSimpleAxis(Parent, ancestor); + } + + return makeListIterator(ancestors); + } + case QXmlNodeModelIndex::AxisAncestorOrSelf: + { + QList<QXmlNodeModelIndex> ancestors; + ancestors.append(ni); + QXmlNodeModelIndex ancestor = nextFromSimpleAxis(Parent, ni); + + while(!ancestor.isNull()) + { + ancestors.append(ancestor); + ancestor = nextFromSimpleAxis(Parent, ancestor); + } + + return makeListIterator(ancestors); + } + case QXmlNodeModelIndex::AxisPrecedingSibling: + { + QList<QXmlNodeModelIndex> preceding; + QXmlNodeModelIndex sibling = nextFromSimpleAxis(PreviousSibling, ni); + + while(!sibling.isNull()) + { + preceding.append(sibling); + sibling = nextFromSimpleAxis(PreviousSibling, sibling); + } + + return makeListIterator(preceding); + } + case QXmlNodeModelIndex::AxisFollowingSibling: + { + QList<QXmlNodeModelIndex> preceding; + QXmlNodeModelIndex sibling = nextFromSimpleAxis(NextSibling, ni); + + while(!sibling.isNull()) + { + preceding.append(sibling); + sibling = nextFromSimpleAxis(NextSibling, sibling); + } + + return makeListIterator(preceding); + } + case QXmlNodeModelIndex::AxisChildOrTop: + { + if(nextFromSimpleAxis(Parent, ni).isNull()) + { + switch(kind(ni)) + { + case QXmlNodeModelIndex::Comment: + /* Fallthrough. */ + case QXmlNodeModelIndex::ProcessingInstruction: + /* Fallthrough. */ + case QXmlNodeModelIndex::Element: + /* Fallthrough. */ + case QXmlNodeModelIndex::Text: + return makeSingletonIterator(ni); + case QXmlNodeModelIndex::Attribute: + /* Fallthrough. */ + case QXmlNodeModelIndex::Document: + /* Fallthrough. */ + case QXmlNodeModelIndex::Namespace: + /* Do nothing. */; + } + } + + /* Else, fallthrough to AxisChild. */ + } + case QXmlNodeModelIndex::AxisChild: + { + QList<QXmlNodeModelIndex> children; + QXmlNodeModelIndex child = nextFromSimpleAxis(FirstChild, ni); + + while(!child.isNull()) + { + children.append(child); + child = nextFromSimpleAxis(NextSibling, child); + } + + return makeListIterator(children); + } + case QXmlNodeModelIndex::AxisDescendant: + { + return makeSequenceMappingIterator<QXmlNodeModelIndex>(this, + ni.iterate(QXmlNodeModelIndex::AxisChild), + DynamicContext::Ptr()); + } + case QXmlNodeModelIndex::AxisAttributeOrTop: + { + if(kind(ni) == QXmlNodeModelIndex::Attribute && nextFromSimpleAxis(Parent, ni).isNull()) + return makeSingletonIterator(ni); + + /* Else, fallthrough to AxisAttribute. */ + } + case QXmlNodeModelIndex::AxisAttribute: + return makeVectorIterator(attributes(ni)); + case QXmlNodeModelIndex::AxisDescendantOrSelf: + return mergeIterators(ni, iterate(ni, QXmlNodeModelIndex::AxisDescendant)); + case QXmlNodeModelIndex::AxisFollowing: + /* Fallthrough. */ + case QXmlNodeModelIndex::AxisPreceding: + { + /* We walk up along the ancestors, and for each parent, we grab its preceding/following + * siblings, and evaluate the descendant axis. The descendant axes gets added + * to a list and we then merge those iterators. */ + QVector<QXmlNodeModelIndexIteratorPointer> descendantIterators; + + QXmlNodeModelIndex current(ni); + while(!current.isNull()) + { + QXmlNodeModelIndex candidate(nextFromSimpleAxis(axis == QXmlNodeModelIndex::AxisPreceding ? PreviousSibling : NextSibling, current)); + if(candidate.isNull()) + { + /* current is an ancestor. We don't want it, so next iteration we + * will grab its preceding sibling. */ + current = nextFromSimpleAxis(Parent, current); + } + else + { + current = candidate; + descendantIterators.append(iterate(current, QXmlNodeModelIndex::AxisDescendantOrSelf)->toReversed()); + } + } + + return makeSequenceMappingIterator<QXmlNodeModelIndex>(&mergeIterator, + IteratorVector::Ptr(new IteratorVector(descendantIterators)), + DynamicContext::Ptr()); + } + } + + Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown axis, internal error."); + return makeEmptyIterator<QXmlNodeModelIndex>(); +} + +/*! + \fn QXmlNodeModelIndex QAbstractXmlNodeModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &origin) const + + When QtXmlPatterns evaluate path expressions, it emulate them through a + combination of calls with QSimpleXmlNodeModel::SimpleAxis values. Therefore, + the implementation of this function must return the node, if any, that + appears on the \a axis emanating from the \a origin. + + If no such node is available, a default constructed + QXmlNodeModelIndex is returned. + + QSimpleXmlNodeModel eliminates the need to handle redundant corner + cases by guaranteeing that it will never ask for: + + \list + \o Children or siblings for attributes. + \o Children for comments, processing instructions, and text nodes. + \o Siblings or parents for document nodes. + \endlist + + A typical implementation performs a \c switch on the value of \a + axis: + + \code + QXmlNodeModelIndex MyTreeModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &origin) const + { + // Convert the QXmlNodeModelIndex to a value that is specific to what we represent. + const MyValue value = toMyValue(ni); + + switch(axis) + { + case Parent: + return toNodeIndex(value.parent()); + case FirstChild: + case PreviousSibling: + case NextSibling: + // and so on + } + } + \endcode + + */ + +/*! + \fn QXmlNodeModelIndex QAbstractXmlNodeModel::createIndex(qint64 data) const + + Creates a node index with \a data as its internal data. \a data is + not constrained. + */ + +/*! + \fn QXmlNodeModelIndex QAbstractXmlNodeModel::createIndex(void *pointer, qint64 additionalData) const + + Creates a node index with \a pointer and \a additionalData as + its internal data. + + What \a pointer and \a additionalData is, is not constrained. + */ + +/*! + \fn QXmlNodeModelIndex QAbstractXmlNodeModel::createIndex(qint64 data, qint64 additionalData) const; + \overload + + Creates a QXmlNodeModelIndex containing \a data and \a + additionalData. + */ + +/*! + \fn QXmlName QAbstractXmlNodeModel::name(const QXmlNodeModelIndex &ni) const + + Returns the name of \a ni. The caller guarantees that \a ni is not + \c null and that it belongs to this QAbstractXmlNodeModel. + + If a node does not have a name, e.g., comment nodes, a null QXmlName + is returned. QXmlNames must be created with the instance of + QXmlQuery that is being used for evaluating queries using this + QAbstractXmlNodeModel. + + This function maps to the \c dm:node-name() accessor. + + If \a ni is a processing instruction, a QXmlName is returned with + the local name as the target name and the namespace URI and prefix + both empty. + + \sa {http://www.w3.org/TR/xpath-datamodel/#dm-node-name}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.11 node-name Accessor} + \sa QXmlName + */ + +/*! + \fn QVector<QXmlName> QAbstractXmlNodeModel::namespaceBindings(const QXmlNodeModelIndex &n) const + + Returns the in-scope namespaces of \a n. The caller guarantees that + \a n is not \c null and that it belongs to this QAbstractXmlNodeModel. + + This function corresponds to the \c dm:namespace-nodes accessor. + + The returned vector of namespace declarations includes namespaces + of the ancestors of \a n. + + The caller guarantees that \a n is an Element that belongs to this + QAbstractXmlNodeModel. + */ + +/*! + \internal + Sends the namespaces declared on \a n to \a receiver. + + As a consequence, no namespaces are sent unless this node is an + element and has namespaces declared. + + The caller guarantees that \a n is not \c null and that it belongs + to this QAbstractXmlNodeModel instance. + + Note that it is not the namespaces that are in scope on \a n, but + only the namespaces that are specifically declared on \a n. + + \a receiver is the receiver that this node is supposed to send its + namespaces to. This is guaranteed by the caller to be a valid + pointer. \a n is the index of the node whose namespaces are to + be sent. + */ +void QAbstractXmlNodeModel::sendNamespaces(const QXmlNodeModelIndex &n, + QAbstractXmlReceiver *const receiver) const +{ + Q_ASSERT(receiver); + const QVector<QXmlName> nss(namespaceBindings(n)); + + /* This is by far the most common case. */ + if(nss.isEmpty()) + return; + + const int len = nss.size(); + for(int i = 0; i < len; ++i) + receiver->namespaceBinding(nss.at(i)); +} + +/*! + \fn QString QAbstractXmlNodeModel::stringValue(const QXmlNodeModelIndex &n) const + + Returns the string value for node \a n. + + The caller guarantees that \a n is not \c null and that it belong to + this QAbstractXmlNodeModel instance. + + This function maps to the \c dm:string-value() accessor, which the + specification completely specifies. Here's a summary: + + \list + + \o For processing instructions, the string value is the data + section(excluding any whitespace appearing between the name and the + data). + + \o For text nodes, the string value equals the text node. + + \o For comments, the content of the comment + + \o For elements, the concatenation of all text nodes that are + descendants. Note, this is not only the children, but the + childrens' childrens' text nodes, and so forth. + + \o For document nodes, the concatenation of all text nodes in the + document. + + \endlist + + \sa {http://www.w3.org/TR/xpath-datamodel/#dm-string-value}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.13 string-value Accessor} + */ + +/*! + \fn QVariant QAbstractXmlNodeModel::typedValue(const QXmlNodeModelIndex &node) const + + Returns the typed value for node \a node. + + The typed value is an atomic value, which an element or attribute + contains. + + The caller guarantees that \a node is either an element or an + attribute. The implementor guarantees that the returned QVariant has + a value which is supported in XQuery. It cannot be an arbitrary + QVariant value. The implementor also guarantees that stringValue() + returns a lexical representation of typedValue()(this is guaranteed + by QSimpleXmlNodeModel::stringValue()). + + If the return QVariant is a default constructed variant, it signals + that \a node has no typed value. +*/ + +/*! + \internal + */ +QPatternist::ItemIteratorPtr QAbstractXmlNodeModel::sequencedTypedValue(const QXmlNodeModelIndex &ni) const +{ + const QVariant &candidate = typedValue(ni); + if(candidate.isNull()) + return QPatternist::CommonValues::emptyIterator; + else + return makeSingletonIterator(AtomicValue::toXDM(candidate)); +} + +/*! + \internal + */ +QPatternist::ItemTypePtr QAbstractXmlNodeModel::type(const QXmlNodeModelIndex &) const +{ + Q_ASSERT_X(false, Q_FUNC_INFO, + "This function is internal and must not be called."); + return QPatternist::ItemTypePtr(); +} + +/*! + \internal + + Returns the namespace URI on \a ni that corresponds to \a prefix. + + If \a prefix is StandardPrefixes::empty, the namespace URI for the + default namespace is returned. + + The default implementation use namespaceBindings(), in a straight + forward manner. + + If no namespace exists for \a prefix, NamespaceResolver::NoBinding + is returned. + + The caller guarantees to only call this function for element nodes. + */ +QXmlName::NamespaceCode QAbstractXmlNodeModel::namespaceForPrefix(const QXmlNodeModelIndex &ni, + const QXmlName::PrefixCode prefix) const +{ + Q_ASSERT(kind(ni) == QXmlNodeModelIndex::Element); + + const QVector<QXmlName> nbs(namespaceBindings(ni)); + const int len = nbs.size(); + + for(int i = 0; i < len; ++i) + { + if(nbs.at(i).prefix() == prefix) + return nbs.at(i).namespaceURI(); + } + + return NamespaceResolver::NoBinding; +} + + +/*! + \internal + + Determines whether \a ni1 is deep equal to \a ni2. + + isDeepEqual() is defined as evaluating the expression \c + fn:deep-equal($n1, $n2) where \c $n1 is \a ni1 and \c $n1 is \a + ni2. This function is associative, meaning the same value is + returned regardless of if isDeepEqual() is invoked with \a ni1 as + first argument or second. It is guaranteed that \a ni1 and \a ni2 + are nodes, as opposed to the definition of \c fn:deep-equal(). + + Returns true if \a ni1 is deep-equal to \a ni2, otherwise false + + \sa {"http://www.w3.org/TR/xpath-functions/#func-deep-equal"}{XQuery 1.0 and XPath 2.0 Functions and Operators, 15.3.1 fn:deep-equal} + */ +bool QAbstractXmlNodeModel::isDeepEqual(const QXmlNodeModelIndex &n1, + const QXmlNodeModelIndex &n2) const +{ + Q_ASSERT(!n1.isNull()); + Q_ASSERT(!n2.isNull()); + + const QXmlNodeModelIndex::NodeKind nk = n1.kind(); + + if(nk != n2.kind()) + return false; + + if(n1.name() != n2.name()) + return false; + + switch(nk) + { + case QXmlNodeModelIndex::Element: + { + QXmlNodeModelIndexIteratorPointer atts1(n1.iterate(QXmlNodeModelIndex::AxisAttribute)); + QXmlNodeModelIndex node(atts1->next()); + + const QXmlNodeModelIndex::List atts2(n2.iterate(QXmlNodeModelIndex::AxisAttribute)->toList()); + const QXmlNodeModelIndex::List::const_iterator end(atts2.constEnd()); + + while(!node.isNull()) + { + bool equal = false; + for(QXmlNodeModelIndex::List::const_iterator it = atts2.constBegin(); it != end; ++it) + { + if(isDeepEqual(node, (*it))) + equal = true; + } + + if(!equal) + return false; + + node = atts1->next(); + } + + /* Fallthrough, so we check the children. */ + } + case QXmlNodeModelIndex::Document: + { + QXmlNodeModelIndexIteratorPointer itn1(n1.iterate(QXmlNodeModelIndex::AxisChild)); + QXmlNodeModelIndexIteratorPointer itn2(n2.iterate(QXmlNodeModelIndex::AxisChild)); + + while(true) + { + QXmlNodeModelIndex no1(itn1->next()); + QXmlNodeModelIndex no2(itn2->next()); + + while(!no1.isNull() && isIgnorableInDeepEqual(no1)) + no1 = itn1->next(); + + while(!no2.isNull() && isIgnorableInDeepEqual(no2)) + no2 = itn2->next(); + + if(!no1.isNull() && !no2.isNull()) + { + if(!isDeepEqual(no1, no2)) + return false; + } + else + return no1.isNull() && no2.isNull(); + } + + return true; + } + case QXmlNodeModelIndex::Attribute: + /* Fallthrough */ + case QXmlNodeModelIndex::ProcessingInstruction: + /* Fallthrough. */ + case QXmlNodeModelIndex::Text: + /* Fallthrough. */ + case QXmlNodeModelIndex::Comment: + return n1.stringValue() == n2.stringValue(); + case QXmlNodeModelIndex::Namespace: + { + Q_ASSERT_X(false, Q_FUNC_INFO, "Not implemented"); + return false; + } + } + + return false; +} + +/*! + \class QXmlItem + \reentrant + \since 4.4 + \brief The QXmlItem class contains either an XML node or an atomic value. + \ingroup xml-tools + + In XQuery, all expressions evaluate to a sequence of items, where + each item is either an XML node or an atomic value. The query in the + following snippet evaluates to sequence of five items. + + \quotefile doc/src/snippets/patternist/items.xq + + The five items are: An element, an atomic value (binary data encoded + in base64), a date, a float, and an attribute. + + QXmlItem is the class that represents these XQuery items in the + QtXmlPatterns API. A non-null instance of QXmlItem is either a node + or an atomic value. Calling isNode() or isAtomicValue() tells you + which it is. Atomic values are represented elsewhere in the Qt API + as instances of QVariant, and an instance of QXmlItem that + represents an atomic value can be converted to a QVariant by calling + toAtomicValue(). A QXmlItem that wraps a node is represented + elsewhere as an instance of QXmlNodeModelIndex. A node QXmlItem can + be converted to a QXmlNodeModelIndex by calling toNodeModelIndex(). + + A default constructed QXmlItem instance is neither a node nor an + atomic value. It is considered null, in which case isNull() returns + true. + + An instance of QXmlItem will be left dangling if the + \l{QAbstractXmlNodeModel} {XML node model} it + refers to is deleted, if it is a QXmlNodeModelIndex. + */ + +/*! + \typedef QXmlItem::Iterator + A QAbstractXmlForwardIterator over QXmlItem. + */ + +/*! + Constructs a null QXmlItem that is neither a node nor an atomic + value. isNull() returns true for a default constructed instance. + */ +QXmlItem::QXmlItem() +{ + m_node.model = 0; + m_node.data = 0; + m_node.additionalData = 0; +} + +bool QXmlItem::internalIsAtomicValue() const +{ + return m_node.model == reinterpret_cast<QAbstractXmlNodeModel *>(~0); +} + +/*! + The copy constructor constructs a copy of \a other. + */ +QXmlItem::QXmlItem(const QXmlItem &other) : m_node(other.m_node) +{ + if(internalIsAtomicValue()) + m_atomicValue->ref.ref(); +} + +/*! + Constructs an atomic value QXmlItem with \a atomicValue. + + \sa isAtomicValue() + */ +QXmlItem::QXmlItem(const QVariant &atomicValue) +{ + if(atomicValue.isNull()) + { + /* Then we behave just like the default constructor. */ + m_node.model = 0; + m_node.data = 0; + m_node.additionalData = 0; + return; + } + + /* + We can't assign directly to m_atomicValue, because the + temporary will self-destruct before we've ref'd it. + */ + const QPatternist::Item temp(QPatternist::AtomicValue::toXDM(atomicValue)); + + if(temp) + { + temp.asAtomicValue()->ref.ref(); + m_node.model = reinterpret_cast<const QAbstractXmlNodeModel *>(~0); + m_atomicValue = temp.asAtomicValue(); + } + else + { + m_atomicValue = 0; + m_node.model = 0; + } + + m_node.additionalData = 0; +} + +/*! + Constructs a node QXmlItem that is a copy of \a node. + + \sa isNode() + */ +QXmlItem::QXmlItem(const QXmlNodeModelIndex &node) : m_node(node.m_storage) +{ +} + + +/*! + Destructor. + */ +QXmlItem::~QXmlItem() +{ + if(internalIsAtomicValue() && !m_atomicValue->ref.deref()) + delete m_atomicValue; +} + +bool QPatternist::NodeIndexStorage::operator!=(const NodeIndexStorage &other) const +{ + return data != other.data + || additionalData != other.additionalData + || model != other.model; +} + +/*! + Assigns \a other to \c this. + */ +QXmlItem &QXmlItem::operator=(const QXmlItem &other) +{ + if(m_node != other.m_node) + { + if(internalIsAtomicValue() && !m_atomicValue->ref.deref()) + delete m_atomicValue; + + m_node = other.m_node; + + if(internalIsAtomicValue()) + m_atomicValue->ref.ref(); + } + + return *this; +} + +/*! + Returns true if this item is a Node. Returns false if it + is an atomic value or null. + + \sa isNull(), isAtomicValue() + */ +bool QXmlItem::isNode() const +{ + return QPatternist::Item::fromPublic(*this).isNode(); +} + +/*! + Returns true if this item is an atomic value. Returns false + if it is a node or null. + + \sa isNull(), isNode() + */ +bool QXmlItem::isAtomicValue() const +{ + return internalIsAtomicValue(); +} + +/*! + If this QXmlItem represents an atomic value, it is converted + to an appropriate QVariant and returned. If this QXmlItem is + not an atomic value, the return value is a default constructed + QVariant. You can call isAtomicValue() to test whether the + item is an atomic value. + + \sa isAtomicValue() + */ +QVariant QXmlItem::toAtomicValue() const +{ + if(isAtomicValue()) + return QPatternist::AtomicValue::toQt(m_atomicValue); + else + return QVariant(); +} + +/*! + If this QXmlItem represents a node, it returns the item as a + QXmlNodeModelIndex. If this QXmlItem is not a node, the return + value is undefined. You can call isNode() to test whether the + item is a node. + + \sa isNode() + */ +QXmlNodeModelIndex QXmlItem::toNodeModelIndex() const +{ + if(isNode()) + return reinterpret_cast<const QXmlNodeModelIndex &>(m_node); + else + return QXmlNodeModelIndex(); +} + +/*! + Returns true if this QXmlItem is neither a node nor an + atomic value. Default constructed instances of QXmlItem + are null. + */ +bool QXmlItem::isNull() const +{ + return !m_node.model; +} + +/*! + \class QXmlNodeModelIndex + \brief The QXmlNodeModelIndex class identifies a node in an XML node model subclassed from QAbstractXmlNodeModel. + \reentrant + \since 4.4 + \ingroup xml-tools + + QXmlNodeModelIndex is an index into an \l{QAbstractXmlNodeModel} + {XML node model}. It contains: + + \list + \o A pointer to an \l{QAbstractXmlNodeModel} {XML node model}, + which is returned by model(), and + \o Some data, which is returned by data(), internalPointer(), + and additionalData(). + \endlist + + Because QXmlNodeModelIndex is intentionally a simple class, it + doesn't have member functions for accessing the properties of + nodes. For example, it doesn't have functions for getting a + node's name or its list of attributes or child nodes. If you find + that you need to retrieve this kind of information from your + query results, there are two ways to proceed. + + \list + + \o Send the output of your XQuery to an \l{QAbstractXmlReceiver} + {XML receiver}, or + + \o Let your XQuery do all the work to produce the desired result. + + \endlist + + The second case is explained by example. Suppose you want to + populate a list widget with the values of certain attributes from a + set of result elements. You could write an XQuery to return the set + of elements, and then you would write the code to iterate over the + result elements, get their attributes, and extract the desired + string values. But the simpler way is to just augment your XQuery to + finding the desired attribute values. Then all you have to do is + evaluate the XQuery using the version of QXmlQuery::evaluateTo() + that populates a QStringList, which you can send directly to your + widget. + + QXmlNodeModelIndex doesn't impose any restrictions on the \c data + value an QXmlNodeModelIndex should contain. The meaning of the data + left to the associated \l {QAbstractXmlNodeModel} {node model}. + Because QXmlNodeModelIndex depends on a particular subclass of + QAbstractXmlNodeModel for its existence, the only way you can create + an instance of QXmlNodeModelIndex is by asking the node model to + create one for you with QAbstractXmlNodeModel::createIndex(). Since + that function is protected, it is usually a good idea to write a + public function that creates a QXmlNodeModelIndex from arguments that + are appropriate for your particular node model. + + A default constructed node index is said to be null, i.e., isNull() + returns true. + + QXmlNodeModelIndex and QAbstractXmlNodeModel follow the same design + pattern used for QModelIndex and QAbstractItemModel. + */ + +/*! + \since 4.4 + \relates QHash + + Computes a hash key from the QXmlNodeModelIndex \a index, and + returns it. This function would be used by QHash if you wanted + to build a hash table for instances of QXmlNodeModelIndex. + + The hash is computed on QXmlNodeModelIndex::data(), + QXmlNodeModelIndex::additionalData(), and + QXmlNodeModelIndex::model(). This means the hash key can be used for + node indexes from different node models. + */ +uint qHash(const QXmlNodeModelIndex &index) +{ + return uint(index.data() + index.additionalData() + quintptr(index.model())); +} + +/*! + \enum QXmlNodeModelIndex::NodeKind + + Identifies a kind of node. + + \value Attribute Identifies an attribute node + \value Text Identifies a text node + \value Comment Identifies a comment node + \value Document Identifies a document node + \value Element Identifies an element node + \value Namespace Identifies a namespace node + \value ProcessingInstruction Identifies a processing instruction. + + Note that the optional XML declaration at very beginning of the XML + document is not a processing instruction + + \sa QAbstractXmlNodeModel::kind() +*/ + +/*! + \typedef QXmlNodeModelIndex::List + + Typedef for QList<QXmlNodeModelIndex>. + */ + +/*! + Returns true if this node is the same as \a other. This operator + does not compare values, children, or names of nodes. It compares + node identities, i.e., whether two nodes are from the same document + and are found at the exact same place. + */ +bool QXmlNodeModelIndex::operator==(const QXmlNodeModelIndex &other) const +{ + return !(m_storage != other.m_storage); +} + +/*! + Returns true if \a other is the same node as this. + */ +bool QXmlNodeModelIndex::operator!=(const QXmlNodeModelIndex &other) const +{ + return !(operator==(other)); +} + +/*! + \fn QXmlNodeModelIndex::QXmlNodeModelIndex() + + Default constructor. Creates an item that is \c null. + + \sa isNull() + */ + +/*! + \fn QXmlNodeModelIndex::QXmlNodeModelIndex(const QXmlNodeModelIndex &other) + + Standard copy constructor. Creates a QXmlNodeModelIndex instance that + is a copy of \a other. + */ + +/*! + \fn bool QXmlNodeModelIndex::isNull() const + + Returns true if this QXmlNodeModelIndex is a default constructed + value, otherwise false. + + A null QXmlNodeModelIndex doesn't represent any node and cannot + be used in conjunction with QAbstractXmlNodeModel. + */ + +/*! + \fn const QAbstractXmlNodeModel *QXmlNodeModelIndex::model() const + + Returns the QAbstractXmlNodeModel that this node index refers to. + QXmlNodeModelIndex does not own QAbstractXmlNodeModel and does not + keep track of its lifetime, so this pointer will dangle if the + QAbstractXmlNodeModel is deallocated first. + + There is no setter for the node model because instances of + QXmlNodeModelIndex instances are only created with + QAbstractXmlNodeModel::createIndex(). +*/ + +/*! + \fn qint64 QXmlNodeModelIndex::data() const + + Returns the first data value. The node index holds two data values. + additionalData() returns the second one. + + \sa additionalData() +*/ + +/*! + \fn void *QXmlNodeModelIndex::internalPointer() const + + Returns the first data value as a void* pointer. + + \sa additionalData() +*/ + +/*! + \fn qint64 QXmlNodeModelIndex::additionalData() const + + Returns the second data value. The node index holds two data values. + data() returns the first one. + + \sa data() +*/ + +/*! + \fn void QXmlNodeModelIndex::reset() + \internal + + Resets this QXmlNodeModelIndex to be null. It is equivalent to + writing: + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qabstractxmlnodemodel.cpp 0 + */ + +/*! + \fn QXmlName QXmlNodeModelIndex::name() const + \internal +*/ + +/*! + \typedef QXmlNodeModelIndex::Iterator + \internal + + Typedef for QAbstractXmlForwardIterator<QXmlNodeModelIndex>. + */ +/*! + \fn QXmlNodeModelIndex QXmlNodeModelIndex::root() const + \internal +*/ + +/*! + \fn QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > QXmlNodeModelIndex::iterate(const Axis axis) const + \internal +*/ + +/*! + \fn QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QPatternist::Item> > QXmlNodeModelIndex::sequencedTypedValue() const + \internal +*/ + +/*! + \fn QUrl QXmlNodeModelIndex::documentUri() const + \internal +*/ + +/*! + \fn QUrl QXmlNodeModelIndex::baseUri() const + \internal +*/ + +/*! + \fn NodeKind QXmlNodeModelIndex::kind() const + \internal +*/ + +/*! + \fn bool QXmlNodeModelIndex::isDeepEqual(const QXmlNodeModelIndex &other) const + \internal +*/ + +/*! + \fn DocumentOrder QXmlNodeModelIndex::compareOrder(const QXmlNodeModelIndex &other) const + \internal +*/ + +/*! + \fn void QXmlNodeModelIndex::sendNamespaces(QAbstractXmlReceiver *const receiver) const + \internal +*/ + +/*! + \fn QVector<QXmlName> QXmlNodeModelIndex::namespaceBindings() const + \internal +*/ + +/*! + \fn QXmlNodeModelIndex QAbstractXmlNodeModel::elementById(const QXmlName &id) const + + Returns the index of the element identified as \a id. XQuery's \c + id() function calls this function. + + The node index returned will be the element node whose value is of + type \c ID and equals \a id, or it will be the element node that has + an attribute whose typed value is of type \c ID and equals \a id. If + there is no such element, a default constructed QXmlNodeModelIndex + instance is returned. The implementor guarantees that if the returned + node index is not null, it identifies an element. + + It is not sufficient for an attribute or element to merely be called + \c id. Its value type must also be \c ID. However, the reserved name + \c xml:id is sufficient. + + In \a id, the \c{namespace URI} and the \c{prefix} are undefined, and + the \c{local name} is the ID that should be looked up. + + \sa {http://www.w3.org/TR/xpath-functions/#func-id}{XQuery 1.0 and XPath 2.0 Functions and Operators, 15.5.2 fn:id} + */ + +/*! + \fn QVector<QXmlNodeModelIndex> QAbstractXmlNodeModel::nodesByIdref(const QXmlName &idref) const + + Returns the elements and/or attributes that have an \c IDREF value + equal to \a idref. XQuery's \c idref() function calls this function. + + The implementor guarantees that the nodes identified by the returned + indexes are elements or attributes. + + It is not sufficient for an attribute or element to merely be called + \c idref. It must also be of type \c IDREF. Elements must be typed as + \c xs:IDREF or \c xs:IDREFS, or, in the case of attributes, as \c + IDREF or \c IDREFS in the schema. + + In \a idref, the \c{namespace URI} and the \c{prefix} are undefined, + and the \c{local name} is the ID that should be looked up. + + \sa {http://www.w3.org/TR/xpath-functions/#func-idref}{XQuery 1.0 and XPath 2.0 Functions and Operators, 15.5.3 fn:idref} + */ + +/*! + \fn QXmlName::NamespaceCode QXmlNodeModelIndex::namespaceForPrefix(const QXmlName::PrefixCode prefix) const + \internal +*/ + +/*! + \fn QString QXmlNodeModelIndex::stringValue() const + \internal +*/ + +/*! + \fn QPatternist::ItemTypePtr QXmlNodeModelIndex::type() const + \internal +*/ + +/*! + \fn bool QXmlNodeModelIndex::is(const QXmlNodeModelIndex &other) const + \internal +*/ + +/*! + \enum QAbstractXmlNodeModel::NodeCopySetting + \internal + + Controls how nodes are copied with copyNodeTo. + + \value InheritNamespaces Copies the node with the \c copy-namespaces + setting being \c inherit. If not set, \c no-inherit is assumed. + \value PreserveNamespaces Copies the node with the \c copy-namespaces + settings being \c preserve. If not set, \c no-preserve is assumed. + */ + +/*! + \typedef QAbstractXmlNodeModel::NodeCopySettings + \internal + */ + +/*! + \internal + + Copies node \a node to \a receiver, steered by \a copySettings. + + The caller guarantees that \a node is not \c null, and that is + belongs to this QAbstractXmlNodeModel instance. + + The caller guarantees that \a receiver is not \c null. +*/ +void QAbstractXmlNodeModel::copyNodeTo(const QXmlNodeModelIndex &node, + QAbstractXmlReceiver *const receiver, + const NodeCopySettings ©Settings) const +{ + Q_UNUSED(node); + Q_UNUSED(receiver); + Q_UNUSED(copySettings); + Q_ASSERT_X(false, Q_FUNC_INFO, + "This function is not expected to be called."); +} + +/*! + Returns the source location for the object with the given \a index + or a default constructed QSourceLocation in case no location + information is available. + + \since 4.6 +*/ +QSourceLocation QAbstractXmlNodeModel::sourceLocation(const QXmlNodeModelIndex &index) const +{ + // TODO: make this method virtual in Qt5 to allow source location support in custom models + if (d_ptr) + return d_ptr->sourceLocation(index); + else + return QSourceLocation(); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qabstractxmlnodemodel.h b/src/xmlpatterns/api/qabstractxmlnodemodel.h new file mode 100644 index 0000000..808e752 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlnodemodel.h @@ -0,0 +1,429 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTXMLNODEMODEL_H +#define QABSTRACTXMLNODEMODEL_H + +#include <QtXmlPatterns/QXmlName> +#include <QtCore/QSharedData> +#include <QtCore/QScopedPointer> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +/* This file contains the classes QXmlNodeModelIndex, QAbstractXmlNodeModel, + * QXmlItem and QPatternist::NodeIndexStorage. */ + +class QAbstractXmlNodeModel; +class QAbstractXmlNodeModelPrivate; +class QAbstractXmlReceiver; +class QSourceLocation; +class QUrl; +class QXmlName; +class QXmlNodeModelIndex; +template<typename T> class QAbstractXmlForwardIterator; +template<typename T> class QVector; + +/* The members in the namespace QPatternist are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ +namespace QPatternist +{ + class DynamicContext; + class Item; + class ItemType; + class XsdValidatedXmlNodeModel; + template<typename TResult, typename TSource, typename TMapper, typename Context> class ItemMappingIterator; + template<typename TResult, typename TSource, typename TMapper> class SequenceMappingIterator; + typedef QExplicitlySharedDataPointer<ItemType> ItemTypePtr; + typedef QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<Item> > ItemIteratorPtr; + typedef QVector<QXmlName> QXmlNameVector; + + class NodeIndexStorage + { + public: + typedef qint64 Data; + + /*! + \note Changing merely the order of these two members, ptr and data, + is a binary incompatible change on Mac Power PC. + */ + union + { + void *ptr; // Do not use ptr directy, use pointer() instead. + Data data; + }; + void *pointer() const + { + /* Constructing to qptrdiff means we avoid the warning "cast to pointer + * from integer of different size." + */ + return (void *)qptrdiff(data); + } + + Data additionalData; + const QAbstractXmlNodeModel *model; + + /* Implementation is in qabstractxmlnodemodel.cpp. */ + inline bool operator!=(const NodeIndexStorage &other) const; + }; +} + +class Q_XMLPATTERNS_EXPORT QXmlNodeModelIndex +{ + enum Constants + { + ForwardAxis = 8192, + ReverseAxis = 16384 + }; + +public: + inline QXmlNodeModelIndex() + { + reset(); + } + + inline QXmlNodeModelIndex(const QXmlNodeModelIndex &other) : m_storage(other.m_storage) + { + } + + bool operator==(const QXmlNodeModelIndex &other) const; + bool operator!=(const QXmlNodeModelIndex &other) const; + + typedef QAbstractXmlForwardIterator<QXmlNodeModelIndex> Iterator; + typedef QList<QXmlNodeModelIndex> List; + + enum NodeKind + { + Attribute = 1, + Comment = 2, + Document = 4, + Element = 8, + Namespace = 16, + ProcessingInstruction = 32, + Text = 64 + }; + + enum DocumentOrder + { + Precedes = -1, + Is = 0, + Follows = 1 + }; + + enum Axis + { + AxisChild = 1 | ForwardAxis, + AxisDescendant = 2 | ForwardAxis, + AxisAttribute = 4 | ForwardAxis, + AxisSelf = 8 | ForwardAxis, + AxisDescendantOrSelf = 16 | ForwardAxis, + AxisFollowingSibling = 32 | ForwardAxis, + AxisNamespace = 64 | ForwardAxis, + AxisFollowing = 128 | ReverseAxis, + AxisParent = 256 | ReverseAxis, + AxisAncestor = 512 | ReverseAxis, + AxisPrecedingSibling = 1024 | ReverseAxis, + AxisPreceding = 2048 | ReverseAxis, + AxisAncestorOrSelf = 4096 | ReverseAxis, + /* Note that we cannot clash with the values of ForwardAxis and + * ReverseAxis. */ + AxisChildOrTop = 32768 | ForwardAxis, + AxisAttributeOrTop = 65536 | ForwardAxis + }; + + inline qint64 data() const + { + return m_storage.data; + } + + inline void *internalPointer() const + { + return m_storage.pointer(); + } + + inline const QAbstractXmlNodeModel *model() const + { + return m_storage.model; + } + + inline qint64 additionalData() const + { + return m_storage.additionalData; + } + + inline bool isNull() const + { + return !m_storage.model; + } + + /* The members below are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ + + inline QXmlName name() const; + inline QXmlNodeModelIndex root() const; + inline QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > iterate(const Axis axis) const; + inline QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QPatternist::Item> > sequencedTypedValue() const; + inline QUrl documentUri() const; + inline QUrl baseUri() const; + inline NodeKind kind() const; + inline bool isDeepEqual(const QXmlNodeModelIndex &other) const; + inline DocumentOrder compareOrder(const QXmlNodeModelIndex &other) const; + inline void sendNamespaces(QAbstractXmlReceiver *const receiver) const; + inline QVector<QXmlName> namespaceBindings() const; + inline QXmlName::NamespaceCode namespaceForPrefix(const QXmlName::PrefixCode prefix) const; + inline QString stringValue() const; + inline QPatternist::ItemTypePtr type() const; + inline bool is(const QXmlNodeModelIndex &other) const; + + inline void reset() + { + m_storage.data = 0; + m_storage.additionalData = 0; + m_storage.model = 0; + } + +private: + static inline QXmlNodeModelIndex create(const qint64 d, + const QAbstractXmlNodeModel *const nm) + { + QXmlNodeModelIndex n; + n.m_storage.data = d; + n.m_storage.model = nm; + n.m_storage.additionalData = 0; + return n; + } + + static inline QXmlNodeModelIndex create(const qint64 data, + const QAbstractXmlNodeModel *const nm, + const qint64 addData) + { + QXmlNodeModelIndex n; + n.m_storage.data = data; + n.m_storage.model = nm; + n.m_storage.additionalData = addData; + return n; + } + + inline QXmlNodeModelIndex(const QPatternist::NodeIndexStorage &storage) : m_storage(storage) + { + } + + friend class QAbstractXmlNodeModel; + friend class QPatternist::Item; + friend class QXmlItem; + inline operator int() const; // Disable + + QPatternist::NodeIndexStorage m_storage; +}; + +Q_XMLPATTERNS_EXPORT uint qHash(const QXmlNodeModelIndex &index); + +inline bool qIsForwardIteratorEnd(const QXmlNodeModelIndex &item) +{ + return item.isNull(); +} + +class Q_XMLPATTERNS_EXPORT QAbstractXmlNodeModel : public QSharedData +{ +public: + enum SimpleAxis + { + Parent, + FirstChild, + PreviousSibling, + NextSibling + }; + + typedef QExplicitlySharedDataPointer<QAbstractXmlNodeModel> Ptr; + typedef QList<Ptr> List; + + QAbstractXmlNodeModel(); + virtual ~QAbstractXmlNodeModel(); + + virtual QUrl baseUri(const QXmlNodeModelIndex &ni) const = 0; + virtual QUrl documentUri(const QXmlNodeModelIndex &ni) const = 0; + virtual QXmlNodeModelIndex::NodeKind kind(const QXmlNodeModelIndex &ni) const = 0; + virtual QXmlNodeModelIndex::DocumentOrder compareOrder(const QXmlNodeModelIndex &ni1, + const QXmlNodeModelIndex &ni2) const = 0; + virtual QXmlNodeModelIndex root(const QXmlNodeModelIndex &n) const = 0; + virtual QXmlName name(const QXmlNodeModelIndex &ni) const = 0; + virtual QString stringValue(const QXmlNodeModelIndex &n) const = 0; + virtual QVariant typedValue(const QXmlNodeModelIndex &n) const = 0; + + /* The members below are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ + virtual QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > iterate(const QXmlNodeModelIndex &ni, QXmlNodeModelIndex::Axis axis) const; + virtual QPatternist::ItemIteratorPtr sequencedTypedValue(const QXmlNodeModelIndex &ni) const; + virtual QPatternist::ItemTypePtr type(const QXmlNodeModelIndex &ni) const; + virtual QXmlName::NamespaceCode namespaceForPrefix(const QXmlNodeModelIndex &ni, + const QXmlName::PrefixCode prefix) const; + virtual bool isDeepEqual(const QXmlNodeModelIndex &ni1, + const QXmlNodeModelIndex &ni2) const; + virtual void sendNamespaces(const QXmlNodeModelIndex &n, + QAbstractXmlReceiver *const receiver) const; + virtual QVector<QXmlName> namespaceBindings(const QXmlNodeModelIndex &n) const = 0; + + + virtual QXmlNodeModelIndex elementById(const QXmlName &NCName) const = 0; + virtual QVector<QXmlNodeModelIndex> nodesByIdref(const QXmlName &NCName) const = 0; + + enum NodeCopySetting + { + InheritNamespaces = 0x1, + PreserveNamespaces = 0x2 + }; + + typedef QFlags<NodeCopySetting> NodeCopySettings; + virtual void copyNodeTo(const QXmlNodeModelIndex &node, + QAbstractXmlReceiver *const receiver, + const NodeCopySettings &) const; + + QSourceLocation sourceLocation(const QXmlNodeModelIndex &index) const; + +protected: + + virtual QXmlNodeModelIndex nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &origin) const = 0; + virtual QVector<QXmlNodeModelIndex> attributes(const QXmlNodeModelIndex &element) const = 0; + + QAbstractXmlNodeModel(QAbstractXmlNodeModelPrivate *d); + + inline QXmlNodeModelIndex createIndex(qint64 data) const + { + return QXmlNodeModelIndex::create(data, this); + } + + inline QXmlNodeModelIndex createIndex(void * pointer, + qint64 additionalData = 0) const + { + return QXmlNodeModelIndex::create(qptrdiff(pointer), this, additionalData); + } + + inline QXmlNodeModelIndex createIndex(qint64 data, + qint64 additionalData) const + { + return QXmlNodeModelIndex::create(data, this, additionalData); + } + + QScopedPointer<QAbstractXmlNodeModelPrivate> d_ptr; +private: + friend class QPatternist::ItemMappingIterator<QXmlNodeModelIndex, QXmlNodeModelIndex, const QAbstractXmlNodeModel *, QExplicitlySharedDataPointer<QPatternist::DynamicContext> >; + friend class QPatternist::SequenceMappingIterator<QXmlNodeModelIndex, QXmlNodeModelIndex, const QAbstractXmlNodeModel *>; + friend class QPatternist::XsdValidatedXmlNodeModel; + + inline QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > mapToSequence(const QXmlNodeModelIndex &ni, + const QExplicitlySharedDataPointer<QPatternist::DynamicContext> &) const; + + static inline bool isIgnorableInDeepEqual(const QXmlNodeModelIndex &n); + Q_DISABLE_COPY(QAbstractXmlNodeModel) +}; + +Q_DECLARE_TYPEINFO(QXmlNodeModelIndex, Q_MOVABLE_TYPE); + +template<typename T> class QAbstractXmlForwardIterator; +class QVariant; +class QXmlItemPrivate; + +namespace QPatternist +{ + class AtomicValue; + class VariableLoader; + class IteratorBridge; + class ToQXmlItemMapper; + class ToItemMapper; +} + +class Q_XMLPATTERNS_EXPORT QXmlItem +{ +public: + typedef QAbstractXmlForwardIterator<QXmlItem> Iterator; + + QXmlItem(); + QXmlItem(const QXmlItem &other); + QXmlItem(const QXmlNodeModelIndex &node); + QXmlItem(const QVariant &atomicValue); + ~QXmlItem(); + QXmlItem &operator=(const QXmlItem &other); + + bool isNull() const; + bool isNode() const; + bool isAtomicValue() const; + + QVariant toAtomicValue() const; + QXmlNodeModelIndex toNodeModelIndex() const; + +private: + friend class QPatternist::IteratorBridge; + friend class QPatternist::VariableLoader; + friend class QPatternist::ToQXmlItemMapper; + friend class QPatternist::ToItemMapper; + friend class QPatternist::Item; + + inline bool internalIsAtomicValue() const; + + inline QXmlItem(const QPatternist::Item &i); + + union + { + QPatternist::NodeIndexStorage m_node; + + /* These two sits at the position of NodeIndexStorage::data. + * NodeIndexStorage::{additionalData,model} are free. */ + const QPatternist::AtomicValue *m_atomicValue; + QXmlItemPrivate * m_ptr; /* Not currently used. */ + }; +}; + +inline bool qIsForwardIteratorEnd(const QXmlItem &item) +{ + return item.isNull(); +} + +Q_DECLARE_TYPEINFO(QXmlItem, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QXmlItem) /* This macro must appear after QT_END_NAMESPACE. */ + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qabstractxmlnodemodel_p.h b/src/xmlpatterns/api/qabstractxmlnodemodel_p.h new file mode 100644 index 0000000..d4c2060 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlnodemodel_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QABSTRACTXMLNODEMODEL_P_H +#define QABSTRACTXMLNODEMODEL_P_H + +#include "qabstractxmlnodemodel.h" +#include "qsourcelocation.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAbstractXmlNodeModelPrivate +{ +public: + virtual ~QAbstractXmlNodeModelPrivate() + { + } + + virtual QSourceLocation sourceLocation(const QXmlNodeModelIndex &index) const + { + Q_UNUSED(index); + + return QSourceLocation(); + } +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qabstractxmlpullprovider.cpp b/src/xmlpatterns/api/qabstractxmlpullprovider.cpp new file mode 100644 index 0000000..6dbd50b --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlpullprovider.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QHash> + +#include "qxmlname.h" +#include "qnamepool_p.h" +#include "qabstractxmlpullprovider_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +// TODO have example where query selects, and the events for the result are indented + +/*! + \internal + \class AbstractXmlPullProvider + \brief The AbstractXmlPullProvider class provides a pull-based stream interface for the XPath Data Model. + \reentrant + \ingroup xml-tools + + AbstractXmlPullProvider allows a stream of items from the XPath Data Model -- essentially XML -- + to be iterated over. The subclass of AbstractXmlPullProvider provides the events, and the + user calling next() and so on, consumes them. AbstractXmlPullProvider can be considered + a forward-only, non-reversible iterator. + + Note that the content the events describes, are not necessarily a well-formed XML document, but + rather an instance of the XPath Data model, to be specific. For instance, maybe a pull provider + returns two atomic values, followed by an element tree, and at the end two document nodes. + + If you are subclassing AbstractXmlPullProvider, be careful to correctly implement + the behaviors, as described for the individual members and events. + + \sa AbstractXmlPullProvider::Event + */ + +/*! + \enum AbstractXmlPullProvider::Event + \value StartOfInput The value AbstractXmlPullProvider::current() returns before the first call to next(). + \value AtomicValue an atomic value such as an \c xs:integer, \c xs:hexBinary, or \c xs:dateTime. Atomic values + can only be top level items. + \value StartDocument Signals the start of a document node. Note that a AbstractXmlPullProvider can provide + a sequence of document nodes. + \value EndDocument Signals the end of a document node. StartDocument and EndDocument are always balanced + and always top-level events. For instance, StartDocument can never appear after any StartElement + events that hasn't been balanced by the corresponding amount of EndElement events. + \value StartElement Signals an element start tag. + \value EndElement Signals the end of an element. StartElement and EndElement events are always balanced. + \value Text Signals a text node. Adjacent text nodes cannot occur. + \value ProcessingInstruction A processing instruction. Its name is returned from name(), and its value in stringValue(). + \value Comment a comment node. Its value can be retrieved with stingValue(). + \value Attribute Signals an attribute node. Attribute events can only appear after Namespace events, or + if no such are sent, after the StartElement. In addition they must appear sequentially, + and each name must be unique. The ordering of attribute events is undefined and insignificant. + \value Namespace Signals a namespace binding. They occur very infrequently and are not needed for attributes + and elements. Namespace events can only appear after the StartElement event. The + ordering of namespace events is undefined and insignificant. + \value EndOfInput When next() is called after the last event, EndOfInput is returned. + + \sa AbstractXmlPullProvider::current() + */ + +/*! + Constucts a AbstractXmlPullProvider instance. + */ +AbstractXmlPullProvider::AbstractXmlPullProvider() +{ +} + +/*! + Destructs this AbstractXmlPullProvider. + */ +AbstractXmlPullProvider::~AbstractXmlPullProvider() +{ +} + +/*! + \fn Event AbstractXmlPullProvider::next() = 0; + Advances this AbstractXmlPullProvider, and returns the new event. + + \sa current() + */ + +/*! + \fn Event AbstractXmlPullProvider::current() const = 0; + Returns the event that next() returned the last time it was called. It doesn't + alter this AbstractXmlPullProvider. + + current() may not modify this AbstractXmlPullProvider's state. Subsequent calls to current() + must return the same value. + + \sa AbstractXmlPullProvider::Event + */ + +/*! + \fn QName AbstractXmlPullProvider::name() const = 0; + If the current event is StartElement, + EndElement, ProcessingInstruction, Attribute, or Namespace, the node's name is returned. + + If the current event is ProcessingInstruction, + the processing instruction target is in in the local name. + + If the current event is Namespace, the name's namespace URI is the namespace, and + the local name is the prefix the name is binding to. + + In all other cases, an invalid QName is returned. + */ + +/*! + \fn QVariant AbstractXmlPullProvider::atomicValue() const = 0; + + If current() event is AtomicValue, the atomic value is returned as a QVariant. + In all other cases, this function returns a null QVariant. + */ + +/*! + \fn QString AbstractXmlPullProvider::stringValue() const = 0; + + If current() is Text, the text node's value is returned. + + If the current() event is Comment, its value is returned. The subclasser guarantees + it does not contain the string "-->". + + If the current() event is ProcessingInstruction, its data is returned. The subclasser + guarantees the data does not contain the string "?>". + + In other cases, it returns a default constructed string. + */ + +/*! + \fn QHash<QXmlName, QString> AbstractXmlPullProvider::attributes() = 0; + + If the current() is Element, the attributes of the element are returned, + an empty list of attributes otherwise. + */ + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qabstractxmlpullprovider_p.h b/src/xmlpatterns/api/qabstractxmlpullprovider_p.h new file mode 100644 index 0000000..547bf4b --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlpullprovider_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QABSTRACTXMLPULLPROVIDER_H +#define QABSTRACTXMLPULLPROVIDER_H + +#include <QtCore/QtGlobal> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlItem; +class QXmlName; +class QString; +class QVariant; +template<typename Key, typename Value> class QHash; + +namespace QPatternist +{ + class AbstractXmlPullProviderPrivate; + + class AbstractXmlPullProvider + { + public: + AbstractXmlPullProvider(); + virtual ~AbstractXmlPullProvider(); + + enum Event + { + StartOfInput = 1, + AtomicValue = 1 << 1, + StartDocument = 1 << 2, + EndDocument = 1 << 3, + StartElement = 1 << 4, + EndElement = 1 << 5, + Text = 1 << 6, + ProcessingInstruction = 1 << 7, + Comment = 1 << 8, + Attribute = 1 << 9, + Namespace = 1 << 10, + EndOfInput = 1 << 11 + }; + + virtual Event next() = 0; + virtual Event current() const = 0; + virtual QXmlName name() const = 0; + virtual QVariant atomicValue() const = 0; + virtual QString stringValue() const = 0; + + virtual QHash<QXmlName, QString> attributes() = 0; + virtual QHash<QXmlName, QXmlItem> attributeItems() = 0; + + /* *** The functions below are internal. */ + private: + Q_DISABLE_COPY(AbstractXmlPullProvider) + AbstractXmlPullProviderPrivate *d; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qabstractxmlreceiver.cpp b/src/xmlpatterns/api/qabstractxmlreceiver.cpp new file mode 100644 index 0000000..2b7c295 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlreceiver.cpp @@ -0,0 +1,475 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QString> + +#include "qitem_p.h" + +#include "qabstractxmlreceiver_p.h" +#include "qabstractxmlreceiver.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractXmlReceiver + \brief The QAbstractXmlReceiver class provides a callback interface + for transforming the output of a QXmlQuery. + \reentrant + \since 4.4 + \ingroup xml-tools + + QAbstractXmlReceiver is an abstract base class that provides + a callback interface for receiving an \l {XQuery Sequence} + {XQuery sequence}, usually the output of an QXmlQuery, and + transforming that sequence into a structure of your choosing, + usually XML. Consider the example: + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qabstractxmlreceiver.cpp 0 + + First it constructs a \l {QXmlQuery} {query} that gets the + first paragraph from document \c index.html. Then it constructs + an \l {QXmlSerializer} {XML serializer} with the \l {QXmlQuery} + {query} and \l {QIODevice} {myOutputDevice} (Note the + \l {QXmlSerializer} {serializer} is an \e {XML receiver}, + ie a subclass of QAbstractXmlReceiver). Finally, it + \l {QXmlQuery::evaluateTo()} {evaluates} the + \l {QXmlQuery} {query}, producing an ordered sequence of calls + to the \l {QXmlSerializer} {serializer's} callback functions. + The sequence of callbacks transforms the query output to XML + and writes it to \l {QIODevice} {myOutputDevice}. + + Although the example uses \l {QXmlQuery} to produce the sequence + of callbacks to functions in QAbstractXmlReceiver, you can call + the callback functions directly as long as your sequence of + calls represents a valid \l {XQuery Sequence} {XQuery sequence}. + + \target XQuery Sequence + \section1 XQuery Sequences + + An XQuery \a sequence is an ordered collection of zero, one, + or many \e items. Each \e item is either an \e {atomic value} + or a \e {node}. An \e {atomic value} is a simple data value. + + There are six kinds of \e nodes. + + \list + + \o An \e {Element Node} represents an XML element. + + \o An \e {Attribute Node} represents an XML attribute. + + \o A \e {Document Node} represents an entire XML document. + + \o A \e {Text Node} represents character data (element content). + + \o A \e {Processing Instruction Node} represents an XML + processing instruction, which is used in an XML document + to tell the application reading the document to perform + some action. A typical example is to use a processing + instruction to tell the application to use a particular + XSLT stylesheet to display the document. + + \o And a \e {Comment node} represents an XML comment. + + \endlist + + The \e sequence of \e nodes and \e {atomic values} obeys + the following rules. Note that \e {Namespace Node} refers + to a special \e {Attribute Node} with name \e {xmlns}. + + \list + + \o Each \e node appears in the \e sequence before its children + and their descendants appear. + + \o A \e node's descendants appear in the \e sequence before + any of its siblings appear. + + \o A \e {Document Node} represents an entire document. Zero or + more \e {Document Nodes} can appear in a \e sequence, but they + can only be top level items (i.e., a \e {Document Node} can't + be a child of another \e node. + + \o \e {Namespace Nodes} immediately follow the \e {Element Node} + with which they are associated. + + \o \e {Attribute Nodes} immediately follow the \e {Namespace Nodes} + of the element with which they are associated, or... + + \o If there are no \e {Namespace Nodes} following an element, then + the \e {Attribute Nodes} immediately follow the element. + + \o An \e {atomic value} can only appear as a top level \e item, + i.e., it can't appear as a child of a \e node. + + \o \e {Processing Instruction Nodes} do not have children, and + their parent is either a \e {Document Node} or an \e {Element + Node}. + + \o \e {Comment Nodes} do not have children, and + their parent is either a \e {Document Node} or an \e {Element + Node}. + + \endlist + + The \e sequence of \e nodes and \e {atomic values} is sent to + an QAbstractXmlReceiver (QXmlSerializer in + the example above) as a sequence of calls to the receiver's + callback functions. The mapping of callback functions to + sequence items is as follows. + + \list + + \o startDocument() and endDocument() are called for each + \e {Document Node} in the \e sequence. endDocument() is not + called until all the \e {Document Node's} children have + appeared in the \e sequence. + + \o startElement() and endElement() are called for each + \e {Element Node}. endElement() is not called until all the + \e {Element Node's} children have appeared in the \e sequence. + + \o attribute() is called for each \e {Attribute Node}. + + \o comment() is called for each \e {Comment Node}. + + \o characters() is called for each \e {Text Node}. + + \o processingInstruction() is called for each \e {Processing + Instruction Node}. + + \o namespaceBinding() is called for each \e {Namespace Node}. + + \o atomicValue() is called for each \e {atomic value}. + + \endlist + + For a complete explanation of XQuery sequences, visit + \l {http://www.w3.org/TR/xpath-datamodel/}{XQuery Data Model}. + + \sa {http://www.w3.org/TR/xpath-datamodel/}{W3C XQuery 1.0 and XPath 2.0 Data Model (XDM)} + \sa QXmlSerializer + \sa QXmlResultItems + */ + +template<const QXmlNodeModelIndex::Axis axis> +void QAbstractXmlReceiver::sendFromAxis(const QXmlNodeModelIndex &node) +{ + Q_ASSERT(!node.isNull()); + const QXmlNodeModelIndex::Iterator::Ptr it(node.iterate(axis)); + QXmlNodeModelIndex next(it->next()); + + while(!next.isNull()) + { + sendAsNode(next); + next = it->next(); + } +} + +/*! + \internal + */ +QAbstractXmlReceiver::QAbstractXmlReceiver(QAbstractXmlReceiverPrivate *d) + : d_ptr(d) +{ +} + +/*! + Constructs an abstract xml receiver. + */ +QAbstractXmlReceiver::QAbstractXmlReceiver() : d_ptr(0) +{ +} + +/*! + Destroys the xml receiver. + */ +QAbstractXmlReceiver::~QAbstractXmlReceiver() +{ +} + +/*! + \fn void QAbstractXmlReceiver::startElement(const QXmlName &name) + + This callback is called when a new element node appears + in the \l {XQuery Sequence} {sequence}. \a name is the + valid \l {QXmlName} {name} of the node element. + */ + +/* +### Qt 5: + +Consider how source locations should be communicated. Maybe every signature +should be extended by adding "qint64 line = -1, qint64 column = -1". + */ + +/*! + \fn void QAbstractXmlReceiver::endElement() + + This callback is called when the end of an element node + appears in the \l {XQuery Sequence} {sequence}. +*/ + +/*! + \fn void QAbstractXmlReceiver::attribute(const QXmlName &name, + const QStringRef &value) + This callback is called when an attribute node + appears in the \l {XQuery Sequence} {sequence}. + \a name is the \l {QXmlName} {attribute name} and + the \a value string contains the attribute value. + */ + +/*! + \fn void QAbstractXmlReceiver::comment(const QString &value) + + This callback is called when a comment node appears + in the \l {XQuery Sequence} {sequence}. The \a value + is the comment text, which must not contain the string + "--". + */ + +/*! + \fn void QAbstractXmlReceiver::characters(const QStringRef &value) + + This callback is called when a text node appears in the + \l {XQuery Sequence} {sequence}. The \a value contains + the text. Adjacent text nodes may not occur in the + \l {XQuery Sequence} {sequence}, i.e., this callback must not + be called twice in a row. + */ + +/*! + \fn void QAbstractXmlReceiver::startDocument() + + This callback is called when a document node appears + in the \l {XQuery Sequence} {sequence}. + */ + +/* +### Qt 5: + +Change + virtual void startDocument() = 0; + +To: + virtual void startDocument(const QUrl &uri) = 0; + +Such that it allows the document URI to be communicated. The contract would +allow null QUrls. +*/ + +/*! + \fn void QAbstractXmlReceiver::endDocument() + + This callback is called when the end of a document node + appears in the \l {XQuery Sequence} {sequence}. + */ + +/*! + \fn void QAbstractXmlReceiver::processingInstruction(const QXmlName &target, + const QString &value) + + This callback is called when a processing instruction + appears in the \l {XQuery Sequence} {sequence}. + A processing instruction is used in an XML document + to tell the application reading the document to + perform some action. A typical example is to use a + processing instruction to tell the application to use a + particular XSLT stylesheet to process the document. + + \quotefile doc/src/snippets/patternist/xmlStylesheet.xq + + \a target is the \l {QXmlName} {name} of the processing + instruction. Its \e prefix and \e {namespace URI} must both + be empty. Its \e {local name} is the target. In the above + example, the name is \e {xml-stylesheet}. + + The \a value specifies the action to be taken. Note that + the \a value must not contain the string "?>". In the above + example, the \a value is \e{type="test/xsl" href="formatter.xsl}. + + Generally, use of processing instructions should be avoided, + because they are not namespace aware and in many contexts + are stripped out anyway. Processing instructions can often + be replaced with elements from a custom namespace. + */ + +/*! + \fn void QAbstractXmlReceiver::atomicValue(const QVariant &value) + + This callback is called when an atomic value appears in the \l + {XQuery Sequence} {sequence}. The \a value is a simple \l {QVariant} + {data value}. It is guaranteed to be \l {QVariant::isValid()} + {valid}. + */ + +/*! + \fn virtual void QAbstractXmlReceiver::namespaceBinding(const QXmlName &name) + + This callback is called when a namespace binding is in scope of an + element. A namespace is defined by a URI. In the \l {QXmlName} + \a name, the value of \l {QXmlName::namespaceUri()} is that URI. The + value of \l {QXmlName::prefix()} is the prefix that the URI is bound + to. The local name is insignificant and can be an arbitrary value. + */ + +/*! + \internal + + Treats \a outputItem as a node and calls the appropriate function, + e.g., attribute() or comment(), depending on its + QXmlNodeModelIndex::NodeKind. + + This is a helper function that subclasses can use to multiplex + Nodes received via item(). + */ +void QAbstractXmlReceiver::sendAsNode(const QPatternist::Item &outputItem) +{ + Q_ASSERT(outputItem); + Q_ASSERT(outputItem.isNode()); + const QXmlNodeModelIndex asNode = outputItem.asNode(); + + switch(asNode.kind()) + { + case QXmlNodeModelIndex::Attribute: + { + const QString &v = outputItem.stringValue(); + attribute(asNode.name(), QStringRef(&v)); + return; + } + case QXmlNodeModelIndex::Element: + { + startElement(asNode.name()); + + /* First the namespaces, then attributes, then the children. */ + asNode.sendNamespaces(this); + sendFromAxis<QXmlNodeModelIndex::AxisAttribute>(asNode); + sendFromAxis<QXmlNodeModelIndex::AxisChild>(asNode); + + endElement(); + + return; + } + case QXmlNodeModelIndex::Text: + { + const QString &v = asNode.stringValue(); + characters(QStringRef(&v)); + return; + } + case QXmlNodeModelIndex::ProcessingInstruction: + { + processingInstruction(asNode.name(), outputItem.stringValue()); + return; + } + case QXmlNodeModelIndex::Comment: + { + comment(outputItem.stringValue()); + return; + } + case QXmlNodeModelIndex::Document: + { + startDocument(); + sendFromAxis<QXmlNodeModelIndex::AxisChild>(asNode); + endDocument(); + return; + } + case QXmlNodeModelIndex::Namespace: + Q_ASSERT_X(false, Q_FUNC_INFO, "Not implemented"); + } + + Q_ASSERT_X(false, Q_FUNC_INFO, + QString::fromLatin1("Unknown node type: %1").arg(asNode.kind()).toUtf8().constData()); +} + +/*! + \internal + + This function may be called instead of characters() if, and only if, + \a value consists only of whitespace. + + The caller gurantees that \a value is not empty. + + \e Whitespace refers to a sequence of characters that are either + spaces, tabs, or newlines, in any order. In other words, not all + the Unicode whitespace category is considered whitespace here. + + However, there is no guarantee or requirement that whitespaceOnly() + is called for text nodes containing whitespace only. characters() + may be called just as well. This is why the default implementation + for whitespaceOnly() calls characters(). + + \sa characters() + */ +void QAbstractXmlReceiver::whitespaceOnly(const QStringRef &value) +{ + Q_ASSERT_X(value.toString().trimmed().isEmpty(), Q_FUNC_INFO, + "The caller must guarantee only whitespace is passed. Use characters() in other cases."); + const QString &v = value.toString(); + characters(QStringRef(&v)); +} + +/*! + \internal + */ +void QAbstractXmlReceiver::item(const QPatternist::Item &item) +{ + if(item.isNode()) + return sendAsNode(item); + else + atomicValue(QPatternist::AtomicValue::toQt(item.asAtomicValue())); +} + +/*! + \fn void QAbstractXmlReceiver::startOfSequence() + + This callback is called once only, right before the + \l {XQuery Sequence} {sequence} begins. + */ + +/*! + \fn void QAbstractXmlReceiver::endOfSequence() + + This callback is called once only, right after the + \l {XQuery Sequence} {sequence} ends. + */ + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qabstractxmlreceiver.h b/src/xmlpatterns/api/qabstractxmlreceiver.h new file mode 100644 index 0000000..0407730 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlreceiver.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTXMLRECEIVER_H +#define QABSTRACTXMLRECEIVER_H + +#include <QtCore/QVariant> +#include <QtCore/QScopedPointer> +#include <QtXmlPatterns/QXmlNodeModelIndex> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QAbstractXmlReceiverPrivate; +class QXmlName; + +namespace QPatternist +{ + class Item; +} + +class Q_XMLPATTERNS_EXPORT QAbstractXmlReceiver +{ +public: + QAbstractXmlReceiver(); + + virtual ~QAbstractXmlReceiver(); + + virtual void startElement(const QXmlName &name) = 0; + virtual void endElement() = 0; + virtual void attribute(const QXmlName &name, + const QStringRef &value) = 0; + virtual void comment(const QString &value) = 0; + virtual void characters(const QStringRef &value) = 0; + virtual void startDocument() = 0; + virtual void endDocument() = 0; + + virtual void processingInstruction(const QXmlName &target, + const QString &value) = 0; + + virtual void atomicValue(const QVariant &value) = 0; + virtual void namespaceBinding(const QXmlName &name) = 0; + virtual void startOfSequence() = 0; + virtual void endOfSequence() = 0; + + /* The members below are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ + virtual void whitespaceOnly(const QStringRef &value); + virtual void item(const QPatternist::Item &item); + +protected: + QAbstractXmlReceiver(QAbstractXmlReceiverPrivate *d); + QScopedPointer<QAbstractXmlReceiverPrivate> d_ptr; + + void sendAsNode(const QPatternist::Item &outputItem); +private: + template<const QXmlNodeModelIndex::Axis axis> + void sendFromAxis(const QXmlNodeModelIndex &node); + Q_DISABLE_COPY(QAbstractXmlReceiver) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qabstractxmlreceiver_p.h b/src/xmlpatterns/api/qabstractxmlreceiver_p.h new file mode 100644 index 0000000..34fd546 --- /dev/null +++ b/src/xmlpatterns/api/qabstractxmlreceiver_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QABSTRACTXMLRECEIVER_P_H +#define QABSTRACTXMLRECEIVER_P_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAbstractXmlReceiverPrivate +{ +public: + virtual ~QAbstractXmlReceiverPrivate() + { + } +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qcoloringmessagehandler.cpp b/src/xmlpatterns/api/qcoloringmessagehandler.cpp new file mode 100644 index 0000000..83dbaee --- /dev/null +++ b/src/xmlpatterns/api/qcoloringmessagehandler.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QXmlStreamReader> + +#include "qcoloringmessagehandler_p.h" +#include "qxmlpatternistcli_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +ColoringMessageHandler::ColoringMessageHandler(QObject *parent) : QAbstractMessageHandler(parent) +{ + m_classToColor.insert(QLatin1String("XQuery-data"), Data); + m_classToColor.insert(QLatin1String("XQuery-expression"), Keyword); + m_classToColor.insert(QLatin1String("XQuery-function"), Keyword); + m_classToColor.insert(QLatin1String("XQuery-keyword"), Keyword); + m_classToColor.insert(QLatin1String("XQuery-type"), Keyword); + m_classToColor.insert(QLatin1String("XQuery-uri"), Data); + m_classToColor.insert(QLatin1String("XQuery-filepath"), Data); + + /* If you're tuning the colors, take it easy laddie. Take into account: + * + * - Get over your own taste, there's others too on this planet + * - Make sure it works well on black & white + * - Make sure it works well on white & black + */ + insertMapping(Location, CyanForeground); + insertMapping(ErrorCode, RedForeground); + insertMapping(Keyword, BlueForeground); + insertMapping(Data, BlueForeground); + insertMapping(RunningText, DefaultColor); +} + +void ColoringMessageHandler::handleMessage(QtMsgType type, + const QString &description, + const QUrl &identifier, + const QSourceLocation &sourceLocation) +{ + const bool hasLine = sourceLocation.line() != -1; + + switch(type) + { + case QtWarningMsg: + { + if(hasLine) + { + writeUncolored(QXmlPatternistCLI::tr("Warning in %1, at line %2, column %3: %4").arg(QString::fromLatin1(sourceLocation.uri().toEncoded()), + QString::number(sourceLocation.line()), + QString::number(sourceLocation.column()), + colorifyDescription(description))); + } + else + { + writeUncolored(QXmlPatternistCLI::tr("Warning in %1: %2").arg(QString::fromLatin1(sourceLocation.uri().toEncoded()), + colorifyDescription(description))); + } + + break; + } + case QtFatalMsg: + { + const QString errorCode(identifier.fragment()); + Q_ASSERT(!errorCode.isEmpty()); + QUrl uri(identifier); + uri.setFragment(QString()); + + QString location; + + if(sourceLocation.isNull()) + location = QXmlPatternistCLI::tr("Unknown location"); + else + location = QString::fromLatin1(sourceLocation.uri().toEncoded()); + + QString errorId; + /* If it's a standard error code, we don't want to output the + * whole URI. */ + if(uri.toString() == QLatin1String("http://www.w3.org/2005/xqt-errors")) + errorId = errorCode; + else + errorId = QString::fromLatin1(identifier.toEncoded()); + + if(hasLine) + { + writeUncolored(QXmlPatternistCLI::tr("Error %1 in %2, at line %3, column %4: %5").arg(colorify(errorId, ErrorCode), + colorify(location, Location), + colorify(QString::number(sourceLocation.line()), Location), + colorify(QString::number(sourceLocation.column()), Location), + colorifyDescription(description))); + } + else + { + writeUncolored(QXmlPatternistCLI::tr("Error %1 in %2: %3").arg(colorify(errorId, ErrorCode), + colorify(location, Location), + colorifyDescription(description))); + } + break; + } + case QtCriticalMsg: + /* Fallthrough. */ + case QtDebugMsg: + { + Q_ASSERT_X(false, Q_FUNC_INFO, + "message() is not supposed to receive QtCriticalMsg or QtDebugMsg."); + return; + } + } +} + +QString ColoringMessageHandler::colorifyDescription(const QString &in) const +{ + QXmlStreamReader reader(in); + QString result; + result.reserve(in.size()); + ColorType currentColor = RunningText; + + while(!reader.atEnd()) + { + reader.readNext(); + + switch(reader.tokenType()) + { + case QXmlStreamReader::StartElement: + { + if(reader.name() == QLatin1String("span")) + { + Q_ASSERT(m_classToColor.contains(reader.attributes().value(QLatin1String("class")).toString())); + currentColor = m_classToColor.value(reader.attributes().value(QLatin1String("class")).toString()); + } + + continue; + } + case QXmlStreamReader::Characters: + { + result.append(colorify(reader.text().toString(), currentColor)); + continue; + } + case QXmlStreamReader::EndElement: + { + currentColor = RunningText; + continue; + } + /* Fallthrough, */ + case QXmlStreamReader::StartDocument: + /* Fallthrough, */ + case QXmlStreamReader::EndDocument: + continue; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, + "Unexpected node."); + } + } + + Q_ASSERT_X(!reader.hasError(), Q_FUNC_INFO, + "The output from Patternist must be well-formed."); + return result; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qcoloringmessagehandler_p.h b/src/xmlpatterns/api/qcoloringmessagehandler_p.h new file mode 100644 index 0000000..223bed6 --- /dev/null +++ b/src/xmlpatterns/api/qcoloringmessagehandler_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the XMLPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_ColoringMessageHandler_h +#define Patternist_ColoringMessageHandler_h + +#include <QHash> + +#include "qcoloroutput_p.h" +#include "qabstractmessagehandler.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class ColoringMessageHandler : public QAbstractMessageHandler + , private ColorOutput + { + public: + ColoringMessageHandler(QObject *parent = 0); + + protected: + virtual void handleMessage(QtMsgType type, + const QString &description, + const QUrl &identifier, + const QSourceLocation &sourceLocation); + + private: + QString colorifyDescription(const QString &in) const; + + enum ColorType + { + RunningText, + Location, + ErrorCode, + Keyword, + Data + }; + + QHash<QString, ColorType> m_classToColor; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qcoloroutput.cpp b/src/xmlpatterns/api/qcoloroutput.cpp new file mode 100644 index 0000000..9ba7430 --- /dev/null +++ b/src/xmlpatterns/api/qcoloroutput.cpp @@ -0,0 +1,377 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QFile> +#include <QHash> +#include <QTextCodec> + +#include "qcoloroutput_p.h" + +// TODO: rename insertMapping() to insertColorMapping() +// TODO: Use a smart pointer for managing ColorOutputPrivate *d; +// TODO: break out the C++ example into a snippet file + +/* This include must appear here, because if it appears at the beginning of the file for + * instance, it breaks build -- "qglobal.h:628: error: template with + * C linkage" -- on Mac OS X 10.4. */ +#ifndef Q_OS_WIN +#include <unistd.h> +#endif + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +namespace QPatternist +{ + class ColorOutputPrivate + { + public: + ColorOutputPrivate() : currentColorID(-1) + + { + /* - QIODevice::Unbuffered because we want it to appear when the user actually calls, performance + * is considered of lower priority. + */ + m_out.open(stderr, QIODevice::WriteOnly | QIODevice::Unbuffered); + + coloringEnabled = isColoringPossible(); + } + + ColorOutput::ColorMapping colorMapping; + int currentColorID; + bool coloringEnabled; + + static const char *const foregrounds[]; + static const char *const backgrounds[]; + + inline void write(const QString &msg) + { + m_out.write(msg.toLocal8Bit()); + } + + static QString escapeCode(const QString &in) + { + QString result; + result.append(QChar(0x1B)); + result.append(QLatin1Char('[')); + result.append(in); + result.append(QLatin1Char('m')); + return result; + } + + private: + QFile m_out; + + /*! + Returns true if it's suitable to send colored output to \c stderr. + */ + inline bool isColoringPossible() const + { +# if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + /* Windows doesn't at all support ANSI escape codes, unless + * the user install a "device driver". See the Wikipedia links in the + * class documentation for details. */ + return false; +# else + /* We use QFile::handle() to get the file descriptor. It's a bit unsure + * whether it's 2 on all platforms and in all cases, so hopefully this layer + * of abstraction helps handle such cases. */ + return isatty(m_out.handle()); +# endif + } + }; +} + +const char *const ColorOutputPrivate::foregrounds[] = +{ + "0;30", + "0;34", + "0;32", + "0;36", + "0;31", + "0;35", + "0;33", + "0;37", + "1;30", + "1;34", + "1;32", + "1;36", + "1;31", + "1;35", + "1;33", + "1;37" +}; + +const char *const ColorOutputPrivate::backgrounds[] = +{ + "0;40", + "0;44", + "0;42", + "0;46", + "0;41", + "0;45", + "0;43" +}; + +/*! + \class ColorOutput + \since 4.4 + \nonreentrant + \brief Outputs colored messages to \c stderr. + \internal + + ColorOutput is a convenience class for outputting messages to \c + stderr using color escape codes, as mandated in ECMA-48. ColorOutput + will only color output when it is detected to be suitable. For + instance, if \c stderr is detected to be attached to a file instead + of a TTY, no coloring will be done. + + ColorOutput does its best attempt. but it is generally undefined + what coloring or effect the various coloring flags has. It depends + strongly on what terminal software that is being used. + + When using `echo -e 'my escape sequence'`, \c{\033} works as an + initiator but not when printing from a C++ program, despite having + escaped the backslash. That's why we below use characters with + value 0x1B. + + It can be convenient to subclass ColorOutput with a private scope, + such that the functions are directly available in the class using + it. + + \section1 Usage + + To output messages, call write() or writeUncolored(). write() takes + as second argument an integer, which ColorOutput uses as a lookup + key to find the color it should color the text in. The mapping from + keys to colors is done using insertMapping(). Typically this is used + by having enums for the various kinds of messages, which + subsequently are registered. + + \code + enum MyMessage + { + Error, + Important + }; + + ColorOutput output; + output.insertMapping(Error, ColorOutput::RedForeground); + output.insertMapping(Import, ColorOutput::BlueForeground); + + output.write("This is important", Important); + output.write("Jack, I'm only the selected official!", Error); + \endcode + + \sa {http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html} {Bash Prompt HOWTO, 6.1. Colours} + {http://linuxgazette.net/issue51/livingston-blade.html} {Linux Gazette, Tweaking Eterm, Edward Livingston-Blade} + {http://www.ecma-international.org/publications/standards/Ecma-048.htm} {Standard ECMA-48, Control Functions for Coded Character Sets, ECMA International}, + {http://en.wikipedia.org/wiki/ANSI_escape_code} {Wikipedia, ANSI escape code} + {http://linuxgazette.net/issue65/padala.html} {Linux Gazette, So You Like Color!, Pradeep Padala} + */ + +/*! + \enum ColorOutput::ColorCodeComponent + \value BlackForeground + \value BlueForeground + \value GreenForeground + \value CyanForeground + \value RedForeground + \value PurpleForeground + \value BrownForeground + \value LightGrayForeground + \value DarkGrayForeground + \value LightBlueForeground + \value LightGreenForeground + \value LightCyanForeground + \value LightRedForeground + \value LightPurpleForeground + \value YellowForeground + \value WhiteForeground + \value BlackBackground + \value BlueBackground + \value GreenBackground + \value CyanBackground + \value RedBackground + \value PurpleBackground + \value BrownBackground + + \value DefaultColor ColorOutput performs no coloring. This typically + means black on white or white on black, depending + on the settings of the user's terminal. + */ + +/*! + Sets the color mapping to be \a cMapping. + + Negative values are disallowed. + + \sa colorMapping(), insertMapping() + */ +void ColorOutput::setColorMapping(const ColorMapping &cMapping) +{ + d->colorMapping = cMapping; +} + +/*! + Returns the color mappings in use. + + \sa setColorMapping(), insertMapping() + */ +ColorOutput::ColorMapping ColorOutput::colorMapping() const +{ + return d->colorMapping; +} + +/*! + Constructs a ColorOutput instance, ready for use. + */ +ColorOutput::ColorOutput() : d(new ColorOutputPrivate()) +{ +} + +/*! + Destructs this ColorOutput instance. + */ +ColorOutput::~ColorOutput() +{ + delete d; +} + +/*! + Sends \a message to \c stderr, using the color looked up in colorMapping() using \a colorID. + + If \a color isn't available in colorMapping(), result and behavior is undefined. + + If \a colorID is 0, which is the default value, the previously used coloring is used. ColorOutput + is initialized to not color at all. + + If \a message is empty, effects are undefined. + + \a message will be printed as is. For instance, no line endings will be inserted. + */ +void ColorOutput::write(const QString &message, int colorID) +{ + d->write(colorify(message, colorID)); +} + +/*! + Writes \a message to \c stderr as if for instance + QTextStream would have been used, and adds a line ending at the end. + + This function can be practical to use such that one can use ColorOutput for all forms of writing. + */ +void ColorOutput::writeUncolored(const QString &message) +{ + d->write(message + QLatin1Char('\n')); +} + +/*! + Treats \a message and \a colorID identically to write(), but instead of writing + \a message to \c stderr, it is prepared for being written to \c stderr, but is then + returned. + + This is useful when the colored string is inserted into a translated string(dividing + the string into several small strings prevents proper translation). + */ +QString ColorOutput::colorify(const QString &message, int colorID) const +{ + Q_ASSERT_X(colorID == -1 || d->colorMapping.contains(colorID), Q_FUNC_INFO, + qPrintable(QString::fromLatin1("There is no color registered by id %1").arg(colorID))); + Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO, "It makes no sense to attempt to print an empty string."); + + if(colorID != -1) + d->currentColorID = colorID; + + if(d->coloringEnabled && colorID != -1) + { + const int color(d->colorMapping.value(colorID)); + + /* If DefaultColor is set, we don't want to color it. */ + if(color & DefaultColor) + return message; + + const int foregroundCode = (int(color) & ForegroundMask) >> ForegroundShift; + const int backgroundCode = (int(color) & BackgroundMask) >> BackgroundShift; + QString finalMessage; + bool closureNeeded = false; + + if(foregroundCode) + { + finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1]))); + closureNeeded = true; + } + + if(backgroundCode) + { + finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1]))); + closureNeeded = true; + } + + finalMessage.append(message); + + if(closureNeeded) + { + finalMessage.append(QChar(0x1B)); + finalMessage.append(QLatin1String("[0m")); + } + + return finalMessage; + } + else + return message; +} + +/*! + Adds a color mapping from \a colorID to \a colorCode, for this ColorOutput instance. + + This is a convenience function for creating a ColorOutput::ColorMapping instance and + calling setColorMapping(). + + \sa colorMapping(), setColorMapping() + */ +void ColorOutput::insertMapping(int colorID, const ColorCode colorCode) +{ + d->colorMapping.insert(colorID, colorCode); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qcoloroutput_p.h b/src/xmlpatterns/api/qcoloroutput_p.h new file mode 100644 index 0000000..020cfc2 --- /dev/null +++ b/src/xmlpatterns/api/qcoloroutput_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the XMLPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_ColorOutput_h +#define Patternist_ColorOutput_h + +#include <QtCore/QtGlobal> +#include <QtCore/QHash> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class ColorOutputPrivate; + + class ColorOutput + { + enum + { + ForegroundShift = 10, + BackgroundShift = 20, + SpecialShift = 20, + ForegroundMask = ((1 << ForegroundShift) - 1) << ForegroundShift, + BackgroundMask = ((1 << BackgroundShift) - 1) << BackgroundShift + }; + + public: + enum ColorCodeComponent + { + BlackForeground = 1 << ForegroundShift, + BlueForeground = 2 << ForegroundShift, + GreenForeground = 3 << ForegroundShift, + CyanForeground = 4 << ForegroundShift, + RedForeground = 5 << ForegroundShift, + PurpleForeground = 6 << ForegroundShift, + BrownForeground = 7 << ForegroundShift, + LightGrayForeground = 8 << ForegroundShift, + DarkGrayForeground = 9 << ForegroundShift, + LightBlueForeground = 10 << ForegroundShift, + LightGreenForeground = 11 << ForegroundShift, + LightCyanForeground = 12 << ForegroundShift, + LightRedForeground = 13 << ForegroundShift, + LightPurpleForeground = 14 << ForegroundShift, + YellowForeground = 15 << ForegroundShift, + WhiteForeground = 16 << ForegroundShift, + + BlackBackground = 1 << BackgroundShift, + BlueBackground = 2 << BackgroundShift, + GreenBackground = 3 << BackgroundShift, + CyanBackground = 4 << BackgroundShift, + RedBackground = 5 << BackgroundShift, + PurpleBackground = 6 << BackgroundShift, + BrownBackground = 7 << BackgroundShift, + DefaultColor = 1 << SpecialShift + }; + + typedef QFlags<ColorCodeComponent> ColorCode; + typedef QHash<int, ColorCode> ColorMapping; + + ColorOutput(); + ~ColorOutput(); + + void setColorMapping(const ColorMapping &cMapping); + ColorMapping colorMapping() const; + void insertMapping(int colorID, const ColorCode colorCode); + + void writeUncolored(const QString &message); + void write(const QString &message, int color = -1); + QString colorify(const QString &message, int color = -1) const; + + private: + ColorOutputPrivate *d; + Q_DISABLE_COPY(ColorOutput) + }; +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(QPatternist::ColorOutput::ColorCode) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qdeviceresourceloader_p.h b/src/xmlpatterns/api/qdeviceresourceloader_p.h new file mode 100644 index 0000000..fbea0a7 --- /dev/null +++ b/src/xmlpatterns/api/qdeviceresourceloader_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QPatternist_DeviceResourceLoader_p_H +#define QPatternist_DeviceResourceLoader_p_H + +template<typename T> class QSet; +class QUrl; + +#include "qresourceloader_p.h" + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Base class for resource loaders that manage device variables. + * + * @author Frans Englich <frans.englich@nokia.com> + * @since 4.5 + */ + class DeviceResourceLoader : public ResourceLoader + { + public: + typedef QExplicitlySharedDataPointer<DeviceResourceLoader> Ptr; + /** + * @short Returns the URIs for device variables that this + * ResourceLoader has loaded. + * + * The returned set may be empty. + */ + virtual QSet<QUrl> deviceURIs() const = 0; + }; +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qiodevicedelegate.cpp b/src/xmlpatterns/api/qiodevicedelegate.cpp new file mode 100644 index 0000000..ebd6e41 --- /dev/null +++ b/src/xmlpatterns/api/qiodevicedelegate.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtDebug> + +#include "qpatternistlocale_p.h" + +#include "qiodevicedelegate_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +QIODeviceDelegate::QIODeviceDelegate(QIODevice *const source) : m_source(source) +{ + Q_ASSERT(m_source); + + connect(source, SIGNAL(aboutToClose()), SIGNAL(aboutToClose())); + connect(source, SIGNAL(bytesWritten(qint64)), SIGNAL(bytesWritten(qint64))); + connect(source, SIGNAL(readChannelFinished()), SIGNAL(readChannelFinished())); + connect(source, SIGNAL(readyRead()), SIGNAL(readyRead())); + + /* According to Thiago these two signals are very similar, but QtNetworkAccess uses finished() + * instead for a minor but significant reason. */ + connect(source, SIGNAL(readChannelFinished()), SIGNAL(finished())); + + /* For instance QFile emits no signals, so how do we know if the device has all data available + * and it therefore is safe and correct to emit finished()? isSequential() tells us whether it's + * not random access, and whether it's safe to emit finished(). */ + if(m_source->isSequential()) + QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); + else + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); + + setOpenMode(QIODevice::ReadOnly); + + /* Set up the timeout timer. */ + connect(&m_timeout, SIGNAL(timeout()), SLOT(networkTimeout())); + + m_timeout.setSingleShot(true); + m_timeout.start(Timeout); +} + +void QIODeviceDelegate::networkTimeout() +{ + setErrorString(QtXmlPatterns::tr("Network timeout.")); + error(QNetworkReply::TimeoutError); +} + +void QIODeviceDelegate::abort() +{ + /* Do nothing, just to please QNetworkReply's pure virtual. */ +} + +bool QIODeviceDelegate::atEnd() const +{ + return m_source->atEnd(); +} + +qint64 QIODeviceDelegate::bytesAvailable() const +{ + return m_source->bytesAvailable(); +} + +qint64 QIODeviceDelegate::bytesToWrite() const +{ + return m_source->bytesToWrite(); +} + +bool QIODeviceDelegate::canReadLine() const +{ + return m_source->canReadLine(); +} + +void QIODeviceDelegate::close() +{ + return m_source->close(); +} + +bool QIODeviceDelegate::isSequential() const +{ + return m_source->isSequential(); +} + +bool QIODeviceDelegate::open(OpenMode mode) +{ + const bool success = m_source->open(mode); + setOpenMode(m_source->openMode()); + return success; +} + +qint64 QIODeviceDelegate::pos() const +{ + return m_source->pos(); +} + +bool QIODeviceDelegate::reset() +{ + return m_source->reset(); +} + +bool QIODeviceDelegate::seek(qint64 pos) +{ + return m_source->seek(pos); +} + +qint64 QIODeviceDelegate::size() const +{ + return m_source->size(); +} + +bool QIODeviceDelegate::waitForBytesWritten(int msecs) +{ + return m_source->waitForBytesWritten(msecs); +} + +bool QIODeviceDelegate::waitForReadyRead(int msecs) +{ + return m_source->waitForReadyRead(msecs); +} + +qint64 QIODeviceDelegate::readData(char *data, qint64 maxSize) +{ + return m_source->read(data, maxSize); +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qiodevicedelegate_p.h b/src/xmlpatterns/api/qiodevicedelegate_p.h new file mode 100644 index 0000000..456048e --- /dev/null +++ b/src/xmlpatterns/api/qiodevicedelegate_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QIODEVICEDELEGATE_P_H +#define QIODEVICEDELEGATE_P_H + +#include <QtCore/QTimer> +#include <QtNetwork/QNetworkReply> + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * This is read-only currently. + */ + class QIODeviceDelegate : public QNetworkReply + { + Q_OBJECT + public: + QIODeviceDelegate(QIODevice *const source); + + virtual void abort(); + + virtual bool atEnd() const; + virtual qint64 bytesAvailable() const; + virtual qint64 bytesToWrite() const; + virtual bool canReadLine() const; + virtual void close(); + virtual bool isSequential() const; + virtual bool open(OpenMode mode); + virtual qint64 pos() const; + virtual bool reset(); + virtual bool seek(qint64 pos); + virtual qint64 size() const; + virtual bool waitForBytesWritten(int msecs); + virtual bool waitForReadyRead(int msecs); + + protected: + virtual qint64 readData(char *data, qint64 maxSize); + + private Q_SLOTS: + void networkTimeout(); + private: + enum + { + /** + * 20 seconds expressed in milliseconds. + */ + Timeout = 20000 + }; + + QIODevice *const m_source; + QTimer m_timeout; + }; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/xmlpatterns/api/qnetworkaccessdelegator.cpp b/src/xmlpatterns/api/qnetworkaccessdelegator.cpp new file mode 100644 index 0000000..05c4b8e --- /dev/null +++ b/src/xmlpatterns/api/qnetworkaccessdelegator.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QUrl> + +#include <QNetworkAccessManager> + +#include "qnetworkaccessdelegator_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +NetworkAccessDelegator::NetworkAccessDelegator(QNetworkAccessManager *const genericManager, + QNetworkAccessManager *const variableURIManager) : m_genericManager(genericManager) + , m_variableURIManager(variableURIManager) +{ +} + +QNetworkAccessManager *NetworkAccessDelegator::managerFor(const QUrl &uri) +{ + /* Unfortunately we have to do it this way, QUrl::isParentOf() doesn't + * understand URI schemes like this one. */ + const QString requestedUrl(uri.toString()); + + /* On the topic of timeouts: + * + * Currently the schemes QNetworkAccessManager handles should/will do + * timeouts for 4.4, but we need to do timeouts for our own. */ + if(requestedUrl.startsWith(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:"))) + return m_variableURIManager; + else + { + if(!m_genericManager) + m_genericManager = new QNetworkAccessManager(this); + + return m_genericManager; + } +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qnetworkaccessdelegator_p.h b/src/xmlpatterns/api/qnetworkaccessdelegator_p.h new file mode 100644 index 0000000..10c229a --- /dev/null +++ b/src/xmlpatterns/api/qnetworkaccessdelegator_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QNETWORKACCESSDELEGATOR_P_H +#define QNETWORKACCESSDELEGATOR_P_H + +#include <QObject> +#include <QPointer> +#include <QSharedData> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +class QNetworkAccessManager; +class QUrl; + +namespace QPatternist +{ + /** + * @short A value based class that hands out QNetworkAccessManager + * appropriately for variable bindings. + * + * NetworkAccessDelegator is an indirection mechanism which takes care of + * the fact that QIODevice instances are injected into the data model by + * having them represented using a URI. managerFor() returns appropriately + * the right network access manager depending on whether the URI refers to + * a variable, or to something else. + * + * The constructor take a pointer to two NetworkAccessDelegator instances. + * First is a generic one, the second is the one which handles variable + * bindings. managerFor() then returns the appropriate one depending on the + * URI. + * + * @since 4.5 + * @see AccelTreeResourceLoader::load() + * @author Frans Englich <frans.englich@nokia.com> + */ + class Q_AUTOTEST_EXPORT NetworkAccessDelegator : public QObject + , public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<NetworkAccessDelegator> Ptr; + NetworkAccessDelegator(QNetworkAccessManager *const genericManager, + QNetworkAccessManager *const variableURIManager); + + QNetworkAccessManager *managerFor(const QUrl &uri); + + QPointer<QNetworkAccessManager> m_genericManager; + QPointer<QNetworkAccessManager> m_variableURIManager; + private: + Q_DISABLE_COPY(NetworkAccessDelegator) + }; +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qpullbridge.cpp b/src/xmlpatterns/api/qpullbridge.cpp new file mode 100644 index 0000000..80dac38 --- /dev/null +++ b/src/xmlpatterns/api/qpullbridge.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QVariant> + +#include "qabstractxmlnodemodel_p.h" +#include "qitemmappingiterator_p.h" +#include "qitem_p.h" +#include "qxmlname.h" +#include "qxmlquery_p.h" + +#include "qpullbridge_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +/*! + \brief Bridges a QPatternist::SequenceIterator to QAbstractXmlPullProvider. + \class QPatternist::PullBridge + \internal + \reentrant + \ingroup xml-tools + + The approach of this class is rather straight forward since QPatternist::SequenceIterator + and QAbstractXmlPullProvider are conceptually similar. While QPatternist::SequenceIterator only + delivers top level items(since it's not an event stream, it's a list of items), PullBridge + needs to recursively iterate the children of nodes too, which is achieved through the + stack m_iterators. + */ + +AbstractXmlPullProvider::Event PullBridge::next() +{ + m_index = m_iterators.top().second->next(); + + if(!m_index.isNull()) + { + Item item(m_index); + + if(item && item.isAtomicValue()) + m_current = AtomicValue; + else + { + Q_ASSERT(item.isNode()); + + switch(m_index.kind()) + { + case QXmlNodeModelIndex::Attribute: + { + m_current = Attribute; + break; + } + case QXmlNodeModelIndex::Comment: + { + m_current = Comment; + break; + } + case QXmlNodeModelIndex::Element: + { + m_iterators.push(qMakePair(StartElement, m_index.iterate(QXmlNodeModelIndex::AxisChild))); + m_current = StartElement; + break; + } + case QXmlNodeModelIndex::Document: + { + m_iterators.push(qMakePair(StartDocument, m_index.iterate(QXmlNodeModelIndex::AxisChild))); + m_current = StartDocument; + break; + } + case QXmlNodeModelIndex::Namespace: + { + m_current = Namespace; + break; + } + case QXmlNodeModelIndex::ProcessingInstruction: + { + m_current = ProcessingInstruction; + break; + } + case QXmlNodeModelIndex::Text: + { + m_current = Text; + break; + } + } + } + } + else + { + if(m_iterators.isEmpty()) + m_current = EndOfInput; + else + { + switch(m_iterators.top().first) + { + case StartOfInput: + { + m_current = EndOfInput; + break; + } + case StartElement: + { + m_current = EndElement; + m_iterators.pop(); + break; + } + case StartDocument: + { + m_current = EndDocument; + m_iterators.pop(); + break; + } + default: + { + Q_ASSERT_X(false, Q_FUNC_INFO, + "Invalid value."); + m_current = EndOfInput; + } + } + } + + } + + return m_current; +} + +AbstractXmlPullProvider::Event PullBridge::current() const +{ + return m_current; +} + +QXmlNodeModelIndex PullBridge::index() const +{ + return m_index; +} + +QSourceLocation PullBridge::sourceLocation() const +{ + return m_index.model()->sourceLocation(m_index); +} + +QXmlName PullBridge::name() const +{ + return m_index.name(); +} + +QVariant PullBridge::atomicValue() const +{ + return QVariant(); +} + +QString PullBridge::stringValue() const +{ + return QString(); +} + +QHash<QXmlName, QString> PullBridge::attributes() +{ + Q_ASSERT(m_current == StartElement); + + QHash<QXmlName, QString> attributes; + + QXmlNodeModelIndex::Iterator::Ptr it = m_index.iterate(QXmlNodeModelIndex::AxisAttribute); + QXmlNodeModelIndex index = it->next(); + while (!index.isNull()) { + const Item attribute(index); + attributes.insert(index.name(), index.stringValue()); + + index = it->next(); + } + + return attributes; +} + +QHash<QXmlName, QXmlItem> PullBridge::attributeItems() +{ + Q_ASSERT(m_current == StartElement); + + QHash<QXmlName, QXmlItem> attributes; + + QXmlNodeModelIndex::Iterator::Ptr it = m_index.iterate(QXmlNodeModelIndex::AxisAttribute); + QXmlNodeModelIndex index = it->next(); + while (!index.isNull()) { + const Item attribute(index); + attributes.insert(index.name(), QXmlItem(index)); + + index = it->next(); + } + + return attributes; +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qpullbridge_p.h b/src/xmlpatterns/api/qpullbridge_p.h new file mode 100644 index 0000000..1553a3e --- /dev/null +++ b/src/xmlpatterns/api/qpullbridge_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef PATTERNIST_PULLBRIDGE_P_H +#define PATTERNIST_PULLBRIDGE_P_H + +#include <QtCore/QPair> +#include <QtCore/QStack> + +#include "qabstractxmlforwarditerator_p.h" +#include "qabstractxmlpullprovider_p.h" +#include "qitem_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class PullBridge : public AbstractXmlPullProvider + { + public: + inline PullBridge(const QXmlNodeModelIndex::Iterator::Ptr &it) : m_current(StartOfInput) + { + Q_ASSERT(it); + m_iterators.push(qMakePair(StartOfInput, it)); + } + + virtual Event next(); + virtual Event current() const; + virtual QXmlName name() const; + /** + * Returns always an empty QVariant. + */ + virtual QVariant atomicValue() const; + virtual QString stringValue() const; + virtual QHash<QXmlName, QString> attributes(); + virtual QHash<QXmlName, QXmlItem> attributeItems(); + + QXmlNodeModelIndex index() const; + QSourceLocation sourceLocation() const; + + private: + typedef QStack<QPair<Event, QXmlNodeModelIndex::Iterator::Ptr> > IteratorStack; + IteratorStack m_iterators; + QXmlNodeModelIndex m_index; + Event m_current; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qreferencecountedvalue_p.h b/src/xmlpatterns/api/qreferencecountedvalue_p.h new file mode 100644 index 0000000..679660c --- /dev/null +++ b/src/xmlpatterns/api/qreferencecountedvalue_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QPatternist_ReferenceCountedValue_p_h +#define QPatternist_ReferenceCountedValue_p_h + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ +/*! + \class ReferenceCountedValue + \internal + \since 4.4 + \brief A template class that reference counts a value. + + This class is useful when an instance needs to have ownership semantics + as if it was value based. A typical examples is a QObject pointer, which + doesn't have a single owner. + + This is achieved through storing a copy of the object as + a member inside ReferenceCountedValue, which never is copied. It will + stay in scope until the last reference to the ReferenceCountedValue instance + is removed, and subsequently ReferenceCountedValue is deleted and hence also + the contained value. One should use ReferenceCountedValue by passing around + copies of Ptr, which is a typedef for the QExplicitlySharedDataPointer + smart pointer. +*/ + template<typename T> + class ReferenceCountedValue : public QSharedData + { + public: + typedef QExplicitlySharedDataPointer<ReferenceCountedValue<T> > Ptr; + + inline ReferenceCountedValue(T *const v) : value(v) + { + } + + inline ~ReferenceCountedValue() + { + delete value; + } + + T *const value; + private: + /*! + Disabled, no implementation provided. + */ + inline ReferenceCountedValue(); + Q_DISABLE_COPY(ReferenceCountedValue) + }; +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qresourcedelegator.cpp b/src/xmlpatterns/api/qresourcedelegator.cpp new file mode 100644 index 0000000..cb78666 --- /dev/null +++ b/src/xmlpatterns/api/qresourcedelegator.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qresourcedelegator_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +bool ResourceDelegator::isUnparsedTextAvailable(const QUrl &uri, + const QString &encoding) +{ + return m_parentLoader->isUnparsedTextAvailable(uri, encoding); +} + +ItemType::Ptr ResourceDelegator::announceUnparsedText(const QUrl &uri) +{ + return m_parentLoader->announceUnparsedText(uri); +} + +Item ResourceDelegator::openUnparsedText(const QUrl &uri, + const QString &encoding, + const ReportContext::Ptr &context, + const SourceLocationReflection *const where) +{ + return m_parentLoader->openUnparsedText(uri, encoding, context, where); +} + +Item ResourceDelegator::openDocument(const QUrl &uri, + const ReportContext::Ptr &context) +{ + if(m_needsOverride.contains(uri)) + return m_forDeviceLoader->openDocument(uri, context); + else + return m_parentLoader->openDocument(uri, context); +} + +SequenceType::Ptr ResourceDelegator::announceDocument(const QUrl &uri, const Usage usageHint) +{ + return m_parentLoader->announceDocument(uri, usageHint); +} + +bool ResourceDelegator::isDocumentAvailable(const QUrl &uri) +{ + return m_parentLoader->isDocumentAvailable(uri); +} + +Item::Iterator::Ptr ResourceDelegator::openCollection(const QUrl &uri) +{ + return m_parentLoader->openCollection(uri); +} + +SequenceType::Ptr ResourceDelegator::announceCollection(const QUrl &uri) +{ + return m_parentLoader->announceCollection(uri); +} + +QSet<QUrl> ResourceDelegator::deviceURIs() const +{ + QSet<QUrl> uris(m_needsOverride); + uris |= m_forDeviceLoader->deviceURIs(); + return uris; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qresourcedelegator_p.h b/src/xmlpatterns/api/qresourcedelegator_p.h new file mode 100644 index 0000000..688a23f --- /dev/null +++ b/src/xmlpatterns/api/qresourcedelegator_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QPatternist_ResourceDelegator_p_H +#define QPatternist_ResourceDelegator_p_H + +#include <QSet> +#include <QUrl> + +#include "qdeviceresourceloader_p.h" + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + /** + * @short Delegates to another ResourceLoader, but in case a URI is in an + * exception list, it delegates to a different loader. + * + * This is used for handling device variables, since when a device variable + * is rebound, a resource loader needs to carry that binding, while the + * resource loader for the other query remains as is. + * + * @since 4.5 + * @author Frans Englich <frans.englich@nokia.com> + */ + class ResourceDelegator : public DeviceResourceLoader + { + public: + ResourceDelegator(const QSet<QUrl> &needsOverride, + const ResourceLoader::Ptr &parentLoader, + const ResourceLoader::Ptr &forDeviceLoader) : m_needsOverride(needsOverride) + , m_parentLoader(parentLoader) + , m_forDeviceLoader(forDeviceLoader) + + { + Q_ASSERT(m_parentLoader); + } + + virtual bool isUnparsedTextAvailable(const QUrl &uri, + const QString &encoding); + virtual ItemType::Ptr announceUnparsedText(const QUrl &uri); + virtual Item openUnparsedText(const QUrl &uri, + const QString &encoding, + const ReportContext::Ptr &context, + const SourceLocationReflection *const where); + virtual Item openDocument(const QUrl &uri, + const ReportContext::Ptr &context); + virtual SequenceType::Ptr announceDocument(const QUrl &uri, const Usage usageHint); + virtual bool isDocumentAvailable(const QUrl &uri); + virtual Item::Iterator::Ptr openCollection(const QUrl &uri); + virtual SequenceType::Ptr announceCollection(const QUrl &uri); + + /** + * Returns the union of the deviceURIs() that ResourceDelegator's two + * resource loaders has. + */ + virtual QSet<QUrl> deviceURIs() const; + + private: + const QSet<QUrl> m_needsOverride; + const ResourceLoader::Ptr m_parentLoader; + const ResourceDelegator::Ptr m_forDeviceLoader; + }; +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qsimplexmlnodemodel.cpp b/src/xmlpatterns/api/qsimplexmlnodemodel.cpp new file mode 100644 index 0000000..40f99e5 --- /dev/null +++ b/src/xmlpatterns/api/qsimplexmlnodemodel.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QUrl> +#include <QVector> +#include <QXmlNamePool> + +#include "qabstractxmlnodemodel_p.h" +#include "qemptyiterator_p.h" +#include "qitemmappingiterator_p.h" +#include "qsequencemappingiterator_p.h" +#include "qsimplexmlnodemodel.h" +#include "qsingletoniterator_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +class QSimpleXmlNodeModelPrivate : public QAbstractXmlNodeModelPrivate +{ +public: + QSimpleXmlNodeModelPrivate(const QXmlNamePool &np) : namePool(np) + { + } + + mutable QXmlNamePool namePool; +}; + +/*! + \class QSimpleXmlNodeModel + \brief The QSimpleXmlNodeModel class is an implementation of QAbstractXmlNodeModel sufficient for many common cases. + \reentrant + \since 4.4 + \ingroup xml-tools + + Subclassing QAbstractXmlNodeModel can be a significant task, because it + requires implementing several, complex member functions. QSimpleXmlNodeModel + provides default implementations of these member functions that are suitable + for a wide range of node models. + + Subclasses of QSimpleXmlNodeModel must be thread-safe. + */ + +/*! + Constructs a QSimpleXmlNodeModel for use with with the specified + \a namePool. + */ +QSimpleXmlNodeModel::QSimpleXmlNodeModel(const QXmlNamePool &namePool) + : QAbstractXmlNodeModel(new QSimpleXmlNodeModelPrivate(namePool)) +{ +} + +/*! + Destructor. + */ +QSimpleXmlNodeModel::~QSimpleXmlNodeModel() +{ +} + +/*! + If \a node is an element or attribute, typedValue() is called, and + the return value converted to a string, as per XQuery's rules. + + If \a node is another type of node, the empty string is returned. + + If this function is overridden for comments or processing + instructions, it is important to remember to call it (for elements + and attributes having values not of type \c xs:string) to ensure that + the values are formatted according to XQuery. + + */ +QString QSimpleXmlNodeModel::stringValue(const QXmlNodeModelIndex &node) const +{ + const QXmlNodeModelIndex::NodeKind k= kind(node); + if(k == QXmlNodeModelIndex::Element || k == QXmlNodeModelIndex::Attribute) + { + const QVariant &candidate = typedValue(node); + if(candidate.isNull()) + return QString(); + else + return AtomicValue::toXDM(candidate).stringValue(); + } + else + return QString(); +} + +/*! + Returns the base URI for \a node. This is always the document + URI. + + \sa documentUri() + */ +QUrl QSimpleXmlNodeModel::baseUri(const QXmlNodeModelIndex &node) const +{ + return documentUri(node); +} + +/*! + Returns the name pool associated with this model. The + implementation of name() will use this name pool to create + names. + */ +QXmlNamePool &QSimpleXmlNodeModel::namePool() const +{ + Q_D(const QSimpleXmlNodeModel); + + return d->namePool; +} + +/*! + Always returns an empty QVector. This signals that no namespace + bindings are in scope for \a node. + */ +QVector<QXmlName> QSimpleXmlNodeModel::namespaceBindings(const QXmlNodeModelIndex &node) const +{ + Q_UNUSED(node); + return QVector<QXmlName>(); +} + +/*! + Always returns a default constructed QXmlNodeModelIndex instance, + regardless of \a id. + + This effectively means the model has no elements that have an id. + */ +QXmlNodeModelIndex QSimpleXmlNodeModel::elementById(const QXmlName &id) const +{ + Q_UNUSED(id); + return QXmlNodeModelIndex(); +} + +/*! + Always returns an empty vector, regardless of \a idref. + + This effectively means the model has no elements or attributes of + type \c IDREF. + */ +QVector<QXmlNodeModelIndex> QSimpleXmlNodeModel::nodesByIdref(const QXmlName &idref) const +{ + Q_UNUSED(idref); + return QVector<QXmlNodeModelIndex>(); +} + +QT_END_NAMESPACE + + diff --git a/src/xmlpatterns/api/qsimplexmlnodemodel.h b/src/xmlpatterns/api/qsimplexmlnodemodel.h new file mode 100644 index 0000000..cfbe360 --- /dev/null +++ b/src/xmlpatterns/api/qsimplexmlnodemodel.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLEXMLNODEMODEL_H +#define QSIMPLEXMLNODEMODEL_H + +#include <QtXmlPatterns/QAbstractXmlNodeModel> +#include <QtXmlPatterns/QXmlQuery> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +template<typename T> class QExplicitlySharedDataPointer; +class QSimpleXmlNodeModelPrivate; +class Q_XMLPATTERNS_EXPORT QSimpleXmlNodeModel : public QAbstractXmlNodeModel +{ +public: + QSimpleXmlNodeModel(const QXmlNamePool &namePool); + virtual ~QSimpleXmlNodeModel(); + + virtual QUrl baseUri(const QXmlNodeModelIndex &node) const; + QXmlNamePool &namePool() const; + virtual QVector<QXmlName> namespaceBindings(const QXmlNodeModelIndex&) const; + virtual QString stringValue(const QXmlNodeModelIndex &node) const; + virtual QXmlNodeModelIndex elementById(const QXmlName &id) const; + virtual QVector<QXmlNodeModelIndex> nodesByIdref(const QXmlName &idref) const; + +private: + Q_DECLARE_PRIVATE(QSimpleXmlNodeModel) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qsourcelocation.cpp b/src/xmlpatterns/api/qsourcelocation.cpp new file mode 100644 index 0000000..392d84c --- /dev/null +++ b/src/xmlpatterns/api/qsourcelocation.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdebug_p.h" + +#include "qsourcelocation.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QSourceLocation + \reentrant + \since 4.4 + \brief The QSourceLocation class identifies a location in a resource by URI, line, and column. + \ingroup xml-tools + + QSourceLocation is a simple value based class that has three + properties, uri(), line(), and column(), that, taken together, + identify a certain point in a resource, e.g., a file or an in-memory + document. + + line() and column() refer to character counts (not byte counts), and + they both start from 1, as opposed to 0. + */ + +/*! + Construct a QSourceLocation that doesn't identify anything at all. + + For a default constructed QSourceLocation(), isNull() returns \c true. + */ +QSourceLocation::QSourceLocation() : m_line(-1), m_column(-1) +{ +} + +/*! + Constructs a QSourceLocation that is a copy of \a other. + */ +QSourceLocation::QSourceLocation(const QSourceLocation &other) + : m_line(other.m_line), m_column(other.m_column), m_uri(other.m_uri) +{ +} + +/*! + Constructs a QSourceLocation with URI \a u, line \a l and column \a c. + */ +QSourceLocation::QSourceLocation(const QUrl &u, int l, int c) + : m_line(l), m_column(c), m_uri(u) +{ +} + +/*! + Destructor. + */ +QSourceLocation::~QSourceLocation() +{ +} + +/*! + Returns true if this QSourceLocation is identical to \a other. + + Two QSourceLocation instances are equal if their uri(), line() and + column() are equal. + + QSourceLocation instances for which isNull() returns true are + considered equal. + */ +bool QSourceLocation::operator==(const QSourceLocation &other) const +{ + return m_line == other.m_line + && m_column == other.m_column + && m_uri == other.m_uri; +} + +/*! + Returns the opposite of applying operator==() for this QXmlName + and \a other. + */ +bool QSourceLocation::operator!=(const QSourceLocation &other) const +{ + return operator==(other); +} + +/*! + Assigns this QSourceLocation instance to \a other. + */ +QSourceLocation &QSourceLocation::operator=(const QSourceLocation &other) +{ + if(this != &other) + { + m_line = other.m_line; + m_column = other.m_column; + m_uri = other.m_uri; + } + + return *this; +} + +/*! + Returns the current column number. The column number refers to the + count of characters, not bytes. The first column is column 1, not 0. + The default value is -1, indicating the column number is unknown. + */ +qint64 QSourceLocation::column() const +{ + return m_column; +} + +/*! + Sets the column number to \a newColumn. 0 is an invalid column + number. The first column number is 1. + */ +void QSourceLocation::setColumn(qint64 newColumn) +{ + Q_ASSERT_X(newColumn != 0, Q_FUNC_INFO, + "0 is an invalid column number. The first column number is 1."); + m_column = newColumn; +} + +/*! + Returns the current line number. The first line number is 1, not 0. + The default value is -1, indicating the line number is unknown. + */ +qint64 QSourceLocation::line() const +{ + return m_line; +} + +/*! + Sets the line number to \a newLine. 0 is an invalid line + number. The first line number is 1. + */ +void QSourceLocation::setLine(qint64 newLine) +{ + m_line = newLine; +} + +/*! + Returns the resource that this QSourceLocation refers to. For + example, the resource could be a file in the local file system, + if the URI scheme is \c file. + */ +QUrl QSourceLocation::uri() const +{ + return m_uri; +} + +/*! + Sets the URI to \a newUri. + */ +void QSourceLocation::setUri(const QUrl &newUri) +{ + m_uri = newUri; +} + +/*! + \relates QSourceLocation + \since 4.4 + + Prints \a sourceLocation to the debug stream \a debug. + */ +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QSourceLocation &sourceLocation) +{ + debug << "QSourceLocation(" + << sourceLocation.uri() + << ", line:" + << sourceLocation.line() + << ", column:" + << sourceLocation.column() + << ')'; + return debug; +} +#endif + +/*! + Returns \c true if this QSourceLocation doesn't identify anything. + + For a default constructed QSourceLocation, this function returns \c + true. The same applies for any other QSourceLocation whose uri() is + invalid. + */ +bool QSourceLocation::isNull() const +{ + return !m_uri.isValid(); +} + +/*! + \since 4.4 + + Computes a hash key for the QSourceLocation \a location. + + \relates QSourceLocation + */ +uint qHash(const QSourceLocation &location) +{ + /* Not the world's best hash function exactly. */ + return qHash(location.uri().toString()) + location.line() + location.column(); +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qsourcelocation.h b/src/xmlpatterns/api/qsourcelocation.h new file mode 100644 index 0000000..80184fd --- /dev/null +++ b/src/xmlpatterns/api/qsourcelocation.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOURCELOCATION_H +#define QSOURCELOCATION_H + +#include <QtCore/QMetaType> +#include <QtCore/QUrl> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QSourceLocationPrivate; + +class Q_XMLPATTERNS_EXPORT QSourceLocation +{ +public: + QSourceLocation(); + QSourceLocation(const QSourceLocation &other); + QSourceLocation(const QUrl &uri, int line = -1, int column = -1); + ~QSourceLocation(); + QSourceLocation &operator=(const QSourceLocation &other); + bool operator==(const QSourceLocation &other) const; + bool operator!=(const QSourceLocation &other) const; + + qint64 column() const; + void setColumn(qint64 newColumn); + + qint64 line() const; + void setLine(qint64 newLine); + + QUrl uri() const; + void setUri(const QUrl &newUri); + bool isNull() const; + +private: + union + { + qint64 m_line; + QSourceLocationPrivate *m_ptr; + }; + qint64 m_column; + QUrl m_uri; +}; + +Q_XMLPATTERNS_EXPORT uint qHash(const QSourceLocation &location); + +#ifndef QT_NO_DEBUG_STREAM +Q_XMLPATTERNS_EXPORT QDebug operator<<(QDebug debug, const QSourceLocation &sourceLocation); +#endif + +Q_DECLARE_TYPEINFO(QSourceLocation, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QSourceLocation) /* This macro must appear after QT_END_NAMESPACE. */ + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/quriloader.cpp b/src/xmlpatterns/api/quriloader.cpp new file mode 100644 index 0000000..b8cb104 --- /dev/null +++ b/src/xmlpatterns/api/quriloader.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtNetwork/QNetworkRequest> +#include <QtNetwork/QNetworkReply> + +#include "qiodevicedelegate_p.h" +#include "quriloader_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +URILoader::URILoader(QObject *const parent, + const NamePool::Ptr &np, + const VariableLoader::Ptr &l) : QNetworkAccessManager(parent) + , m_variableNS(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:")) + , m_namePool(np) + , m_variableLoader(l) +{ + Q_ASSERT(m_variableLoader); +} + +QNetworkReply *URILoader::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData) +{ + const QString requestedUrl(req.url().toString()); + + /* We got a QIODevice variable. */ + const QString name(requestedUrl.right(requestedUrl.length() - m_variableNS.length())); + + const QVariant variant(m_variableLoader->valueFor(m_namePool->allocateQName(QString(), name, QString()))); + + if(!variant.isNull() && variant.userType() == qMetaTypeId<QIODevice *>()) + return new QIODeviceDelegate(qvariant_cast<QIODevice *>(variant)); + else + { + /* If we're entering this code path, the variable URI identified a variable + * which we don't have, which means we either have a bug, or the user had + * crafted an invalid URI manually. */ + + return QNetworkAccessManager::createRequest(op, req, outgoingData); + } +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/quriloader_p.h b/src/xmlpatterns/api/quriloader_p.h new file mode 100644 index 0000000..eaaca5f --- /dev/null +++ b/src/xmlpatterns/api/quriloader_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QURILOADER_P_H +#define QURILOADER_P_H + +#include <QtNetwork/QNetworkAccessManager> +#include <QtXmlPatterns/QXmlName> + +#include "qnamepool_p.h" +#include "qvariableloader_p.h" + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class URILoader : public QNetworkAccessManager + { + public: + URILoader(QObject *const parent, + const NamePool::Ptr &np, + const VariableLoader::Ptr &variableLoader); + + virtual QNetworkReply *createRequest(Operation op, + const QNetworkRequest & req, + QIODevice *outgoingData = 0); + + private: + const QString m_variableNS; + const NamePool::Ptr m_namePool; + const VariableLoader::Ptr m_variableLoader; + + }; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/xmlpatterns/api/qvariableloader.cpp b/src/xmlpatterns/api/qvariableloader.cpp new file mode 100644 index 0000000..9909508 --- /dev/null +++ b/src/xmlpatterns/api/qvariableloader.cpp @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QVariant> +#include <QStringList> + +#include "qanyuri_p.h" +#include "qatomicstring_p.h" +#include "qbuiltintypes_p.h" +#include "qcommonsequencetypes_p.h" +#include "qgenericsequencetype_p.h" +#include "qinteger_p.h" +#include "qitem_p.h" +#include "qsequencetype_p.h" +#include "qvariableloader_p.h" +#include "qxmlquery_p.h" + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + + class VariantListIterator : public ListIteratorPlatform<QVariant, Item, VariantListIterator> + { + public: + inline VariantListIterator(const QVariantList &list) : ListIteratorPlatform<QVariant, Item, VariantListIterator>(list) + { + } + + private: + friend class ListIteratorPlatform<QVariant, Item, VariantListIterator>; + + inline Item inputToOutputItem(const QVariant &inputType) const + { + return AtomicValue::toXDM(inputType); + } + }; + + class StringListIterator : public ListIteratorPlatform<QString, Item, StringListIterator> + { + public: + inline StringListIterator(const QStringList &list) : ListIteratorPlatform<QString, Item, StringListIterator>(list) + { + } + + private: + friend class ListIteratorPlatform<QString, Item, StringListIterator>; + + static inline Item inputToOutputItem(const QString &inputType) + { + return AtomicString::fromValue(inputType); + } + }; + + /** + * Takes two DynamicContext instances, and redirects the storage of temporary trees + * to one of them. + * + * @since 4.5 + */ + class TemporaryTreesRedirectingContext : public DelegatingDynamicContext + { + public: + TemporaryTreesRedirectingContext(const DynamicContext::Ptr &other, + const DynamicContext::Ptr &modelStorage) : DelegatingDynamicContext(other) + , m_modelStorage(modelStorage) + { + Q_ASSERT(m_modelStorage); + } + + virtual void addNodeModel(const QAbstractXmlNodeModel::Ptr &nodeModel) + { + m_modelStorage->addNodeModel(nodeModel); + } + + private: + const DynamicContext::Ptr m_modelStorage; + }; +} + +using namespace QPatternist; + +SequenceType::Ptr VariableLoader::announceExternalVariable(const QXmlName name, + const SequenceType::Ptr &declaredType) +{ + Q_UNUSED(declaredType); + const QVariant &variant = m_bindingHash.value(name); + + + if(variant.isNull()) + return SequenceType::Ptr(); + else if(variant.userType() == qMetaTypeId<QIODevice *>()) + return CommonSequenceTypes::ExactlyOneAnyURI; + else if(variant.userType() == qMetaTypeId<QXmlQuery>()) + { + const QXmlQuery variableQuery(qvariant_cast<QXmlQuery>(variant)); + return variableQuery.d->expression()->staticType(); + } + else + { + return makeGenericSequenceType(AtomicValue::qtToXDMType(qvariant_cast<QXmlItem>(variant)), + Cardinality::exactlyOne()); + } +} + +Item::Iterator::Ptr VariableLoader::evaluateSequence(const QXmlName name, + const DynamicContext::Ptr &context) +{ + + const QVariant &variant = m_bindingHash.value(name); + Q_ASSERT_X(!variant.isNull(), Q_FUNC_INFO, + "We assume that we have a binding."); + + /* Same code as in the default clause below. */ + if(variant.userType() == qMetaTypeId<QIODevice *>()) + return makeSingletonIterator(itemForName(name)); + else if(variant.userType() == qMetaTypeId<QXmlQuery>()) + { + const QXmlQuery variableQuery(qvariant_cast<QXmlQuery>(variant)); + + return variableQuery.d->expression()->evaluateSequence(DynamicContext::Ptr(new TemporaryTreesRedirectingContext(variableQuery.d->dynamicContext(), context))); + } + + const QVariant v(qvariant_cast<QXmlItem>(variant).toAtomicValue()); + + switch(v.type()) + { + case QVariant::StringList: + return Item::Iterator::Ptr(new StringListIterator(v.toStringList())); + case QVariant::List: + return Item::Iterator::Ptr(new VariantListIterator(v.toList())); + default: + return makeSingletonIterator(itemForName(name)); + } +} + +Item VariableLoader::itemForName(const QXmlName &name) const +{ + const QVariant &variant = m_bindingHash.value(name); + + if(variant.userType() == qMetaTypeId<QIODevice *>()) + return Item(AnyURI::fromValue(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + m_namePool->stringForLocalName(name.localName()))); + + const QXmlItem item(qvariant_cast<QXmlItem>(variant)); + + if(item.isNode()) + return Item::fromPublic(item); + else + { + const QVariant atomicValue(item.toAtomicValue()); + /* If the atomicValue is null it means it doesn't exist in m_bindingHash, and therefore it must + * be a QIODevice, since Patternist guarantees to only ask for variables that announceExternalVariable() + * has accepted. */ + if(atomicValue.isNull()) + return Item(AnyURI::fromValue(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + m_namePool->stringForLocalName(name.localName()))); + else + return AtomicValue::toXDM(atomicValue); + } +} + +Item VariableLoader::evaluateSingleton(const QXmlName name, + const DynamicContext::Ptr &) +{ + return itemForName(name); +} + +bool VariableLoader::isSameType(const QVariant &v1, + const QVariant &v2) const +{ + /* Are both of type QIODevice *? */ + if(v1.userType() == qMetaTypeId<QIODevice *>() && v1.userType() == v2.userType()) + return true; + + /* Ok, we have two QXmlItems. */ + const QXmlItem i1(qvariant_cast<QXmlItem>(v1)); + const QXmlItem i2(qvariant_cast<QXmlItem>(v2)); + + if(i1.isNode()) + { + Q_ASSERT(false); + return false; + } + else if(i2.isAtomicValue()) + return i1.toAtomicValue().type() == i2.toAtomicValue().type(); + else + { + /* One is an atomic, the other is a node or they are null. */ + return false; + } +} + +void VariableLoader::removeBinding(const QXmlName &name) +{ + m_bindingHash.remove(name); +} + +bool VariableLoader::hasBinding(const QXmlName &name) const +{ + return m_bindingHash.contains(name) + || (m_previousLoader && m_previousLoader->hasBinding(name)); +} + +QVariant VariableLoader::valueFor(const QXmlName &name) const +{ + if(m_bindingHash.contains(name)) + return m_bindingHash.value(name); + else if(m_previousLoader) + return m_previousLoader->valueFor(name); + else + return QVariant(); +} + +void VariableLoader::addBinding(const QXmlName &name, + const QVariant &value) +{ + m_bindingHash.insert(name, value); +} + +bool VariableLoader::invalidationRequired(const QXmlName &name, + const QVariant &variant) const +{ + return hasBinding(name) && !isSameType(valueFor(name), variant); +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qvariableloader_p.h b/src/xmlpatterns/api/qvariableloader_p.h new file mode 100644 index 0000000..cf050cb --- /dev/null +++ b/src/xmlpatterns/api/qvariableloader_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef PATTERNIST_VARIABLELOADER_P_H +#define PATTERNIST_VARIABLELOADER_P_H + +#include <QtCore/QSet> +#include <QtXmlPatterns/QXmlQuery> +#include <QtDebug> + +#include "qdynamiccontext_p.h" +#include "qexternalvariableloader_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class VariableLoader : public ExternalVariableLoader + { + public: + typedef QHash<QXmlName, QVariant> BindingHash; + typedef QExplicitlySharedDataPointer<VariableLoader> Ptr; + + inline VariableLoader(const NamePool::Ptr &np, + const VariableLoader::Ptr &previousLoader = VariableLoader::Ptr()) : m_namePool(np) + , m_previousLoader(previousLoader) + + { + } + + virtual QPatternist::SequenceType::Ptr announceExternalVariable(const QXmlName name, + const QPatternist::SequenceType::Ptr &declaredType); + virtual QPatternist::Item::Iterator::Ptr evaluateSequence(const QXmlName name, + const QPatternist::DynamicContext::Ptr &); + + virtual QPatternist::Item evaluateSingleton(const QXmlName name, + const QPatternist::DynamicContext::Ptr &); + + void removeBinding(const QXmlName &name); + bool hasBinding(const QXmlName &name) const; + QVariant valueFor(const QXmlName &name) const; + void addBinding(const QXmlName &name, + const QVariant &value); + + bool isSameType(const QVariant &v1, + const QVariant &v2) const; + + bool invalidationRequired(const QXmlName &name, + const QVariant &variant) const; + + private: + + inline QPatternist::Item itemForName(const QXmlName &name) const; + + const NamePool::Ptr m_namePool; + VariableLoader::Ptr m_previousLoader; + BindingHash m_bindingHash; + }; +} + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QIODevice *) +Q_DECLARE_METATYPE(QXmlQuery) + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlformatter.cpp b/src/xmlpatterns/api/qxmlformatter.cpp new file mode 100644 index 0000000..0925fe5 --- /dev/null +++ b/src/xmlpatterns/api/qxmlformatter.cpp @@ -0,0 +1,338 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtDebug> + +#include "qxmlformatter.h" +#include "qxpathhelper_p.h" +#include "qxmlserializer_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +class QXmlFormatterPrivate : public QXmlSerializerPrivate +{ +public: + inline QXmlFormatterPrivate(const QXmlQuery &q, + QIODevice *const outputDevice); + + int indentationDepth; + int currentDepth; + QString characterBuffer; + QString indentString; + + /** + * Whether we /have/ sent nodes like processing instructions and comments + * to QXmlSerializer. + */ + QStack<bool> canIndent; +}; + +QXmlFormatterPrivate::QXmlFormatterPrivate(const QXmlQuery &query, + QIODevice *const outputDevice) : QXmlSerializerPrivate(query, outputDevice) + , indentationDepth(4) + , currentDepth(0) +{ + indentString.reserve(30); + indentString.resize(1); + indentString[0] = QLatin1Char('\n'); + canIndent.push(false); +} + +/*! + \class QXmlFormatter + \brief The QXmlFormatter class is an implementation of QXmlSerializer for transforming XQuery output into formatted XML. + \reentrant + \since 4.4 + \ingroup xml-tools + + QXmlFormatter is a subclass of QXmlSerializer that formats the XML + output to make it easier for humans to read. + + QXmlSerializer outputs XML without adding unnecessary whitespace. + In particular, it does not add \e {newlines} and indentation. + To make the XML output easier to read, QXmlFormatter adds \e{newlines} + and indentation by adding, removing, and modifying + \l{XQuery Sequence}{sequence nodes} that only consist of whitespace. + It also modifies whitespace in other places where it is not + significant; e.g., between attributes and in the document prologue. + + For example, where the base class QXmlSerializer would + output this: + + \quotefile doc/src/snippets/patternist/notIndented.xml + + QXmlFormatter outputs this: + + \quotefile doc/src/snippets/patternist/indented.xml + + If you just want to serialize your XML in a human-readable + format, use QXmlFormatter as it is. The default indentation + level is 4 spaces, but you can set your own indentation value + setIndentationDepth(). + + The \e{newlines} and indentation added by QXmlFormatter are + suitable for common formats, such as XHTML, SVG, or Docbook, + where whitespace is not significant. However, if your XML will + be used as input where whitespace is significant, then you must + write your own subclass of QXmlSerializer or QAbstractXmlReceiver. + + Note that using QXmlFormatter instead of QXmlSerializer will + increase computational overhead and document storage size due + to the insertion of whitespace. + + Note also that the indentation style used by QXmlFormatter + remains loosely defined and may change in future versions of + Qt. If a specific indentation style is required then either + use the base class QXmlSerializer directly, or write your own + subclass of QXmlSerializer or QAbstractXmlReceiver. + Alternatively, you can subclass QXmlFormatter and reimplement + the callbacks there. + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlformatter.cpp 0 +*/ + +/*! + Constructs a formatter that uses the name pool and message + handler in \a query, and writes the result to \a outputDevice + as formatted XML. + + \a outputDevice is passed directly to QXmlSerializer's constructor. + + \sa QXmlSerializer + */ +QXmlFormatter::QXmlFormatter(const QXmlQuery &query, + QIODevice *outputDevice) : QXmlSerializer(new QXmlFormatterPrivate(query, outputDevice)) +{ +} + +/*! + \internal + */ +void QXmlFormatter::startFormattingContent() +{ + Q_D(QXmlFormatter); + + if(QPatternist::XPathHelper::isWhitespaceOnly(d->characterBuffer)) + { + if(d->canIndent.top()) + QXmlSerializer::characters(QStringRef(&d->indentString)); + } + else + { + if(!d->characterBuffer.isEmpty()) /* Significant data, we don't touch it. */ + QXmlSerializer::characters(QStringRef(&d->characterBuffer)); + } + + d->characterBuffer.clear(); +} + +/*! + \reimp + */ +void QXmlFormatter::startElement(const QXmlName &name) +{ + Q_D(QXmlFormatter); + startFormattingContent(); + ++d->currentDepth; + d->indentString.append(QString(d->indentationDepth, QLatin1Char(' '))); + d->canIndent.push(true); + + QXmlSerializer::startElement(name); +} + +/*! + \reimp + */ +void QXmlFormatter::endElement() +{ + Q_D(QXmlFormatter); + --d->currentDepth; + d->indentString.chop(d->indentationDepth); + + if(!d->hasClosedElement.top().second) + d->canIndent.top() = false; + + startFormattingContent(); + + d->canIndent.pop(); + d->canIndent.top() = true; + QXmlSerializer::endElement(); +} + +/*! + \reimp + */ +void QXmlFormatter::attribute(const QXmlName &name, + const QStringRef &value) +{ + QXmlSerializer::attribute(name, value); +} + +/*! + \reimp + */ +void QXmlFormatter::comment(const QString &value) +{ + Q_D(QXmlFormatter); + startFormattingContent(); + QXmlSerializer::comment(value); + d->canIndent.top() = true; +} + +/*! + \reimp + */ +void QXmlFormatter::characters(const QStringRef &value) +{ + Q_D(QXmlFormatter); + d->isPreviousAtomic = false; + d->characterBuffer += value.toString(); +} + +/*! + \reimp + */ +void QXmlFormatter::processingInstruction(const QXmlName &name, + const QString &value) +{ + Q_D(QXmlFormatter); + startFormattingContent(); + QXmlSerializer::processingInstruction(name, value); + d->canIndent.top() = true; +} + +/*! + \reimp + */ +void QXmlFormatter::atomicValue(const QVariant &value) +{ + Q_D(QXmlFormatter); + d->canIndent.top() = false; + QXmlSerializer::atomicValue(value); +} + +/*! + \reimp + */ +void QXmlFormatter::startDocument() +{ + QXmlSerializer::startDocument(); +} + +/*! + \reimp + */ +void QXmlFormatter::endDocument() +{ + QXmlSerializer::endDocument(); +} + +/*! + \reimp + */ +void QXmlFormatter::startOfSequence() +{ + QXmlSerializer::startOfSequence(); +} + +/*! + \reimp + */ +void QXmlFormatter::endOfSequence() +{ + Q_D(QXmlFormatter); + + /* Flush any buffered content. */ + if(!d->characterBuffer.isEmpty()) + QXmlSerializer::characters(QStringRef(&d->characterBuffer)); + + d->write('\n'); + QXmlSerializer::endOfSequence(); +} + +/*! + \internal + */ +void QXmlFormatter::item(const QPatternist::Item &item) +{ + Q_D(QXmlFormatter); + + if(item.isAtomicValue()) + { + if(QPatternist::XPathHelper::isWhitespaceOnly(item.stringValue())) + return; + else + { + d->canIndent.top() = false; + startFormattingContent(); + } + } + + QXmlSerializer::item(item); +} + +/*! + Returns the number of spaces QXmlFormatter will output for each + indentation level. The default is four. + + \sa setIndentationDepth() + */ +int QXmlFormatter::indentationDepth() const +{ + Q_D(const QXmlFormatter); + return d->indentationDepth; +} + +/*! + Sets \a depth to be the number of spaces QXmlFormatter will + output for level of indentation. The default is four. + + \sa indentationDepth() + */ +void QXmlFormatter::setIndentationDepth(int depth) +{ + Q_D(QXmlFormatter); + d->indentationDepth = depth; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlformatter.h b/src/xmlpatterns/api/qxmlformatter.h new file mode 100644 index 0000000..8ad3aa2 --- /dev/null +++ b/src/xmlpatterns/api/qxmlformatter.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLFORMATTER_H +#define QXMLFORMATTER_H + +#include <QtXmlPatterns/QXmlSerializer> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QIODevice; +class QTextCodec; +class QXmlQuery; +class QXmlFormatterPrivate; + +class Q_XMLPATTERNS_EXPORT QXmlFormatter : public QXmlSerializer +{ +public: + QXmlFormatter(const QXmlQuery &query, + QIODevice *outputDevice); + + virtual void characters(const QStringRef &value); + virtual void comment(const QString &value); + virtual void startElement(const QXmlName &name); + virtual void endElement(); + + virtual void attribute(const QXmlName &name, + const QStringRef &value); + virtual void processingInstruction(const QXmlName &name, + const QString &value); + virtual void atomicValue(const QVariant &value); + virtual void startDocument(); + virtual void endDocument(); + virtual void startOfSequence(); + virtual void endOfSequence(); + + int indentationDepth() const; + void setIndentationDepth(int depth); + + /* The members below are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ + virtual void item(const QPatternist::Item &item); +private: + inline void startFormattingContent(); + Q_DECLARE_PRIVATE(QXmlFormatter) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlname.cpp b/src/xmlpatterns/api/qxmlname.cpp new file mode 100644 index 0000000..8ff7411 --- /dev/null +++ b/src/xmlpatterns/api/qxmlname.cpp @@ -0,0 +1,511 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * QXmlName is conceptually identical to QPatternist::QName. The + * difference is that the latter is elegant, powerful and fast. + * + * However, it is too powerful and too open and not at all designed + * for being public. QXmlName, in contrast, is only a public marker, + * that for instance uses a qint64 instead of qint32, such that we in + * the future can use that, if needed. + */ + +#include "qnamepool_p.h" +#include "qxmlname.h" +#include "qxmlnamepool.h" +#include "qxpathhelper_p.h" +#include "private/qxmlutils_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QXmlName + \brief The QXmlName class represents the name of an XML node, in an efficient, namespace-aware way. + \reentrant + \since 4.4 + \ingroup xml-tools + + QXmlName represents the name of an XML node in a way that + is both efficient and safe for comparing names. Normally, + an XML node represents an XML element or attribute, but + QXmlName can also represent the names of other kinds of + nodes, e.g., QAbstractXmlReceiver::processingInstruction() + and QAbstractXmlReceiver::namespaceBinding(). + + The name of an XML node has three components: The \e {namespace + URI}, the \e {local name}, and the \e {prefix}. To see what these + refer to in XML, consider the following snippet. + + \quotefile doc/src/snippets/patternist/mobeyDick.xml + + For the element named \e book, localName() returns \e book, + namespaceUri() returns \e http://example.com/MyDefault, + and prefix() returns an empty string. For the element named + \e title, localName() returns \e title, namespaceUri() returns + \e http://purl.org/dc/elements/1.1, and prefix() returns \e dc. + + To ensure that operations with QXmlName are efficient, e.g., + copying names and comparing them, each instance of QXmlName is + associated with a \l {QXmlNamePool} {name pool}, which must be + specified at QXmlName construction time. The three components + of the QXmlName, i.e., the namespace URI, the local name, and + the prefix, are stored in the name pool mapped to identifiers + so they can be shared. For this reason, the only way to create + a valid instance of QXmlName is to use the class constructor, + where the \l {QXmlNamePool} {name pool}, local name, namespace + URI, and prefix must all be specified. + + Note that QXmlName's default constructor constructs a null + instance. It is typically used for allocating unused entries + in collections of QXmlName. + + A side effect of associating each instance of QXmlName with + a \l {QXmlNamePool} {name pool} is that each instance of + QXmlName is tied to the QXmlNamePool with which it was created. + However, the QXmlName class does not keep track of the name pool, + so all the accessor functions, e.g., namespaceUri(), prefix(), + localName(), and toClarkName() require that the correct name + pool be passed to them. Failure to provide the correct name + pool to these accessor functions results in undefined behavior. + + Note that a \l {QXmlNamePool} {name pool} is \e not an XML + namespace. One \l {QXmlNamePool} {name pool} can represent + instances of QXmlName from different XML namespaces, and the + instances of QXmlName from one XML namespace can be distributed + over multiple \l {QXmlNamePool} {name pools}. + + \target Comparing QXmlNames + \section1 Comparing QXmlNames + + To determine what a QXmlName refers to, the \e {namespace URI} + and the \e {local name} are used. The \e prefix is not used + because the prefix is simply a shorthand name for use in place + of the normally much longer namespace URI. Nor is the prefix + used in name comparisons. For example, the following two element + nodes represent the same element and compare equal. + + \quotefile doc/src/snippets/patternist/svgDocumentElement.xml + + \quotefile doc/src/snippets/patternist/xsvgDocumentElement.xml + + Although the second name has the prefix \e x, the two names compare + equal as instances of QXmlName, because the prefix is not used in + the comparison. + + A local name can never be an empty string, although the prefix and + namespace URI can. If the prefix is not empty, the namespace URI + cannot be empty. Local names and prefixes must be valid + \l {http://www.w3.org/TR/REC-xml-names/#NT-NCName} {NCNames}, + e.g., \e abc.def or \e abc123. + + QXmlName represents what is sometimes called an \e {expanded QName}, + or simply a QName. + + \sa {http://www.w3.org/TR/REC-xml-names/#NT-NCName} {Namespaces in XML 1.0 (Second Edition), [4] NCName} + */ + +/*! + \enum QXmlName::Constant + \internal + Various constants used in the QPatternist::NamePool and QXmlName. + + Setting of the mask enums use essentially this: + + \quotefile doc/src/snippets/code/src_xmlpatterns_api_qxmlname.cpp + + The masks, such as LocalNameMask, are positive. That is, for the + area which the name resides, the bits are set. + */ + +/*! + Constructs a QXmlName instance that inserts \a localName, + \a namespaceURI and \a prefix into \a namePool if they aren't + already there. The accessor functions namespaceUri(), prefix(), + localName(), and toClarkName() must be passed the \a namePool + used here, so the \a namePool must remain in scope while the + accessor functions might be used. However, two instances can + be compared with \e {==} or \e {!=} and copied without the + \a namePool. + + The user guarantees that the string components are valid for a + QName. In particular, the local name, and the prefix (if present), + must be valid \l {http://www.w3.org/TR/REC-xml-names/#NT-NCName} + {NCNames}. The function isNCName() can be used to test validity + of these names. The namespace URI should be an absolute URI. + QUrl::isRelative() can be used to test whether the namespace URI + is relative or absolute. Finally, providing a prefix is not valid + when no namespace URI is provided. + + \a namePool is not copied. Nor is the reference to it retained + in this instance. This constructor inserts the three strings + into \a namePool. + */ +QXmlName::QXmlName(QXmlNamePool &namePool, + const QString &localName, + const QString &namespaceURI, + const QString &prefix) +{ + Q_ASSERT_X(prefix.isEmpty() || QXmlUtils::isNCName(prefix), Q_FUNC_INFO, + "The prefix is invalid, maybe the arguments were mixed up?"); + Q_ASSERT_X(QXmlUtils::isNCName(localName), Q_FUNC_INFO, + "The local name is invalid, maybe the arguments were mixed up?"); + + m_qNameCode = namePool.d->allocateQName(namespaceURI, localName, prefix).code(); +} + +/*! + \typedef QXmlName::Code + \internal + + Stores the \l {QXmlNamePool} {name pool} identifiers for + the namespace URI, local name, and prefix. + */ + +/*! + Returns true if this QXmlName is not initialized with a + valid combination of \e {namespace URI}, \e {local name}, + and \e {prefix}. + + A valid local name is always required. The prefix and + namespace URI can be empty, but if the prefix is not empty, + the namespace URI must not be empty. Local names and + prefixes must be valid + \l {http://www.w3.org/TR/REC-xml-names/#NT-NCName} {NCNames}, + e.g., \e abc.def or \e abc123. + */ +bool QXmlName::isNull() const +{ + return m_qNameCode == InvalidCode; +} + +/*! + Constructs an uninitialized QXmlName. To build + a valid QXmlName, you normally use the other constructor, which + takes a \l {QXmlNamePool} {name pool}, namespace URI, local name, + and prefix as parameters. But you can also use this constructor + to build a null QXmlName and then assign an existing QXmlName + to it. + + \sa isNull() + */ +QXmlName::QXmlName() : m_qNameCode(InvalidCode) +{ +} + +/*! + \fn QXmlName::QXmlName(const NamespaceCode uri, + const LocalNameCode ln, + const PrefixCode p = 0) + \internal + */ + +/*! + \fn QXmlName::hasPrefix() const + \internal + + Returns true if this QXmlName has a non-empty prefix. If this + function returns true, hasNamespace() will also return true, + because a QXmlName can't have a prefix if it doesn't have a + namespace URI. + */ + +/*! + \fn bool QXmlName::hasNamespace() const + \internal + + Returns true if this QXmlName has a non-empty namespace URI. + */ + +/*! + \fn Code QXmlName::code() const + \internal + + Returns the internal code that contains the id codes for the + local name, prefix and namespace URI. It is opaque when used + outside QXmlName, but it can be useful when one wants to put + a QXmlName in a hash, and the prefix is significant. + */ + +/*! + Returns true if this QXmlName is equal to \a other; otherwise false. + Two QXmlNames are equal if their namespace URIs are the same \e and + their local names are the same. The prefixes are ignored. + + Note that it is meaningless to compare two instances of QXmlName + that were created with different \l {QXmlNamePool} {name pools}, + but the attempt is not detected and the behavior is undefined. + + \sa operator!=() + */ +bool QXmlName::operator==(const QXmlName &other) const +{ + return (m_qNameCode & ExpandedNameMask) == (other.m_qNameCode & ExpandedNameMask); +} + +/*! + Returns true if this QXmlName is \e not equal to \a other; + otherwise false. Two QXmlNames are equal if their namespace + URIs are the same \e and their local names are the same. They + are not equal if either their namespace URIs differ or their + local names differ. Their prefixes are ignored. + + Note that it is meaningless to compare two instances of QXmlName + that were created with different \l {QXmlNamePool} {name pools}, + but the attempt is not detected and the behavior is undefined. + + \sa operator==() + */ +bool QXmlName::operator!=(const QXmlName &other) const +{ + return !operator==(other); +} + +/*! + \fn bool QXmlName::isLexicallyEqual(const QXmlName &other) const + \internal + + Returns true if this and \a other are lexically equal. Two + QXmlNames are lexically equal if their local names are equal + \e and their prefixes are equal. + */ + +/*! + \fn uint qHash(const QXmlName &name) + \since 4.4 + \relates QXmlName + + Computes a hash key from the local name and the namespace + URI in \a name. The prefix in \a name is not used in the computation. + */ +uint qHash(const QXmlName &name) +{ + return name.m_qNameCode & QXmlName::ExpandedNameMask; +} + +/*! + Returns the namespace URI. + + Note that for efficiency, the namespace URI string is not + stored in the QXmlName but in the \l {QXmlNamePool} that was + passed to the constructor. Hence, that same \a namePool must + be passed to this function, so it can be used for looking up + the namespace URI. + */ +QString QXmlName::namespaceUri(const QXmlNamePool &namePool) const +{ + if(isNull()) + return QString(); + else + return namePool.d->stringForNamespace(namespaceURI()); +} + +/*! + Returns the prefix. + + Note that for efficiency, the prefix string is not stored in + the QXmlName but in the \l {QXmlNamePool} that was passed to + the constructor. Hence, that same \a namePool must be passed + to this function, so it can be used for looking up the prefix. + */ +QString QXmlName::prefix(const QXmlNamePool &namePool) const +{ + if(isNull()) + return QString(); + else + return namePool.d->stringForPrefix(prefix()); +} + +/*! + Returns the local name. + + Note that for efficiency, the local name string is not stored + in the QXmlName but in the \l {QXmlNamePool} that was passed to + the constructor. Hence, that same \a namePool must be passed + to this function, so it can be used for looking up the + local name. + */ +QString QXmlName::localName(const QXmlNamePool &namePool) const +{ + if(isNull()) + return QString(); + else + return namePool.d->stringForLocalName(localName()); +} + +/*! + Returns this QXmlName formatted as a Clark Name. For example, + if the local name is \c html, the prefix is \c x, and the + namespace URI is \c {http://www.w3.org/1999/xhtml/}, + then the Clark Name returned is: + + \code + {http://www.w3.org/1999/xhtml/}x:html. + \endcode + + If the local name is \e {MyWidget} and the namespace is empty, + the Clark Name returned is: + + \code + MyWidget + \endcode + + Note that for efficiency, the namespace URI, local name, and + prefix strings are not stored in the QXmlName but in the + \l {QXmlNamePool} that was passed to the constructor. Hence, + that same \a namePool must be passed to this function, so it + can be used for looking up the three string components. + + This function can be useful for debugging. + + \sa {http://www.jclark.com/xml/xmlns.htm} {XML Namespaces, James Clark} + \sa fromClarkName() + */ +QString QXmlName::toClarkName(const QXmlNamePool &namePool) const +{ + return namePool.d->toClarkName(*this); +} + +/*! + Assigns \a other to \e this and returns \e this. + */ +QXmlName &QXmlName::operator=(const QXmlName &other) +{ + m_qNameCode = other.m_qNameCode; + return *this; +} + +/*! + Returns true if \a candidate is an \c NCName. An \c NCName + is a string that can be used as a name in XML and XQuery, + e.g., the prefix or local name in an element or attribute, + or the name of a variable. + + \sa {http://www.w3.org/TR/REC-xml-names/#NT-NCName} {Namespaces in XML 1.0 (Second Edition), [4] NCName} + */ +bool QXmlName::isNCName(const QString &candidate) +{ + return QXmlUtils::isNCName(candidate); +} + +/*! + Converts \a clarkName into a QXmlName, inserts into \a namePool, and + returns it. + + A clark name is a way to present a full QName with only one string, where + the namespace cannot contain braces. Here are a couple of examples: + + \table + \header + \o Clark Name + \o Description + \row + \o \c html + \o The local name \c html, in no namespace + \row + \o \c {http://www.w3.org/1999/xhtml}html + \o The local name \c html, in the XHTML namespace + \row + \o \c {http://www.w3.org/1999/xhtml}my:html + \o The local name \c html, in the XHTML namespace, with the prefix \c my + \endtable + + If the namespace contains braces, the returned value is either invalid or + has undefined content. + + If \a clarkName is an invalid name, a default constructed QXmlName is + returned. + + \since 4.5 + \sa toClarkName() + */ +QXmlName QXmlName::fromClarkName(const QString &clarkName, + const QXmlNamePool &namePool) +{ + return namePool.d->fromClarkName(clarkName); +} + +/*! + \typedef QXmlName::LocalNameCode + \internal + */ + +/*! + \typedef QXmlName::PrefixCode + \internal + */ + +/*! + \typedef QXmlName::NamespaceCode + \internal + */ + +/*! + \fn void QXmlName::setLocalName(const LocalNameCode c) + \internal +*/ + +/*! + \fn LocalNameCode QXmlName::localName() const + \internal +*/ + +/*! + \fn PrefixCode QXmlName::prefix() const + \internal +*/ + +/*! + \fn NamespaceCode QXmlName::namespaceURI() const + \internal +*/ + +/*! + \fn void QXmlName::setNamespaceURI(const NamespaceCode c) + \internal +*/ + +/*! + \fn void QXmlName::setPrefix(const PrefixCode c) + \internal +*/ +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qxmlname.h b/src/xmlpatterns/api/qxmlname.h new file mode 100644 index 0000000..8350302 --- /dev/null +++ b/src/xmlpatterns/api/qxmlname.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLNAME_H +#define QXMLNAME_H + +#include <QtCore/QString> +#include <QtCore/QMetaType> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QXmlName; +class QXmlNamePool; +Q_XMLPATTERNS_EXPORT uint qHash(const QXmlName &name); + +class Q_XMLPATTERNS_EXPORT QXmlName +{ +private: + enum Constant + { + LocalNameOffset = 0, + LocalNameLength = 12, + NamespaceOffset = LocalNameLength, + NamespaceLength = 9, + PrefixLength = 9, + InvalidCode = 1 << 31, + NamespaceMask = ((1 << ((NamespaceOffset + NamespaceLength) - NamespaceOffset)) - 1) << NamespaceOffset, + LocalNameMask = ((1 << ((LocalNameOffset + LocalNameLength) - LocalNameOffset)) - 1) << LocalNameOffset, + PrefixOffset = LocalNameLength + NamespaceLength, + PrefixMask = ((1 << ((PrefixOffset + PrefixLength) - PrefixOffset)) - 1) << PrefixOffset, + MaximumPrefixes = (PrefixMask >> PrefixOffset) - 1, + MaximumLocalNames = (LocalNameMask >> LocalNameOffset) - 1, + MaximumNamespaces = (NamespaceMask >> NamespaceOffset) - 1, + ExpandedNameMask = LocalNameMask | NamespaceMask, + LexicalQNameMask = LocalNameMask | PrefixMask + }; + +public: + + typedef qint16 NamespaceCode; + typedef NamespaceCode PrefixCode; + typedef NamespaceCode LocalNameCode; + + QXmlName(); + + QXmlName(QXmlNamePool &namePool, + const QString &localName, + const QString &namespaceURI = QString(), + const QString &prefix = QString()); + + QString namespaceUri(const QXmlNamePool &query) const; + QString prefix(const QXmlNamePool &query) const; + QString localName(const QXmlNamePool &query) const; + QString toClarkName(const QXmlNamePool &query) const; + bool operator==(const QXmlName &other) const; + bool operator!=(const QXmlName &other) const; + QXmlName &operator=(const QXmlName &other); + bool isNull() const; + static bool isNCName(const QString &candidate); + static QXmlName fromClarkName(const QString &clarkName, + const QXmlNamePool &namePool); + + /* The members below are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ + typedef qint64 Code; + + inline QXmlName(const NamespaceCode uri, + const LocalNameCode ln, + const PrefixCode p = 0); + /* The implementation for these functions are in utils/qnamepool_p.h. */ + inline LocalNameCode localName() const; + inline PrefixCode prefix() const; + inline bool hasPrefix() const; + inline bool hasNamespace() const; + inline NamespaceCode namespaceURI() const; + inline bool isLexicallyEqual(const QXmlName &other) const; + inline void setPrefix(const PrefixCode c); + inline void setNamespaceURI(const NamespaceCode c); + inline void setLocalName(const LocalNameCode c); + inline Code code() const; + + friend Q_XMLPATTERNS_EXPORT uint qHash(const QXmlName &); + +private: + inline QXmlName(const int c) : m_qNameCode(c) + { + } + + Code m_qNameCode; +}; + +Q_DECLARE_TYPEINFO(QXmlName, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QXmlName) /* This macro must appear after QT_END_NAMESPACE. */ + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlnamepool.cpp b/src/xmlpatterns/api/qxmlnamepool.cpp new file mode 100644 index 0000000..bd1f67f --- /dev/null +++ b/src/xmlpatterns/api/qxmlnamepool.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnamepool_p.h" +#include "qxmlnamepool.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QXmlNamePool + \brief The QXmlNamePool class is a table of shared strings referenced by instances of QXmlName. + \reentrant + \since 4.4 + \ingroup xml-tools + + QXmlNamePool is used to optimize operations on instances of + QXmlName. An instance of QXmlName represents an XML name in + a way that allows the XML name to be compared and passed around + efficiently. The efficiency is achieved by storing the strings + comprising the XML names in an instance of QXmlNamePool, where + they are mapped to binary identifiers, which are then packed + into a key which is stored in the QXmlName. + + This means that each instance of QXmlName is tied to the name + pool it was created with, and that name pool should be kept in + scope and used to create all instances of QXmlName that might + be compared. Note also that the name pool is required if you + must reconstitute the QXmlName as text, or if you must access + any of its component strings, so although instances of + QXmlName can be compared without reference to a name pool, the + name pool must be kept in scope if the name's strings must be + accessed later. + + \sa QXmlName + \sa QXmlQuery::namePool() + */ + +/*! + Constructs an empty name pool. + */ +QXmlNamePool::QXmlNamePool() : d(new QPatternist::NamePool()) +{ +} + +/*! + Constructs a copy of the \a other name pool. + */ +QXmlNamePool::QXmlNamePool(const QXmlNamePool &other) : d(other.d) +{ +} + +/*! + Destroys the name pool. Instances of QXmlName constructed + with this name pool can still be compared after this destructor + is called, but their text strings cannot be accessed. + */ +QXmlNamePool::~QXmlNamePool() +{ +} + +QXmlNamePool::QXmlNamePool(QPatternist::NamePool *namePool) : d(QExplicitlySharedDataPointer<QPatternist::NamePool>(namePool)) +{ +} + +/*! + Assigns the \a other name pool to this one. + */ +QXmlNamePool &QXmlNamePool::operator=(const QXmlNamePool &other) +{ + d = other.d; + return *this; +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qxmlnamepool.h b/src/xmlpatterns/api/qxmlnamepool.h new file mode 100644 index 0000000..df9285c --- /dev/null +++ b/src/xmlpatterns/api/qxmlnamepool.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLNAMEPOOL_H +#define QXMLNAMEPOOL_H + +#include <QtCore/QSharedData> +#include <QtCore/QString> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +namespace QPatternist +{ + class NamePool; + class XsdSchemaParser; + class XsdValidatingInstanceReader; +} + +namespace QPatternistSDK +{ + class Global; +} + +class QXmlQueryPrivate; +class QXmlName; + +class Q_XMLPATTERNS_EXPORT QXmlNamePool +{ +public: + QXmlNamePool(); + QXmlNamePool(const QXmlNamePool &other); + ~QXmlNamePool(); + QXmlNamePool &operator=(const QXmlNamePool &other); + +private: + QXmlNamePool(QPatternist::NamePool *namePool); + friend class QXmlQueryPrivate; + friend class QXmlQuery; + friend class QXmlSchemaPrivate; + friend class QXmlSchemaValidatorPrivate; + friend class QXmlSerializerPrivate; + friend class QXmlName; + friend class QPatternist::XsdSchemaParser; + friend class QPatternist::XsdValidatingInstanceReader; + friend class QPatternistSDK::Global; + QExplicitlySharedDataPointer<QPatternist::NamePool> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlpatternistcli_p.h b/src/xmlpatterns/api/qxmlpatternistcli_p.h new file mode 100644 index 0000000..328adcf --- /dev/null +++ b/src/xmlpatterns/api/qxmlpatternistcli_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the XMLPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_Cli_h +#define Patternist_Cli_h + +#include <QCoreApplication> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlPatternistCLI +{ +public: + Q_DECLARE_TR_FUNCTIONS(QXmlPatternistCLI) +private: + inline QXmlPatternistCLI(); + Q_DISABLE_COPY(QXmlPatternistCLI) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlquery.cpp b/src/xmlpatterns/api/qxmlquery.cpp new file mode 100644 index 0000000..d74a536 --- /dev/null +++ b/src/xmlpatterns/api/qxmlquery.cpp @@ -0,0 +1,1209 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QBuffer> +#include <QtCore/QStringList> +#include <QtXmlPatterns/QXmlFormatter> + +#include "qacceltreeresourceloader_p.h" +#include "qcommonvalues_p.h" +#include "qxmlresultitems.h" +#include "qxmlresultitems_p.h" +#include "qxmlserializer.h" +#include "qxpathhelper_p.h" + +#include "qxmlquery.h" +#include "qxmlquery_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QXmlQuery + + \brief The QXmlQuery class performs XQueries on XML data, or on non-XML data modeled to look like XML. + + \reentrant + \since 4.4 + \ingroup xml-tools + + The QXmlQuery class compiles and executes queries written in the + \l {http://www.w3.org/TR/xquery/}{XQuery language}. QXmlQuery is + typically used to query XML data, but it can also query non-XML + data that has been modeled to look like XML. + + Using QXmlQuery to query XML data, as in the snippet below, is + simple because it can use the built-in \l {QAbstractXmlNodeModel} + {XML data model} as its delegate to the underlying query engine for + traversing the data. The built-in data model is specified in \l + {http://www.w3.org/TR/xpath-datamodel/} {XQuery 1.0 and XPath 2.0 + Data Model}. + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qabstractxmlreceiver.cpp 0 + + The example uses QXmlQuery to match the first paragraph of an XML + document and then \l {QXmlSerializer} {output the result} to a + device as XML. + + Using QXmlQuery to query \e {non-XML} data requires writing a + subclass of QAbstractXmlNodeModel to use as a replacement for the + built-in XML data model. The custom data model will be able to + traverse the non-XML data as required by the QAbstractXmlNodeModel + interface. An instance of this custom data model then becomes the + delegate used by the query engine to traverse the non-XML data. For + an example of how to use QXmlQuery to query non-XML data, see the + documentation for QAbstractXmlNodeModel. + + \section1 Running XQueries + + To run a query set up with QXmlQuery, call one of the evaluation + functions. + + \list + + \o evaluateTo(QAbstractXmlReceiver *) is called with a pointer to an + XML \l {QAbstractXmlReceiver} {receiver}, which receives the query + results as a sequence of callbacks. The receiver callback class is + like the callback class used for translating the output of a SAX + parser. QXmlSerializer, for example, is a receiver callback class + for translating the sequence of callbacks for output as unformatted + XML text. + + \endlist + + \list + + \o evaluateTo(QXmlResultItems *) is called with a pointer to an + iterator for an empty sequence of query \l {QXmlResultItems} {result + items}. The Java-like iterator allows the query results to be + accessed sequentially. + + \endlist + + \list + + \o evaluateTo(QStringList *) is like evaluateTo(QXmlResultItems *), + but the query must evaluate to a sequence of strings. + + \endlist + + \section1 Running XPath Expressions + + The XPath language is a subset of the XQuery language, so + running an XPath expression is the same as running an XQuery + query. Pass the XPath expression to QXmlQuery using setQuery(). + + \section1 Running XSLT stylesheets + + Running an XSLT stylesheet is like running an XQuery, except that + when you construct your QXmlQuery, you must pass QXmlQuery::XSLT20 + to tell QXmlQuery to interpret whatever it gets from setQuery() as + an XSLT stylesheet instead of as an XQuery. You must also set the + input document by calling setFocus(). + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlquery.cpp 7 + + \note Currently, setFocus() must be called \e before setQuery() when + using XSLT. + + Another way to run an XSLT stylesheet is to use the \c xmlpatterns + command line utility. + + \code + xmlpatterns myStylesheet.xsl myInput.xml + \endcode + + \note For the current release, XSLT support should be considered + experimental. See section \l{XQuery#XSLT 2.0} {XSLT conformance} for + details. + + Stylesheet parameters are bound using bindVariable(). + + \section1 Binding A Query To A Starting Node + + When a query is run on XML data, as in the snippet above, the + \c{doc()} function returns the node in the built-in data model where + the query evaluation will begin. But when a query is run on a custom + node model containing non-XML data, one of the bindVariable() + functions must be called to bind a variable name to a starting node + in the custom model. A $variable reference is used in the XQuery + text to access the starting node in the custom model. It is not + necessary to declare the variable name external in the query. See + the example in the documentation for QAbstractXmlNodeModel. + + \section1 Reentrancy and Thread-Safety + + QXmlQuery is reentrant but not thread-safe. It is safe to use the + QxmlQuery copy constructor to create a copy of a query and run the + same query multiple times. Behind the scenes, QXmlQuery will reuse + resources such as opened files and compiled queries to the extent + possible. But it is not safe to use the same instance of QXmlQuery + in multiple threads. + + \section1 Error Handling + + Errors can occur during query evaluation. Examples include type + errors and file loading errors. When an error occurs: + + \list + + \o The error message is sent to the messageHandler(). + + \o QXmlResultItems::hasError() will return \c{true}, or + evaluateTo() will return \c{false}; + + \o The results of the evaluation are undefined. + + \endlist + + \section1 Resource Management + + When a query runs, it parses documents, allocating internal data + structures to hold them, and it may load other resources over the + network. It reuses these allocated resources when possible, to + avoid having to reload and reparse them. + + When setQuery() is called, the query text is compiled into an + internal data structure and optimized. The optimized form can + then be reused for multiple evaluations of the query. Since the + compile-and-optimize process can be expensive, repeating it for + the same query should be avoided by using a separate instance of + QXmlQuery for each query text. + + Once a document has been parsed, its internal representation is + maintained in the QXmlQuery instance and shared among multiple + QXmlQuery instances. + + An instance of QCoreApplication must exist before QXmlQuery can be + used. + + \section1 Event Handling + + When QXmlQuery accesses resources (e.g., calling \c fn:doc() to load a file, + or accessing a device via a bound variable), the event loop is used, which + means events will be processed. To avoid processing events when QXmlQuery + accesses resources, create your QXmlQuery instance in a separate thread. + */ + +/*! + \enum QXmlQuery::QueryLanguage + \since 4.5 + + Specifies whether you want QXmlQuery to interpret the input to + setQuery() as an XQuery or as an XSLT stylesheet. + + \value XQuery10 XQuery 1.0. + \value XSLT20 XSLT 2.0 + \omitvalue XmlSchema11IdentityConstraintSelector The selector, the restricted + XPath pattern found in W3C XML Schema 1.1 for uniqueness + contraints. Apart from restricting the syntax, the type check stage + for the expression assumes a sequence of nodes to be the focus. + \omitvalue XmlSchema11IdentityConstraintField The field, the restricted + XPath pattern found in W3C XML Schema 1.1 for uniqueness + contraints. Apart from restricting the syntax, the type check stage + for the expression assumes a sequence of nodes to be the focus. + \omitvalue XPath20 Signifies XPath 2.0. Has no effect in the public API, it's + used internally. As With XmlSchema11IdentityConstraintSelector and + XmlSchema11IdentityConstraintField, the type check stage + for the expression assumes a sequence of nodes to be the focus. + + \sa setQuery() + */ + +// ### Qt5: Merge constructor overloads +/*! + Constructs an invalid, empty query that cannot be used until + setQuery() is called. + + \note This constructor must not be used if you intend to use + this QXmlQuery to process XSL-T stylesheets. The other constructor + must be used in that case. + */ +QXmlQuery::QXmlQuery() : d(new QXmlQueryPrivate()) +{ +} + +/*! + Constructs a QXmlQuery that is a copy of \a other. The new + instance will share resources with the existing query + to the extent possible. + */ +QXmlQuery::QXmlQuery(const QXmlQuery &other) : d(new QXmlQueryPrivate(*other.d)) +{ + /* First we have invoked QXmlQueryPrivate's synthesized copy constructor. + * Keep this section in sync with QXmlQuery::operator=(). */ + d->detach(); +} + +/*! + Constructs a query that will use \a np as its name pool. The query + cannot be evaluated until setQuery() has been called. + */ +QXmlQuery::QXmlQuery(const QXmlNamePool &np) : d(new QXmlQueryPrivate(np)) +{ +} + +/*! + + Constructs a query that will be used to run Xqueries or XSL-T + stylesheets, depending on the value of \a queryLanguage. It will use + \a np as its name pool. + + \note If your QXmlQuery will process XSL-T stylesheets, this + constructor must be used. The default constructor can only + create instances of QXmlQuery for running XQueries. + + \note The XSL-T support in this release is considered experimental. + See the \l{XQuery#XSLT 2.0} {XSLT conformance} for details. + + \since 4.5 + \sa queryLanguage() + */ +QXmlQuery::QXmlQuery(QueryLanguage queryLanguage, + const QXmlNamePool &np) : d(new QXmlQueryPrivate(np)) +{ + d->queryLanguage = queryLanguage; +} + +/*! + Destroys this QXmlQuery. + */ +QXmlQuery::~QXmlQuery() +{ + delete d; +} + +/*! + Assigns \a other to this QXmlQuery instance. + */ +QXmlQuery &QXmlQuery::operator=(const QXmlQuery &other) +{ + /* Keep this section in sync with QXmlQuery::QXmlQuery(const QXmlQuery &). + */ + if(d != other.d) + { + *d = *other.d; + d->detach(); + } + + return *this; +} + +/*! + Changes the \l {QAbstractMessageHandler}{message handler} for this + QXmlQuery to \a aMessageHandler. The query sends all compile and + runtime messages to this message handler. QXmlQuery does not take + ownership of \a aMessageHandler. + + Normally, the default message handler is sufficient. It writes + compile and runtime messages to \e stderr. The default message + handler includes color codes if \e stderr can render colors. + + Note that changing the message handler after the query has been + compiled has no effect, i.e. the query uses the same message handler + at runtime that it uses at compile time. + + When QXmlQuery calls QAbstractMessageHandler::message(), + the arguments are as follows: + + \table + \header + \o message() argument + \o Semantics + \row + \o QtMsgType type + \o Only QtWarningMsg and QtFatalMsg are used. The former + identifies a compile or runtime warning, while the + latter identifies a dynamic or static error. + \row + \o const QString & description + \o An XHTML document which is the actual message. It is translated + into the current language. + \row + \o const QUrl &identifier + \o Identifies the error with a URI, where the fragment is + the error code, and the rest of the URI is the error namespace. + \row + \o const QSourceLocation & sourceLocation + \o Identifies where the error occurred. + \endtable + + */ +void QXmlQuery::setMessageHandler(QAbstractMessageHandler *aMessageHandler) +{ + d->messageHandler = aMessageHandler; +} + +/*! + Returns the message handler that handles compile and runtime + messages for this QXmlQuery. + */ +QAbstractMessageHandler *QXmlQuery::messageHandler() const +{ + return d->messageHandler; +} + +/*! + Sets this QXmlQuery to an XQuery read from the \a sourceCode + device. The device must have been opened with at least + QIODevice::ReadOnly. + + \a documentURI represents the query obtained from the \a sourceCode + device. It is the base URI of the static context, as defined in the + \l {http://www.w3.org/TR/xquery/}{XQuery language}. It is used + internally to resolve relative URIs that appear in the query, and + for message reporting. \a documentURI can be empty. If it is empty, + the \l{QCoreApplication::applicationFilePath()} {application file + path} is used. If it is not empty, it may be either relative or + absolute. If it is relative, it is resolved itself against the + \l {QCoreApplication::applicationFilePath()} {application file + path} before it is used. If \a documentURI is neither a valid URI + nor empty, the result is undefined. + + If the query contains a static error (e.g. syntax error), an error + message is sent to the messageHandler(), and isValid() will return + \e false. + + Variables must be bound before setQuery() is called. + + The encoding of the XQuery in \a sourceCode is detected internally + using the rules for setting and detecting encoding of XQuery files, + which are explained in the \l {http://www.w3.org/TR/xquery/} + {XQuery language}. + + If \a sourceCode is \c null or not readable, or if \a documentURI is not + a valid URI, behavior is undefined. + \sa isValid() + */ +void QXmlQuery::setQuery(QIODevice *sourceCode, const QUrl &documentURI) +{ + if(!sourceCode) + { + qWarning("A null QIODevice pointer cannot be passed."); + return; + } + + if(!sourceCode->isReadable()) + { + qWarning("The device must be readable."); + return; + } + + d->queryURI = QPatternist::XPathHelper::normalizeQueryURI(documentURI); + d->expression(sourceCode); +} + +/*! + \overload + The behavior and requirements of this function are the same as for + setQuery(QIODevice*, const QUrl&), after the XQuery has been read + from the IO device into a string. Because \a sourceCode is already + a Unicode string, detection of its encoding is unnecessary. +*/ +void QXmlQuery::setQuery(const QString &sourceCode, const QUrl &documentURI) +{ + Q_ASSERT_X(documentURI.isEmpty() || documentURI.isValid(), Q_FUNC_INFO, + "The document URI must be valid."); + + QByteArray query(sourceCode.toUtf8()); + QBuffer buffer(&query); + buffer.open(QIODevice::ReadOnly); + + setQuery(&buffer, documentURI); +} + +/*! + Sets this QXmlQuery to the XQuery read from the \a queryURI. Use + isValid() after calling this function. If an error occurred reading + \a queryURI, e.g., the query does not exist, cannot be read, or is + invalid, isValid() will return \e false. + + The supported URI schemes are the same as those in the XQuery + function \c{fn:doc}, except that queryURI can be the object of + a variable binding. + + \a baseURI is the Base URI of the static context, as defined in the + \l {http://www.w3.org/TR/xquery/}{XQuery language}. It is used + internally to resolve relative URIs that appear in the query, and + for message reporting. If \a baseURI is empty, \a queryURI is used. + Otherwise, \a baseURI is used, and it is resolved against the \l + {QCoreApplication::applicationFilePath()} {application file path} if + it is relative. + + If \a queryURI is empty or invalid, or if \a baseURI is invalid, + the behavior of this function is undefined. + */ +void QXmlQuery::setQuery(const QUrl &queryURI, const QUrl &baseURI) +{ + Q_ASSERT_X(queryURI.isValid(), Q_FUNC_INFO, "The passed URI must be valid."); + + const QUrl canonicalURI(QPatternist::XPathHelper::normalizeQueryURI(queryURI)); + Q_ASSERT(canonicalURI.isValid()); + Q_ASSERT(!canonicalURI.isRelative()); + Q_ASSERT(baseURI.isValid() || baseURI.isEmpty()); + + d->queryURI = QPatternist::XPathHelper::normalizeQueryURI(baseURI.isEmpty() ? queryURI : baseURI); + + QPatternist::AutoPtr<QIODevice> result; + + try + { + result.reset(QPatternist::AccelTreeResourceLoader::load(canonicalURI, d->m_networkAccessDelegator, + d->staticContext())); + } + catch(const QPatternist::Exception) + { + /* We do nothing, result will be 0. */ + } + + if(result) + { + setQuery(result.data(), d->queryURI); + result->close(); + } + else + d->recompileRequired(); +} + +/*! + Binds the variable \a name to the \a value so that $\a name can be + used from within the query to refer to the \a value. + + \a name must not be \e null. \a {name}.isNull() must return false. + If \a name has already been bound by a previous bindVariable() call, + its previous binding will be overridden. + + If \a {value} is null so that \a {value}.isNull() returns true, and + \a {name} already has a binding, the effect is to remove the + existing binding for \a {name}. + + To bind a value of type QString or QUrl, wrap the value in a + QVariant such that QXmlItem's QVariant constructor is called. + + All strings processed by the query must be valid XQuery strings, + which means they must contain only XML 1.0 characters. However, + this requirement is not checked. If the query processes an invalid + string, the behavior is undefined. + + \sa QVariant::isValid(), {QtXDM}{How QVariant maps to XQuery's Data Model}, + QXmlItem::isNull() + */ +void QXmlQuery::bindVariable(const QXmlName &name, const QXmlItem &value) +{ + if(name.isNull()) + { + qWarning("The variable name cannot be null."); + return; + } + + const QPatternist::VariableLoader::Ptr vl(d->variableLoader()); + const QVariant variant(QVariant::fromValue(value)); + + /* If the type of the variable changed(as opposed to only the value), + * we will have to recompile. */ + if(vl->invalidationRequired(name, variant) || value.isNull()) + d->recompileRequired(); + + vl->addBinding(name, variant); +} + +/*! + \overload + + This function constructs a QXmlName from \a localName using the + query's \l {QXmlNamePool} {namespace}. The function then behaves as + the overloaded function. It is equivalent to the following snippet. + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlquery.cpp 0 + */ +void QXmlQuery::bindVariable(const QString &localName, const QXmlItem &value) +{ + bindVariable(QXmlName(d->namePool, localName), value); +} + +/*! + Binds the variable \a name to the \a device so that $\a name can be + used from within the query to refer to the \a device. The QIODevice + \a device is exposed to the query as a URI of type \c{xs:anyURI}, + which can be passed to the \c{fn:doc()} function to be read. E.g., + this function can be used to pass an XML document in memory to + \c{fn:doc}. + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlquery.cpp 1 + + The caller must ensure that \a device has been opened with at least + QIODevice::ReadOnly prior to this binding. Otherwise, behavior is + undefined. + + If the query will access an XML document contained in a QString, use + a QBuffer as shown in the following snippet. Suppose \e myQString + contains \c{<document>content</document>} + + \snippet doc/src/snippets/qxmlquery/bindingExample.cpp 0 + + \a name must not be \e null. \a {name}.isNull() must return false. + If \a name has already been bound, its previous binding will be + overridden. The URI that \a name evaluates to is arbitrary and may + change. + + If the type of the variable binding changes (e.g., if a previous + binding by the same name was a QVariant, or if there was no previous + binding), isValid() will return \c{false}, and recompilation of the + query text is required. To recompile the query, call setQuery(). For + this reason, bindVariable() should be called before setQuery(), if + possible. + + \note \a device must not be deleted while this QXmlQuery exists. +*/ +void QXmlQuery::bindVariable(const QXmlName &name, QIODevice *device) +{ + if(device && !device->isReadable()) + { + qWarning("A null, or readable QIODevice must be passed."); + return; + } + + if(name.isNull()) + { + qWarning("The variable name cannot be null."); + return; + } + + const QPatternist::VariableLoader::Ptr vl(d->variableLoader()); + + if(device) + { + const QVariant variant(QVariant::fromValue(device)); + + if(vl->invalidationRequired(name, variant)) + d->recompileRequired(); + + vl->addBinding(name, variant); + + /* We need to tell the resource loader to discard its document, because + * the underlying QIODevice has changed, but the variable name is the + * same which means that the URI is the same, and hence the resource + * loader will return the document for the old QIODevice. + */ + d->resourceLoader()->clear(QUrl(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + d->namePool.d->stringForLocalName(name.localName()))); + } + else + { + vl->removeBinding(name); + d->recompileRequired(); + } +} + +/*! + \overload + + If \a localName is a valid \l {QXmlName::isNCName()} {NCName}, this + function is equivalent to the following snippet. + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlquery.cpp 2 + + A QXmlName is constructed from \a localName, and is passed + to the appropriate overload along with \a device. + + \sa QXmlName::isNCName() + */ +void QXmlQuery::bindVariable(const QString &localName, QIODevice *device) +{ + bindVariable(QXmlName(d->namePool, localName), device); +} + +/*! + Evaluates this query and sends the result as a sequence of callbacks + to the \l {QAbstractXmlReceiver} {receiver} \a callback. QXmlQuery + does not take ownership of \a callback. + + If an error occurs during the evaluation, error messages are sent to + messageHandler() and \c false is returned. + + If this query \l {isValid()} {is invalid}, \c{false} is returned + and the behavior is undefined. If \a callback is null, + behavior is undefined. + + \sa QAbstractXmlReceiver, isValid() + */ +bool QXmlQuery::evaluateTo(QAbstractXmlReceiver *callback) const +{ + if(!callback) + { + qWarning("A non-null callback must be passed."); + return false; + } + + if(isValid()) + { + try + { + /* + * This order is significant. expression() might cause + * query recompilation, and as part of that it recreates + * the static context. However, if we create the dynamic + * context before the query recompilation has been + * triggered, it will use the old static context, and + * hence old source locations. + */ + const QPatternist::Expression::Ptr expr(d->expression()); + const QPatternist::DynamicContext::Ptr dynContext(d->dynamicContext(callback)); + callback->startOfSequence(); + expr->evaluateToSequenceReceiver(dynContext); + callback->endOfSequence(); + return true; + } + catch(const QPatternist::Exception) + { + return false; + } + } + else + return false; +} + +/*! + Attempts to evaluate the query and returns the results in the + \a target \l {QStringList} {string list}. + + If the query \l {isValid()} {is valid} and the evaluation succeeds, + true is returned. Otherwise, false is returned and the contents of + \a target are undefined. + + The query must evaluate to a sequence of \c{xs:string} values. If + the query does not evaluate to a sequence of strings, the values can + often be converted by adding a call to \c{string()} at the end of + the XQuery. + + If \a target is null, the behavior is undefined. + */ +bool QXmlQuery::evaluateTo(QStringList *target) const +{ + if(!target) + { + qWarning("A non-null callback must be passed."); + return false; + } + + if(isValid()) + { + try + { + /* + * This order is significant. expression() might cause + * query recompilation, and as part of that it recreates + * the static context. However, if we create the dynamic + * context before the query recompilation has been + * triggered, it will use the old static context, and + * hence old source locations. + */ + const QPatternist::Expression::Ptr expr(d->expression()); + if(!expr) + return false; + + QPatternist::DynamicContext::Ptr dynContext(d->dynamicContext()); + + if(!QPatternist::BuiltinTypes::xsString->xdtTypeMatches(expr->staticType()->itemType())) + return false; + + const QPatternist::Item::Iterator::Ptr it(expr->evaluateSequence(dynContext)); + QPatternist::Item next(it->next()); + + while(!next.isNull()) + { + target->append(next.stringValue()); + next = it->next(); + } + + return true; + } + catch(const QPatternist::Exception) + { + return false; + } + } + else + return false; +} + +/*! + Evaluates the query or stylesheet, and writes the output to \a target. + + QXmlSerializer is used to write the output to \a target. In a future + release, it is expected that this function will be changed to + respect serialization options set in the stylesheet. + + If an error occurs during the evaluation, error messages are sent to + messageHandler() and \c false is returned. + + If \a target is \c null, or is not opened in at least + QIODevice::WriteOnly mode, the behavior is undefined. QXmlQuery + does not take ownership of \a target. + + \since 4.5 + \overload + */ +bool QXmlQuery::evaluateTo(QIODevice *target) const +{ + if(!target) + { + qWarning("The pointer to the device cannot be null."); + return false; + } + + if(!target->isWritable()) + { + qWarning("The device must be writable."); + return false; + } + + QXmlSerializer serializer(*this, target); + return evaluateTo(&serializer); +} + +/*! + Starts the evaluation and makes it available in \a result. If \a + result is null, the behavior is undefined. The evaluation takes + place incrementally (lazy evaluation), as the caller uses + QXmlResultItems::next() to get the next result. + + \sa QXmlResultItems::next() +*/ +void QXmlQuery::evaluateTo(QXmlResultItems *result) const +{ + if(!result) + { + qWarning("A null pointer cannot be passed."); + return; + } + + if(isValid()) + { + try + { + /* + * We don't have the d->expression() calls and + * d->dynamicContext() calls in the same order as seen in + * QXmlQuery::evaluateTo(), and the reason to why + * that isn't a problem, is that we call isValid(). + */ + const QPatternist::DynamicContext::Ptr dynContext(d->dynamicContext()); + result->d_ptr->setDynamicContext(dynContext); + result->d_ptr->iterator = d->expression()->evaluateSequence(dynContext); + } + catch(const QPatternist::Exception) + { + result->d_ptr->iterator = QPatternist::CommonValues::emptyIterator; + result->d_ptr->hasError = true; + } + } + else + { + result->d_ptr->iterator= QPatternist::CommonValues::emptyIterator; + result->d_ptr->hasError = true; + } +} + +/*! + Evaluates the query, and serializes the output as XML to \a output. + + If an error occurs during the evaluation, error messages are sent to + messageHandler(), the content of \a output is undefined and \c false is + returned, otherwise \c true is returned. + + If \a output is \c null behavior is undefined. QXmlQuery + does not take ownership of \a output. + + Internally, the class QXmlFormatter is used for this. + \since 4.5 + */ +bool QXmlQuery::evaluateTo(QString *output) const +{ + Q_ASSERT_X(output, Q_FUNC_INFO, + "The input cannot be null"); + + QBuffer outputDevice; + outputDevice.open(QIODevice::ReadWrite); + + QXmlFormatter formatter(*this, &outputDevice); + const bool success = evaluateTo(&formatter); + + outputDevice.close(); + *output = QString::fromUtf8(outputDevice.data().constData()); + + return success; +} + +/*! + Returns true if this query is valid. Examples of invalid queries + are ones that contain syntax errors or that have not had setQuery() + called for them yet. + */ +bool QXmlQuery::isValid() const +{ + return d->isValid(); +} + +/*! + Sets the URI resolver to \a resolver. QXmlQuery does not take + ownership of \a resolver. + + \sa uriResolver() + */ +void QXmlQuery::setUriResolver(const QAbstractUriResolver *resolver) +{ + d->uriResolver = resolver; +} + +/*! + Returns the query's URI resolver. If no URI resolver has been set, + QtXmlPatterns will use the URIs in queries as they are. + + The URI resolver provides a level of abstraction, or \e{polymorphic + URIs}. A resolver can rewrite \e{logical} URIs to physical ones, or + it can translate obsolete or invalid URIs to valid ones. + + QtXmlPatterns calls the URI resolver for all URIs it encounters, + except for namespaces. Specifically, all builtin functions that deal + with URIs (\c{fn:doc()}, and \c{fn:doc-available()}). + + In the case of \c{fn:doc()}, the absolute URI is the base URI in the + static context (which most likely is the location of the query). + Rather than use the URI the user specified, the return value of + QAbstractUriResolver::resolve() will be used. + + When QtXmlPatterns calls QAbstractUriResolver::resolve() the + absolute URI is the URI mandated by the XQuery language, and the + relative URI is the URI specified by the user. + + \sa setUriResolver() + */ +const QAbstractUriResolver *QXmlQuery::uriResolver() const +{ + return d->uriResolver; +} + +/*! + Returns the name pool used by this QXmlQuery for constructing \l + {QXmlName} {names}. There is no setter for the name pool, because + mixing name pools causes errors due to name confusion. + */ +QXmlNamePool QXmlQuery::namePool() const +{ + return d->namePool; +} + +/*! + Sets the focus to \a item. The focus is the set of items that the + context item expression and path expressions navigate from. For + example, in the expression \e p/span, the element that \e p + evaluates to is the focus for the following expression, \e span. + + The focus can be accessed using the context item expression, i.e., + dot ("."). + + By default, the focus is not set and is undefined. It will + therefore result in a dynamic error, \c XPDY0002, if the focus + is attempted to be accessed. The focus must be set before the + query is set with setQuery(). + + There is no behavior defined for setting an item which is null. + + */ +void QXmlQuery::setFocus(const QXmlItem &item) +{ + d->contextItem = item; +} + +/** + * This function should be a private member function of QXmlQuery, + * but we don't dare that due to our weird compilers. + * @internal + * @relates QXmlQuery + */ +template<typename TInputType> +bool setFocusHelper(QXmlQuery *const queryInstance, + const TInputType &focusValue) +{ + /* We call resourceLoader(), so we have ensured that we have a resourceLoader + * that we will share in our copy. */ + queryInstance->d->resourceLoader(); + + QXmlQuery focusQuery(*queryInstance); + + /* Now we use the same, so we own the loaded document. */ + focusQuery.d->m_resourceLoader = queryInstance->d->m_resourceLoader; + + /* The copy constructor doesn't allow us to copy an existing QXmlQuery and + * changing the language at the same time so we need to use private API. */ + focusQuery.d->queryLanguage = QXmlQuery::XQuery10; + + Q_ASSERT(focusQuery.queryLanguage() == QXmlQuery::XQuery10); + focusQuery.bindVariable(QChar::fromLatin1('u'), focusValue); + focusQuery.setQuery(QLatin1String("doc($u)")); + Q_ASSERT(focusQuery.isValid()); + + QXmlResultItems focusResult; + + queryInstance->d->m_resourceLoader = focusQuery.d->m_resourceLoader; + + focusQuery.evaluateTo(&focusResult); + const QXmlItem focusItem(focusResult.next()); + + if(focusItem.isNull() || focusResult.hasError()) + return false; + else + { + queryInstance->setFocus(focusItem); + return true; + } +} + +/*! + \since 4.5 + \overload + + Sets the focus to be the document located at \a documentURI and + returns true. If \a documentURI cannot be loaded, false is returned. + It is undefined at what time the document may be loaded. When + loading the document, the message handler and URI resolver set on + this QXmlQuery are used. + + If \a documentURI is empty or is not a valid URI, the behavior of + this function is undefined. + */ +bool QXmlQuery::setFocus(const QUrl &documentURI) +{ + Q_ASSERT_X(documentURI.isValid() && !documentURI.isEmpty(), + Q_FUNC_INFO, + "The URI passed must be valid."); + + return setFocusHelper(this, QVariant(documentURI)); +} + +/*! + + Sets the focus to be the \a document read from the QIODevice and + returns true. If \a document cannot be loaded, false is returned. + + QXmlQuery does not take ownership of \a document. The user + guarantees that a document is available from the \a document device + and that the document is not empty. The device must be opened in at + least read-only mode. \a document must stay in scope as long as the + current query is active. + + \since 4.5 + \overload + */ +bool QXmlQuery::setFocus(QIODevice *document) +{ + if(!document) + { + qWarning("A null QIODevice pointer cannot be passed."); + return false; + } + + if(!document->isReadable()) + { + qWarning("The device must be readable."); + return false; + } + + return setFocusHelper(this, document); +} + +/*! + This function behaves identically to calling the setFocus() overload with a + QIODevice whose content is \a focus encoded as UTF-8. That is, \a focus is + treated as if it contained an XML document. + + Returns the same result as the overload. + + \overload + \since 4.6 + */ +bool QXmlQuery::setFocus(const QString &focus) +{ + QBuffer device; + device.setData(focus.toUtf8()); + device.open(QIODevice::ReadOnly); + + return setFocusHelper(this, &device); +} + +/*! + Returns a value indicating what this QXmlQuery is being used for. + The default is QXmlQuery::XQuery10, which means the QXmlQuery is + being used for running XQuery and XPath queries. QXmlQuery::XSLT20 + can also be returned, which indicates the QXmlQuery is for running + XSL-T spreadsheets. + + \since 4.5 + */ +QXmlQuery::QueryLanguage QXmlQuery::queryLanguage() const +{ + return d->queryLanguage; +} + +/*! + Sets the \a name of the initial template. The initial template is + the one the processor calls first, instead of attempting to match a + template to the context node (if any). If an initial template is not + set, the standard order of template invocation will be used. + + This function only applies when using QXmlQuery to process XSL-T + stylesheets. The name becomes part of the compiled stylesheet. + Therefore, this function must be called before calling setQuery(). + + If the stylesheet has no template named \a name, the processor will + use the standard order of template invocation. + + \since 4.5 + \sa initialTemplateName() + */ +void QXmlQuery::setInitialTemplateName(const QXmlName &name) +{ + d->initialTemplateName = name; +} + +/*! + \overload + + Sets the name of the initial template to \a localName, which must be + a valid \l{QXmlName::localName()} {local name}. The initial template + is the one the processor calls first, instead of attempting to match + a template to the context node (if any). If an initial template is + not set, the standard order of template invocation will be used. + + This function only applies when using QXmlQuery to process XSL-T + stylesheets. The name becomes part of the compiled stylesheet. + Therefore, this function must be called before calling setQuery(). + + If \a localName is not a valid \l{QXmlName::localName()} {local + name}, the effect is undefined. If the stylesheet has no template + named \a localName, the processor will use the standard order of + template invocation. + + \since 4.5 + \sa initialTemplateName() + */ +void QXmlQuery::setInitialTemplateName(const QString &localName) +{ + Q_ASSERT_X(QXmlName::isNCName(localName), + Q_FUNC_INFO, + "The name passed must be a valid NCName."); + setInitialTemplateName(QXmlName(d->namePool, localName)); +} + +/*! + Returns the name of the XSL-T stylesheet template that the processor + will call first when running an XSL-T stylesheet. This function only + applies when using QXmlQuery to process XSL-T stylesheets. By + default, no initial template is set. In that case, a default + constructed QXmlName is returned. + + \since 4.5 + */ +QXmlName QXmlQuery::initialTemplateName() const +{ + return d->initialTemplateName; +} + +/*! + Sets the network manager to \a newManager. + QXmlQuery does not take ownership of \a newManager. + + \sa networkAccessManager() + \since 4.5 + */ +void QXmlQuery::setNetworkAccessManager(QNetworkAccessManager *newManager) +{ + d->m_networkAccessDelegator->m_genericManager = newManager; +} + +/*! + Returns the network manager, or 0 if it has not been set. + + \sa setNetworkAccessManager() + \since 4.5 + */ +QNetworkAccessManager *QXmlQuery::networkAccessManager() const +{ + return d->m_networkAccessDelegator->m_genericManager; +} + +/*! + Binds the result of the query \a query, to a variable by name \a name. + + Evaluation of \a query will be commenced when this function is called. + + If \a query is invalid, behavior is undefined. \a query will be copied. + + \since 4.5 + \sa isValid() + */ +void QXmlQuery::bindVariable(const QXmlName &name, const QXmlQuery &query) +{ + Q_ASSERT_X(query.isValid(), Q_FUNC_INFO, "The query being bound must be valid."); + + const QPatternist::VariableLoader::Ptr vl(d->variableLoader()); + const QVariant variant(QVariant::fromValue(query)); + + if(vl->invalidationRequired(name, variant)) + d->recompileRequired(); + + vl->addBinding(name, variant); +} + +/*! + \overload + + Has the same behavior and effects as the function being overloaded, but takes + the variable name \a localName as a QString. \a query is used as in the + overloaded function. + + \since 4.5 + */ +void QXmlQuery::bindVariable(const QString &localName, const QXmlQuery &query) +{ + return bindVariable(QXmlName(d->namePool, localName), query); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlquery.h b/src/xmlpatterns/api/qxmlquery.h new file mode 100644 index 0000000..041d035 --- /dev/null +++ b/src/xmlpatterns/api/qxmlquery.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLQUERY_H +#define QXMLQUERY_H + +#include <QtCore/QUrl> +#include <QtXmlPatterns/QAbstractXmlNodeModel> +#include <QtXmlPatterns/QAbstractXmlReceiver> +#include <QtXmlPatterns/QXmlNamePool> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QAbstractMessageHandler; +class QAbstractUriResolver; +class QIODevice; +class QNetworkAccessManager; +class QXmlName; +class QXmlNodeIndex; +class QXmlQueryPrivate; +class QXmlResultItems; +class QXmlSerializer; + +/* The members in the namespace QPatternistSDK are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ +namespace QPatternistSDK +{ + class TestCase; +} + +namespace QPatternist +{ + class XsdSchemaParser; + class XsdValidatingInstanceReader; + class VariableLoader; +} + +class Q_XMLPATTERNS_EXPORT QXmlQuery +{ +public: + enum QueryLanguage + { + XQuery10 = 1, + XSLT20 = 2, + XmlSchema11IdentityConstraintSelector = 1024, + XmlSchema11IdentityConstraintField = 2048, + XPath20 = 4096 + }; + + QXmlQuery(); + QXmlQuery(const QXmlQuery &other); + QXmlQuery(const QXmlNamePool &np); + QXmlQuery(QueryLanguage queryLanguage, + const QXmlNamePool &np = QXmlNamePool()); + ~QXmlQuery(); + QXmlQuery &operator=(const QXmlQuery &other); + + void setMessageHandler(QAbstractMessageHandler *messageHandler); + QAbstractMessageHandler *messageHandler() const; + + void setQuery(const QString &sourceCode, const QUrl &documentURI = QUrl()); + void setQuery(QIODevice *sourceCode, const QUrl &documentURI = QUrl()); + void setQuery(const QUrl &queryURI, const QUrl &baseURI = QUrl()); + + QXmlNamePool namePool() const; + + void bindVariable(const QXmlName &name, const QXmlItem &value); + void bindVariable(const QString &localName, const QXmlItem &value); + + void bindVariable(const QXmlName &name, QIODevice *); + void bindVariable(const QString &localName, QIODevice *); + void bindVariable(const QXmlName &name, const QXmlQuery &query); + void bindVariable(const QString &localName, const QXmlQuery &query); + + bool isValid() const; + + void evaluateTo(QXmlResultItems *result) const; + bool evaluateTo(QAbstractXmlReceiver *callback) const; + bool evaluateTo(QStringList *target) const; + bool evaluateTo(QIODevice *target) const; + bool evaluateTo(QString *output) const; + + void setUriResolver(const QAbstractUriResolver *resolver); + const QAbstractUriResolver *uriResolver() const; + + void setFocus(const QXmlItem &item); + bool setFocus(const QUrl &documentURI); + bool setFocus(QIODevice *document); + bool setFocus(const QString &focus); + + void setInitialTemplateName(const QXmlName &name); + void setInitialTemplateName(const QString &name); + QXmlName initialTemplateName() const; + + void setNetworkAccessManager(QNetworkAccessManager *newManager); + QNetworkAccessManager *networkAccessManager() const; + + QueryLanguage queryLanguage() const; +private: + friend class QXmlName; + friend class QXmlSerializer; + friend class QPatternistSDK::TestCase; + friend class QPatternist::XsdSchemaParser; + friend class QPatternist::XsdValidatingInstanceReader; + friend class QPatternist::VariableLoader; + template<typename TInputType> friend bool setFocusHelper(QXmlQuery *const queryInstance, + const TInputType &focusValue); + QXmlQueryPrivate *d; +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlquery_p.h b/src/xmlpatterns/api/qxmlquery_p.h new file mode 100644 index 0000000..629b50b --- /dev/null +++ b/src/xmlpatterns/api/qxmlquery_p.h @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QXMLQUERY_P_H +#define QXMLQUERY_P_H + +#include <QAbstractMessageHandler> +#include <QAbstractUriResolver> +#include <QPointer> +#include <QSourceLocation> +#include <QUrl> +#include <QVariant> +#include <QXmlName> +#include <QXmlNamePool> +#include <QXmlQuery> + +#include "qacceltreebuilder_p.h" +#include "qacceltreeresourceloader_p.h" +#include "qcoloringmessagehandler_p.h" +#include "qcommonsequencetypes_p.h" +#include "qexpressionfactory_p.h" +#include "qfocus_p.h" +#include "qfunctionfactorycollection_p.h" +#include "qgenericdynamiccontext_p.h" +#include "qgenericstaticcontext_p.h" +#include "qnamepool_p.h" +#include "qnetworkaccessdelegator_p.h" +#include "qreferencecountedvalue_p.h" +#include "qresourcedelegator_p.h" +#include "qstaticfocuscontext_p.h" +#include "quriloader_p.h" +#include "qvariableloader_p.h" + +QT_BEGIN_NAMESPACE + +class QXmlQueryPrivate +{ +public: + + inline QXmlQueryPrivate(const QXmlNamePool &np = QXmlNamePool()) : namePool(np) + , messageHandler(0) + , uriResolver(0) + , queryLanguage(QXmlQuery::XQuery10) + , m_networkAccessDelegator(new QPatternist::NetworkAccessDelegator(0, 0)) + { + m_networkAccessDelegator->m_variableURIManager = new QPatternist::URILoader(ownerObject(), namePool.d, variableLoader()); + } + + void detach() + { + if(m_variableLoader) + m_variableLoader = QPatternist::VariableLoader::Ptr(new QPatternist::VariableLoader(namePool.d, m_variableLoader)); + + delete m_networkAccessDelegator->m_variableURIManager; + m_networkAccessDelegator->m_variableURIManager = new QPatternist::URILoader(ownerObject(), namePool.d, m_variableLoader); + + if(m_resourceLoader) + { + const QPatternist::AccelTreeResourceLoader::Ptr nev(new QPatternist::AccelTreeResourceLoader(namePool.d, + m_networkAccessDelegator)); + m_resourceLoader = QPatternist::ResourceLoader::Ptr(new QPatternist::ResourceDelegator(m_resourceLoader->deviceURIs(), + m_resourceLoader, + nev)); + } + } + + bool isValid() + { + return expression(); + } + + inline void recompileRequired() + { + m_expr.reset(); + } + + inline QPatternist::VariableLoader::Ptr variableLoader() + { + if(!m_variableLoader) + m_variableLoader = QPatternist::VariableLoader::Ptr(new QPatternist::VariableLoader(namePool.d)); + + return m_variableLoader; + } + + inline QPatternist::GenericStaticContext::Ptr staticContext() + { + if(m_staticContext && m_expr) + return m_staticContext; + /* Else, re-create the staticContext. */ + + if(!messageHandler) + messageHandler = new QPatternist::ColoringMessageHandler(ownerObject()); + + if(!m_functionFactory) + { + if(queryLanguage == QXmlQuery::XSLT20) + m_functionFactory = QPatternist::FunctionFactoryCollection::xslt20Factory(namePool.d); + else + m_functionFactory = QPatternist::FunctionFactoryCollection::xpath20Factory(namePool.d); + } + + const QPatternist::GenericStaticContext::Ptr genericStaticContext(new QPatternist::GenericStaticContext(namePool.d, + messageHandler, + queryURI, + m_functionFactory, + queryLanguage)); + genericStaticContext->setResourceLoader(resourceLoader()); + + genericStaticContext->setExternalVariableLoader(variableLoader()); + + m_staticContext = genericStaticContext; + + if(!contextItem.isNull()) + m_staticContext = QPatternist::StaticContext::Ptr(new QPatternist::StaticFocusContext(QPatternist::AtomicValue::qtToXDMType(contextItem), m_staticContext)); + else if( queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField + || queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintSelector + || queryLanguage == QXmlQuery::XPath20) + m_staticContext = QPatternist::StaticContext::Ptr(new QPatternist::StaticFocusContext(QPatternist::BuiltinTypes::node, m_staticContext)); + + for (int i = 0; i < m_additionalNamespaceBindings.count(); ++i) { + m_staticContext->namespaceBindings()->addBinding(m_additionalNamespaceBindings.at(i)); + } + + return m_staticContext; + } + + inline QPatternist::DynamicContext::Ptr dynamicContext(QAbstractXmlReceiver *const callback = 0) + { + const QPatternist::StaticContext::Ptr statContext(staticContext()); + Q_ASSERT(statContext); + + QPatternist::GenericDynamicContext::Ptr dynContext(new QPatternist::GenericDynamicContext(namePool.d, statContext->messageHandler(), + statContext->sourceLocations())); + + QPatternist::AutoPtr<QPatternist::NodeBuilder> nodeBuilder(new QPatternist::AccelTreeBuilder<false>(QUrl(), QUrl(), namePool.d, + dynContext.data())); + dynContext->setNodeBuilder(nodeBuilder); + + dynContext->setResourceLoader(statContext->resourceLoader()); + dynContext->setExternalVariableLoader(statContext->externalVariableLoader()); + dynContext->setUriResolver(uriResolver); + + if(callback) + dynContext->setOutputReceiver(callback); + + if(contextItem.isNull()) + return dynContext; + else + { + QPatternist::DynamicContext::Ptr focus(new QPatternist::Focus(dynContext)); + QPatternist::Item::Iterator::Ptr it(QPatternist::makeSingletonIterator(QPatternist::Item::fromPublic(contextItem))); + it->next(); + focus->setFocusIterator(it); + return focus; + } + } + + inline QPatternist::AccelTreeResourceLoader::Ptr resourceLoader() + { + if(!m_resourceLoader) + m_resourceLoader = (new QPatternist::AccelTreeResourceLoader(namePool.d, m_networkAccessDelegator)); + + return m_resourceLoader; + } + + void setRequiredType(const QPatternist::SequenceType::Ptr &seqType) + { + Q_ASSERT(seqType); + if(!m_requiredType || m_requiredType->is(seqType)) + return; + + m_requiredType = seqType; + m_staticContext.reset(); + } + + QPatternist::SequenceType::Ptr requiredType() + { + if(m_requiredType) + return m_requiredType; + else + { + m_requiredType = QPatternist::CommonSequenceTypes::ZeroOrMoreItems; + return m_requiredType; + } + } + + QPatternist::Expression::Ptr expression(QIODevice *const queryDevice = 0) + { + if(m_expr && !queryDevice) + return m_expr; + + /* If we need to update, but we don't have any source code, we can + * never create an Expression. */ + if(!queryDevice) + return QPatternist::Expression::Ptr(); + + try + { + /* The static context has source locations, and they need to be + * updated to the new query. */ + m_staticContext.reset(); + + if(!m_expressionFactory) + m_expressionFactory = QPatternist::ExpressionFactory::Ptr(new QPatternist::ExpressionFactory()); + + m_expr = m_expressionFactory->createExpression(queryDevice, staticContext(), + queryLanguage, + requiredType(), + queryURI, + initialTemplateName); + } + catch(const QPatternist::Exception) + { + m_expr.reset(); + + /* We don't call m_staticContext.reset() because it shouldn't be + * necessary, since m_staticContext is changed when the expression + * is changed. */ + } + + return m_expr; + } + + inline void addAdditionalNamespaceBinding(const QXmlName &binding) + { + m_additionalNamespaceBindings.append(binding); + } + + QXmlNamePool namePool; + QPointer<QAbstractMessageHandler> messageHandler; + /** + * Must be absolute and valid. + */ + QUrl queryURI; + const QAbstractUriResolver * uriResolver; + QXmlItem contextItem; + QXmlName initialTemplateName; + + inline void setExpressionFactory(const QPatternist::ExpressionFactory::Ptr &expr) + { + m_expressionFactory = expr; + } + + QXmlQuery::QueryLanguage queryLanguage; + QPointer<QNetworkAccessManager> userNetworkManager; + + inline QObject *ownerObject() + { + if(!m_owner) + m_owner = new QPatternist::ReferenceCountedValue<QObject>(new QObject()); + + return m_owner->value; + } + + QPatternist::ExpressionFactory::Ptr m_expressionFactory; + QPatternist::StaticContext::Ptr m_staticContext; + QPatternist::VariableLoader::Ptr m_variableLoader; + QPatternist::DeviceResourceLoader::Ptr m_resourceLoader; + /** + * This is the AST for the query. + */ + QPatternist::Expression::Ptr m_expr; + QPatternist::ReferenceCountedValue<QObject>::Ptr m_owner; + + /** + * This is our effective network manager, that we end up using. The one the + * user sets is userNetworkManager. + */ + QPatternist::SequenceType::Ptr m_requiredType; + QPatternist::FunctionFactory::Ptr m_functionFactory; + QPatternist::NetworkAccessDelegator::Ptr m_networkAccessDelegator; + + QList<QXmlName> m_additionalNamespaceBindings; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlresultitems.cpp b/src/xmlpatterns/api/qxmlresultitems.cpp new file mode 100644 index 0000000..4d167d0 --- /dev/null +++ b/src/xmlpatterns/api/qxmlresultitems.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxmlresultitems.h" +#include "qxmlresultitems_p.h" +#include "qitem_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QXmlResultItems + \brief The QXmlResultItems class iterates through the results of evaluating an XQuery in QXmlQuery. + \reentrant + \since 4.4 + \ingroup xml-tools + + QXmlResultItems presents the evaluation of an associated query as a + sequence of \l{QXmlItem}{QXmlItems}. The sequence is traversed by + repeatedly calling next(), which actually produces the sequence by + lazy evaluation of the query. + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlresultitems.cpp 0 + + An effect of letting next() produce the sequence by lazy evaluation + is that a query error can occur on any call to next(). If an error + occurs, both next() and current() will return the null QXmlItem, and + hasError() will return true. + + QXmlResultItems can be thought of as an "iterator" that traverses + the sequence of query results once, in the forward direction. Each + call to next() advances the iterator to the next QXmlItem in the + sequence and returns it, and current() always returns the QXmlItem + that next() returned the last time it was called. + + \note When using the QXmlResultItems overload of QXmlQuery::evaluateTo() + to execute a query, it is advisable to create a new instance of this + class for each new set of results rather than reusing an old instance. + + \sa QXmlItem::isNode(), QXmlItem::isAtomicValue(), QXmlNodeModelIndex + */ + +/*! + Constructs an instance of QXmlResultItems. + */ +QXmlResultItems::QXmlResultItems() : d_ptr(new QXmlResultItemsPrivate()) +{ +} + +/*! + Destroys this instance of QXmlResultItems. + */ +QXmlResultItems::~QXmlResultItems() +{ +} + +/*! + Returns the next result in the sequence produced by lazy evaluation + of the associated query. When the returned QXmlItem is null, either + the evaluation terminated normally without producing another result, + or an error occurred. Call hasError() to determine whether the null + item was caused by normal termination or by an error. + + Returns a null QXmlItem if there is no associated QXmlQuery. + */ +QXmlItem QXmlResultItems::next() +{ + Q_D(QXmlResultItems); + if(d->hasError) + return QXmlItem(); + + try + { + d->current = QPatternist::Item::toPublic(d->iterator->next()); + return d->current; + } + catch(const QPatternist::Exception) + { + d->current = QXmlItem(); + d->hasError = true; + return QXmlItem(); + } +} + +/*! + Returns the current item. The current item is the last item + that was produced and returned by next(). + + Returns a null QXmlItem if there is no associated QXmlQuery. + */ +QXmlItem QXmlResultItems::current() const +{ + Q_D(const QXmlResultItems); + + if(d->hasError) + return QXmlItem(); + else + return d->current; +} + +/*! + + If an error occurred during evaluation of the query, true is + returned. + + Returns false if query evaluation has been done. + */ +bool QXmlResultItems::hasError() const +{ + Q_D(const QXmlResultItems); + return d->hasError; +} + +QT_END_NAMESPACE + diff --git a/src/xmlpatterns/api/qxmlresultitems.h b/src/xmlpatterns/api/qxmlresultitems.h new file mode 100644 index 0000000..0a12048 --- /dev/null +++ b/src/xmlpatterns/api/qxmlresultitems.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLRESULTITEMS +#define QXMLRESULTITEMS + +#include <QtCore/QString> +#include <QtCore/QScopedPointer> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QXmlItem; +class QXmlQuery; +class QXmlResultItemsPrivate; + +class Q_XMLPATTERNS_EXPORT QXmlResultItems +{ +public: + QXmlResultItems(); + virtual ~QXmlResultItems(); + + bool hasError() const; + QXmlItem next(); + QXmlItem current() const; + +private: + friend class QXmlQuery; + Q_DECLARE_PRIVATE(QXmlResultItems) + QScopedPointer<QXmlResultItemsPrivate> d_ptr; + Q_DISABLE_COPY(QXmlResultItems) +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlresultitems_p.h b/src/xmlpatterns/api/qxmlresultitems_p.h new file mode 100644 index 0000000..3d0a0e9 --- /dev/null +++ b/src/xmlpatterns/api/qxmlresultitems_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QXMLRESULTITEMS_P_H +#define QXMLRESULTITEMS_P_H + +#include "qcommonvalues_p.h" +#include "qdynamiccontext_p.h" +#include "qitem_p.h" + +QT_BEGIN_NAMESPACE + +class QXmlResultItemsPrivate +{ +public: + inline QXmlResultItemsPrivate() : iterator(QPatternist::CommonValues::emptyIterator) + , hasError(false) + { + } + + void setDynamicContext(const QPatternist::DynamicContext::Ptr &context) + { + m_context = context; + } + + QPatternist::Item::Iterator::Ptr iterator; + QXmlItem current; + bool hasError; +private: + /** + * We never use it. We only keep a ref to it such that it doesn't get + * de-allocated. + */ + QPatternist::DynamicContext::Ptr m_context; +}; + +QT_END_NAMESPACE +#endif + diff --git a/src/xmlpatterns/api/qxmlschema.cpp b/src/xmlpatterns/api/qxmlschema.cpp new file mode 100644 index 0000000..ee92195 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschema.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxmlschema.h" +#include "qxmlschema_p.h" + +#include <QtCore/QIODevice> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +/*! + \class QXmlSchema + + \brief The QXmlSchema class provides loading and validation of a W3C XML Schema. + + \reentrant + \since 4.6 + \ingroup xml-tools + + The QXmlSchema class loads, compiles and validates W3C XML Schema files + that can be used further for validation of XML instance documents via + \l{QXmlSchemaValidator}. + + The following example shows how to load a XML Schema file from the network + and test whether it is a valid schema document: + + \snippet doc/src/snippets/qxmlschema/main.cpp 0 + + \section1 XML Schema Version + + This class is used to represent schemas that conform to the \l{XML Schema} 1.0 + specification. + + \sa QXmlSchemaValidator, {xmlpatterns/schema}{XML Schema Validation Example} +*/ + +/*! + Constructs an invalid, empty schema that cannot be used until + load() is called. + */ +QXmlSchema::QXmlSchema() + : d(new QXmlSchemaPrivate(QXmlNamePool())) +{ +} + +/*! + Constructs a QXmlSchema that is a copy of \a other. The new + instance will share resources with the existing schema + to the extent possible. + */ +QXmlSchema::QXmlSchema(const QXmlSchema &other) + : d(other.d) +{ +} + +/*! + Destroys this QXmlSchema. + */ +QXmlSchema::~QXmlSchema() +{ +} + +/*! + Sets this QXmlSchema to a schema loaded from the \a source + URI. + + If the schema \l {isValid()} {is invalid}, \c{false} is returned + and the behavior is undefined. + + Example: + + \snippet doc/src/snippets/qxmlschema/main.cpp 0 + + \sa isValid() + */ +bool QXmlSchema::load(const QUrl &source) +{ + d->load(source, QString()); + return d->isValid(); +} + +/*! + Sets this QXmlSchema to a schema read from the \a source + device. The device must have been opened with at least + QIODevice::ReadOnly. + + \a documentUri represents the schema obtained from the \a source + device. It is the base URI of the schema, that is used + internally to resolve relative URIs that appear in the schema, and + for message reporting. + + If \a source is \c null or not readable, or if \a documentUri is not + a valid URI, behavior is undefined. + + If the schema \l {isValid()} {is invalid}, \c{false} is returned + and the behavior is undefined. + + Example: + + \snippet doc/src/snippets/qxmlschema/main.cpp 1 + + \sa isValid() + */ +bool QXmlSchema::load(QIODevice *source, const QUrl &documentUri) +{ + d->load(source, documentUri, QString()); + return d->isValid(); +} + +/*! + Sets this QXmlSchema to a schema read from the \a data + + \a documentUri represents the schema obtained from the \a data. + It is the base URI of the schema, that is used internally to + resolve relative URIs that appear in the schema, and + for message reporting. + + If \a documentUri is not a valid URI, behavior is undefined. + \sa isValid() + + If the schema \l {isValid()} {is invalid}, \c{false} is returned + and the behavior is undefined. + + Example: + + \snippet doc/src/snippets/qxmlschema/main.cpp 2 + + \sa isValid() + */ +bool QXmlSchema::load(const QByteArray &data, const QUrl &documentUri) +{ + d->load(data, documentUri, QString()); + return d->isValid(); +} + +/*! + Returns true if this schema is valid. Examples of invalid schemas + are ones that contain syntax errors or that do not conform the + W3C XML Schema specification. + */ +bool QXmlSchema::isValid() const +{ + return d->isValid(); +} + +/*! + Returns the name pool used by this QXmlSchema for constructing \l + {QXmlName} {names}. There is no setter for the name pool, because + mixing name pools causes errors due to name confusion. + */ +QXmlNamePool QXmlSchema::namePool() const +{ + return d->namePool(); +} + +/*! + Returns the document URI of the schema or an empty URI if no + schema has been set. + */ +QUrl QXmlSchema::documentUri() const +{ + return d->documentUri(); +} + +/*! + Changes the \l {QAbstractMessageHandler}{message handler} for this + QXmlSchema to \a handler. The schema sends all compile and + validation messages to this message handler. QXmlSchema does not take + ownership of \a handler. + + Normally, the default message handler is sufficient. It writes + compile and validation messages to \e stderr. The default message + handler includes color codes if \e stderr can render colors. + + When QXmlSchema calls QAbstractMessageHandler::message(), + the arguments are as follows: + + \table + \header + \o message() argument + \o Semantics + \row + \o QtMsgType type + \o Only QtWarningMsg and QtFatalMsg are used. The former + identifies a warning, while the latter identifies an error. + \row + \o const QString & description + \o An XHTML document which is the actual message. It is translated + into the current language. + \row + \o const QUrl &identifier + \o Identifies the error with a URI, where the fragment is + the error code, and the rest of the URI is the error namespace. + \row + \o const QSourceLocation & sourceLocation + \o Identifies where the error occurred. + \endtable + + */ +void QXmlSchema::setMessageHandler(QAbstractMessageHandler *handler) +{ + d->setMessageHandler(handler); +} + +/*! + Returns the message handler that handles compile and validation + messages for this QXmlSchema. + */ +QAbstractMessageHandler *QXmlSchema::messageHandler() const +{ + return d->messageHandler(); +} + +/*! + Sets the URI resolver to \a resolver. QXmlSchema does not take + ownership of \a resolver. + + \sa uriResolver() + */ +void QXmlSchema::setUriResolver(const QAbstractUriResolver *resolver) +{ + d->setUriResolver(resolver); +} + +/*! + Returns the schema's URI resolver. If no URI resolver has been set, + QtXmlPatterns will use the URIs in schemas as they are. + + The URI resolver provides a level of abstraction, or \e{polymorphic + URIs}. A resolver can rewrite \e{logical} URIs to physical ones, or + it can translate obsolete or invalid URIs to valid ones. + + When QtXmlPatterns calls QAbstractUriResolver::resolve() the + absolute URI is the URI mandated by the schema specification, and the + relative URI is the URI specified by the user. + + \sa setUriResolver() + */ +const QAbstractUriResolver *QXmlSchema::uriResolver() const +{ + return d->uriResolver(); +} + +/*! + Sets the network manager to \a manager. + QXmlSchema does not take ownership of \a manager. + + \sa networkAccessManager() + */ +void QXmlSchema::setNetworkAccessManager(QNetworkAccessManager *manager) +{ + d->setNetworkAccessManager(manager); +} + +/*! + Returns the network manager, or 0 if it has not been set. + + \sa setNetworkAccessManager() + */ +QNetworkAccessManager *QXmlSchema::networkAccessManager() const +{ + return d->networkAccessManager(); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlschema.h b/src/xmlpatterns/api/qxmlschema.h new file mode 100644 index 0000000..145f2dc --- /dev/null +++ b/src/xmlpatterns/api/qxmlschema.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLSCHEMA_H +#define QXMLSCHEMA_H + +#include <QtCore/QSharedDataPointer> +#include <QtCore/QUrl> +#include <QtXmlPatterns/QXmlNamePool> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QAbstractMessageHandler; +class QAbstractUriResolver; +class QIODevice; +class QNetworkAccessManager; +class QUrl; +class QXmlNamePool; +class QXmlSchemaPrivate; + +class Q_XMLPATTERNS_EXPORT QXmlSchema +{ + friend class QXmlSchemaValidatorPrivate; + + public: + QXmlSchema(); + QXmlSchema(const QXmlSchema &other); + ~QXmlSchema(); + + bool load(const QUrl &source); + bool load(QIODevice *source, const QUrl &documentUri = QUrl()); + bool load(const QByteArray &data, const QUrl &documentUri = QUrl()); + + bool isValid() const; + + QXmlNamePool namePool() const; + QUrl documentUri() const; + + void setMessageHandler(QAbstractMessageHandler *handler); + QAbstractMessageHandler *messageHandler() const; + + void setUriResolver(const QAbstractUriResolver *resolver); + const QAbstractUriResolver *uriResolver() const; + + void setNetworkAccessManager(QNetworkAccessManager *networkmanager); + QNetworkAccessManager *networkAccessManager() const; + + private: + QSharedDataPointer<QXmlSchemaPrivate> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlschema_p.cpp b/src/xmlpatterns/api/qxmlschema_p.cpp new file mode 100644 index 0000000..f5ed5c0 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschema_p.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qacceltreeresourceloader_p.h" +#include "qxmlschema.h" +#include "qxmlschema_p.h" + +#include <QtCore/QBuffer> +#include <QtCore/QIODevice> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +QXmlSchemaPrivate::QXmlSchemaPrivate(const QXmlNamePool &namePool) + : m_namePool(namePool) + , m_userMessageHandler(0) + , m_uriResolver(0) + , m_userNetworkAccessManager(0) + , m_schemaContext(new QPatternist::XsdSchemaContext(m_namePool.d)) + , m_schemaParserContext(new QPatternist::XsdSchemaParserContext(m_namePool.d, m_schemaContext)) + , m_schemaIsValid(false) +{ + m_networkAccessManager = new QPatternist::ReferenceCountedValue<QNetworkAccessManager>(new QNetworkAccessManager()); + m_messageHandler = new QPatternist::ReferenceCountedValue<QAbstractMessageHandler>(new QPatternist::ColoringMessageHandler()); +} + +QXmlSchemaPrivate::QXmlSchemaPrivate(const QPatternist::XsdSchemaContext::Ptr &schemaContext) + : m_namePool(QXmlNamePool(schemaContext->namePool().data())) + , m_userMessageHandler(0) + , m_uriResolver(0) + , m_userNetworkAccessManager(0) + , m_schemaContext(schemaContext) + , m_schemaParserContext(new QPatternist::XsdSchemaParserContext(m_namePool.d, m_schemaContext)) + , m_schemaIsValid(false) +{ + m_networkAccessManager = new QPatternist::ReferenceCountedValue<QNetworkAccessManager>(new QNetworkAccessManager()); + m_messageHandler = new QPatternist::ReferenceCountedValue<QAbstractMessageHandler>(new QPatternist::ColoringMessageHandler()); +} + +QXmlSchemaPrivate::QXmlSchemaPrivate(const QXmlSchemaPrivate &other) + : QSharedData(other) +{ + m_namePool = other.m_namePool; + m_userMessageHandler = other.m_userMessageHandler; + m_uriResolver = other.m_uriResolver; + m_userNetworkAccessManager = other.m_userNetworkAccessManager; + m_messageHandler = other.m_messageHandler; + m_networkAccessManager = other.m_networkAccessManager; + + m_schemaContext = other.m_schemaContext; + m_schemaParserContext = other.m_schemaParserContext; + m_schemaIsValid = other.m_schemaIsValid; + m_documentUri = other.m_documentUri; +} + +void QXmlSchemaPrivate::load(const QUrl &source, const QString &targetNamespace) +{ + m_documentUri = QPatternist::XPathHelper::normalizeQueryURI(source); + + m_schemaContext->setMessageHandler(messageHandler()); + m_schemaContext->setUriResolver(uriResolver()); + m_schemaContext->setNetworkAccessManager(networkAccessManager()); + + const QPatternist::AutoPtr<QNetworkReply> reply(QPatternist::AccelTreeResourceLoader::load(source, m_schemaContext->networkAccessManager(), + m_schemaContext, QPatternist::AccelTreeResourceLoader::ContinueOnError)); + if (reply) + load(reply.data(), source, targetNamespace); +} + +void QXmlSchemaPrivate::load(const QByteArray &data, const QUrl &documentUri, const QString &targetNamespace) +{ + QByteArray localData(data); + + QBuffer buffer(&localData); + buffer.open(QIODevice::ReadOnly); + + load(&buffer, documentUri, targetNamespace); +} + +void QXmlSchemaPrivate::load(QIODevice *source, const QUrl &documentUri, const QString &targetNamespace) +{ + m_schemaParserContext = QPatternist::XsdSchemaParserContext::Ptr(new QPatternist::XsdSchemaParserContext(m_namePool.d, m_schemaContext)); + m_schemaIsValid = false; + + if (!source) { + qWarning("A null QIODevice pointer cannot be passed."); + return; + } + + if (!source->isReadable()) { + qWarning("The device must be readable."); + return; + } + + m_documentUri = QPatternist::XPathHelper::normalizeQueryURI(documentUri); + m_schemaContext->setMessageHandler(messageHandler()); + m_schemaContext->setUriResolver(uriResolver()); + m_schemaContext->setNetworkAccessManager(networkAccessManager()); + + QPatternist::XsdSchemaParser parser(m_schemaContext, m_schemaParserContext, source); + parser.setDocumentURI(documentUri); + parser.setTargetNamespace(targetNamespace); + + try { + parser.parse(); + m_schemaParserContext->resolver()->resolve(); + + m_schemaIsValid = true; + } catch (QPatternist::Exception exception) { + m_schemaIsValid = false; + } +} + +bool QXmlSchemaPrivate::isValid() const +{ + return m_schemaIsValid; +} + +QXmlNamePool QXmlSchemaPrivate::namePool() const +{ + return m_namePool; +} + +QUrl QXmlSchemaPrivate::documentUri() const +{ + return m_documentUri; +} + +void QXmlSchemaPrivate::setMessageHandler(QAbstractMessageHandler *handler) +{ + m_userMessageHandler = handler; +} + +QAbstractMessageHandler *QXmlSchemaPrivate::messageHandler() const +{ + if (m_userMessageHandler) + return m_userMessageHandler; + + return m_messageHandler.data()->value; +} + +void QXmlSchemaPrivate::setUriResolver(const QAbstractUriResolver *resolver) +{ + m_uriResolver = resolver; +} + +const QAbstractUriResolver *QXmlSchemaPrivate::uriResolver() const +{ + return m_uriResolver; +} + +void QXmlSchemaPrivate::setNetworkAccessManager(QNetworkAccessManager *networkmanager) +{ + m_userNetworkAccessManager = networkmanager; +} + +QNetworkAccessManager *QXmlSchemaPrivate::networkAccessManager() const +{ + if (m_userNetworkAccessManager) + return m_userNetworkAccessManager; + + return m_networkAccessManager.data()->value; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlschema_p.h b/src/xmlpatterns/api/qxmlschema_p.h new file mode 100644 index 0000000..2376fe3 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschema_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QXMLSCHEMA_P_H +#define QXMLSCHEMA_P_H + +#include "qabstractmessagehandler.h" +#include "qabstracturiresolver.h" +#include "qautoptr_p.h" +#include "qcoloringmessagehandler_p.h" +#include "qreferencecountedvalue_p.h" + +#include "qxsdschemacontext_p.h" +#include "qxsdschemaparser_p.h" +#include "qxsdschemaparsercontext_p.h" + +#include <QtCore/QSharedData> +#include <QtNetwork/QNetworkAccessManager> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlSchemaPrivate : public QSharedData +{ + public: + QXmlSchemaPrivate(const QXmlNamePool &namePool); + QXmlSchemaPrivate(const QPatternist::XsdSchemaContext::Ptr &schemaContext); + QXmlSchemaPrivate(const QXmlSchemaPrivate &other); + + void load(const QUrl &source, const QString &targetNamespace); + void load(QIODevice *source, const QUrl &documentUri, const QString &targetNamespace); + void load(const QByteArray &data, const QUrl &documentUri, const QString &targetNamespace); + bool isValid() const; + QXmlNamePool namePool() const; + QUrl documentUri() const; + void setMessageHandler(QAbstractMessageHandler *handler); + QAbstractMessageHandler *messageHandler() const; + void setUriResolver(const QAbstractUriResolver *resolver); + const QAbstractUriResolver *uriResolver() const; + void setNetworkAccessManager(QNetworkAccessManager *networkmanager); + QNetworkAccessManager *networkAccessManager() const; + + QXmlNamePool m_namePool; + QAbstractMessageHandler* m_userMessageHandler; + const QAbstractUriResolver* m_uriResolver; + QNetworkAccessManager* m_userNetworkAccessManager; + QPatternist::ReferenceCountedValue<QAbstractMessageHandler>::Ptr m_messageHandler; + QPatternist::ReferenceCountedValue<QNetworkAccessManager>::Ptr m_networkAccessManager; + + QPatternist::XsdSchemaContext::Ptr m_schemaContext; + QPatternist::XsdSchemaParserContext::Ptr m_schemaParserContext; + bool m_schemaIsValid; + QUrl m_documentUri; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlschemavalidator.cpp b/src/xmlpatterns/api/qxmlschemavalidator.cpp new file mode 100644 index 0000000..682d34f --- /dev/null +++ b/src/xmlpatterns/api/qxmlschemavalidator.cpp @@ -0,0 +1,349 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxmlschemavalidator.h" +#include "qxmlschemavalidator_p.h" + +#include "qacceltreeresourceloader_p.h" +#include "qxmlschema.h" +#include "qxmlschema_p.h" +#include "qxsdvalidatinginstancereader_p.h" + +#include <QtCore/QBuffer> +#include <QtCore/QIODevice> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +/*! + \class QXmlSchemaValidator + + \brief The QXmlSchemaValidator class validates XML instance documents against a W3C XML Schema. + + \reentrant + \since 4.6 + \ingroup xml-tools + + The QXmlSchemaValidator class loads, parses an XML instance document and validates it + against a W3C XML Schema that has been compiled with \l{QXmlSchema}. + + The following example shows how to load a XML Schema from a local + file, check whether it is a valid schema document and use it for validation + of an XML instance document: + + \snippet doc/src/snippets/qxmlschemavalidator/main.cpp 3 + + \section1 XML Schema Version + + This class implements schema validation according to the \l{XML Schema} 1.0 + specification. + + \sa QXmlSchema, {xmlpatterns/schema}{XML Schema Validation Example} +*/ + +/*! + Constructs a schema validator. + The schema used for validation must be referenced in the XML instance document + via the \c xsi:schemaLocation or \c xsi:noNamespaceSchemaLocation attribute. + */ +QXmlSchemaValidator::QXmlSchemaValidator() + : d(new QXmlSchemaValidatorPrivate(QXmlSchema())) +{ +} + +/*! + Constructs a schema validator that will use \a schema for validation. + If an empty \l {QXmlSchema} schema is passed to the validator, the schema used + for validation must be referenced in the XML instance document + via the \c xsi:schemaLocation or \c xsi:noNamespaceSchemaLocation attribute. + */ +QXmlSchemaValidator::QXmlSchemaValidator(const QXmlSchema &schema) + : d(new QXmlSchemaValidatorPrivate(schema)) +{ +} + +/*! + Destroys this QXmlSchemaValidator. + */ +QXmlSchemaValidator::~QXmlSchemaValidator() +{ + delete d; +} + +/*! + Sets the \a schema that shall be used for further validation. + If the schema is empty, the schema used for validation must be referenced + in the XML instance document via the \c xsi:schemaLocation or + \c xsi:noNamespaceSchemaLocation attribute. + */ +void QXmlSchemaValidator::setSchema(const QXmlSchema &schema) +{ + d->setSchema(schema); +} + +/*! + Validates the XML instance document read from \a data with the + given \a documentUri against the schema. + + Returns \c true if the XML instance document is valid according to the + schema, \c false otherwise. + + Example: + + \snippet doc/src/snippets/qxmlschemavalidator/main.cpp 2 + */ +bool QXmlSchemaValidator::validate(const QByteArray &data, const QUrl &documentUri) const +{ + QByteArray localData(data); + + QBuffer buffer(&localData); + buffer.open(QIODevice::ReadOnly); + + return validate(&buffer, documentUri); +} + +/*! + Validates the XML instance document read from \a source against the schema. + + Returns \c true if the XML instance document is valid according to the + schema, \c false otherwise. + + Example: + + \snippet doc/src/snippets/qxmlschemavalidator/main.cpp 0 + */ +bool QXmlSchemaValidator::validate(const QUrl &source) const +{ + d->m_context->setMessageHandler(messageHandler()); + d->m_context->setUriResolver(uriResolver()); + d->m_context->setNetworkAccessManager(networkAccessManager()); + + const QPatternist::AutoPtr<QNetworkReply> reply(QPatternist::AccelTreeResourceLoader::load(source, d->m_context->networkAccessManager(), + d->m_context, QPatternist::AccelTreeResourceLoader::ContinueOnError)); + if (reply) + return validate(reply.data(), source); + else + return false; +} + +/*! + Validates the XML instance document read from \a source with the + given \a documentUri against the schema. + + Returns \c true if the XML instance document is valid according to the + schema, \c false otherwise. + + Example: + + \snippet doc/src/snippets/qxmlschemavalidator/main.cpp 1 + */ +bool QXmlSchemaValidator::validate(QIODevice *source, const QUrl &documentUri) const +{ + if (!source) { + qWarning("A null QIODevice pointer cannot be passed."); + return false; + } + + if (!source->isReadable()) { + qWarning("The device must be readable."); + return false; + } + + const QUrl normalizedUri = QPatternist::XPathHelper::normalizeQueryURI(documentUri); + + d->m_context->setMessageHandler(messageHandler()); + d->m_context->setUriResolver(uriResolver()); + d->m_context->setNetworkAccessManager(networkAccessManager()); + + QPatternist::NetworkAccessDelegator::Ptr delegator(new QPatternist::NetworkAccessDelegator(d->m_context->networkAccessManager(), + d->m_context->networkAccessManager())); + + QPatternist::AccelTreeResourceLoader loader(d->m_context->namePool(), delegator, QPatternist::AccelTreeBuilder<true>::SourceLocationsFeature); + + QPatternist::Item item; + try { + item = loader.openDocument(source, normalizedUri, d->m_context); + } catch (QPatternist::Exception exception) { + return false; + } + + QXmlNodeModelIndex index = item.asNode(); + const QAbstractXmlNodeModel *model = item.asNode().model(); + + QPatternist::XsdValidatedXmlNodeModel *validatedModel = new QPatternist::XsdValidatedXmlNodeModel(model); + + QPatternist::XsdValidatingInstanceReader reader(validatedModel, normalizedUri, d->m_context); + if (d->m_schema) + reader.addSchema(d->m_schema, d->m_schemaDocumentUri); + try { + reader.read(); + } catch (QPatternist::Exception exception) { + return false; + } + + return true; +} + +/*! + Returns the name pool used by this QXmlSchemaValidator for constructing \l + {QXmlName} {names}. There is no setter for the name pool, because + mixing name pools causes errors due to name confusion. + */ +QXmlNamePool QXmlSchemaValidator::namePool() const +{ + return d->m_namePool; +} + +/*! + Returns the schema that is used for validation. + */ +QXmlSchema QXmlSchemaValidator::schema() const +{ + return d->m_originalSchema; +} + +/*! + Changes the \l {QAbstractMessageHandler}{message handler} for this + QXmlSchemaValidator to \a handler. The schema validator sends all parsing and + validation messages to this message handler. QXmlSchemaValidator does not take + ownership of \a handler. + + Normally, the default message handler is sufficient. It writes + compile and validation messages to \e stderr. The default message + handler includes color codes if \e stderr can render colors. + + When QXmlSchemaValidator calls QAbstractMessageHandler::message(), + the arguments are as follows: + + \table + \header + \o message() argument + \o Semantics + \row + \o QtMsgType type + \o Only QtWarningMsg and QtFatalMsg are used. The former + identifies a warning, while the latter identifies an error. + \row + \o const QString & description + \o An XHTML document which is the actual message. It is translated + into the current language. + \row + \o const QUrl &identifier + \o Identifies the error with a URI, where the fragment is + the error code, and the rest of the URI is the error namespace. + \row + \o const QSourceLocation & sourceLocation + \o Identifies where the error occurred. + \endtable + + */ +void QXmlSchemaValidator::setMessageHandler(QAbstractMessageHandler *handler) +{ + d->m_userMessageHandler = handler; +} + +/*! + Returns the message handler that handles parsing and validation + messages for this QXmlSchemaValidator. + */ +QAbstractMessageHandler *QXmlSchemaValidator::messageHandler() const +{ + if (d->m_userMessageHandler) + return d->m_userMessageHandler; + + return d->m_messageHandler.data()->value; +} + +/*! + Sets the URI resolver to \a resolver. QXmlSchemaValidator does not take + ownership of \a resolver. + + \sa uriResolver() + */ +void QXmlSchemaValidator::setUriResolver(const QAbstractUriResolver *resolver) +{ + d->m_uriResolver = resolver; +} + +/*! + Returns the schema's URI resolver. If no URI resolver has been set, + QtXmlPatterns will use the URIs in instance documents as they are. + + The URI resolver provides a level of abstraction, or \e{polymorphic + URIs}. A resolver can rewrite \e{logical} URIs to physical ones, or + it can translate obsolete or invalid URIs to valid ones. + + When QtXmlPatterns calls QAbstractUriResolver::resolve() the + absolute URI is the URI mandated by the schema specification, and the + relative URI is the URI specified by the user. + + \sa setUriResolver() + */ +const QAbstractUriResolver *QXmlSchemaValidator::uriResolver() const +{ + return d->m_uriResolver; +} + +/*! + Sets the network manager to \a manager. + QXmlSchemaValidator does not take ownership of \a manager. + + \sa networkAccessManager() + */ +void QXmlSchemaValidator::setNetworkAccessManager(QNetworkAccessManager *manager) +{ + d->m_userNetworkAccessManager = manager; +} + +/*! + Returns the network manager, or 0 if it has not been set. + + \sa setNetworkAccessManager() + */ +QNetworkAccessManager *QXmlSchemaValidator::networkAccessManager() const +{ + if (d->m_userNetworkAccessManager) + return d->m_userNetworkAccessManager; + + return d->m_networkAccessManager.data()->value; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlschemavalidator.h b/src/xmlpatterns/api/qxmlschemavalidator.h new file mode 100644 index 0000000..7121d19 --- /dev/null +++ b/src/xmlpatterns/api/qxmlschemavalidator.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLSCHEMAVALIDATOR_H +#define QXMLSCHEMAVALIDATOR_H + +#include <QtCore/QUrl> +#include <QtXmlPatterns/QXmlNamePool> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QAbstractMessageHandler; +class QAbstractUriResolver; +class QIODevice; +class QNetworkAccessManager; +class QUrl; +class QXmlNamePool; +class QXmlSchema; +class QXmlSchemaValidatorPrivate; + +class Q_XMLPATTERNS_EXPORT QXmlSchemaValidator +{ + public: + QXmlSchemaValidator(); + QXmlSchemaValidator(const QXmlSchema &schema); + ~QXmlSchemaValidator(); + + void setSchema(const QXmlSchema &schema); + + bool validate(const QUrl &source) const; + bool validate(QIODevice *source, const QUrl &documentUri = QUrl()) const; + bool validate(const QByteArray &data, const QUrl &documentUri = QUrl()) const; + + QXmlNamePool namePool() const; + QXmlSchema schema() const; + + void setMessageHandler(QAbstractMessageHandler *handler); + QAbstractMessageHandler *messageHandler() const; + + void setUriResolver(const QAbstractUriResolver *resolver); + const QAbstractUriResolver *uriResolver() const; + + void setNetworkAccessManager(QNetworkAccessManager *networkmanager); + QNetworkAccessManager *networkAccessManager() const; + + private: + QXmlSchemaValidatorPrivate* const d; + + Q_DISABLE_COPY(QXmlSchemaValidator) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlschemavalidator_p.h b/src/xmlpatterns/api/qxmlschemavalidator_p.h new file mode 100644 index 0000000..fb9492a --- /dev/null +++ b/src/xmlpatterns/api/qxmlschemavalidator_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QXMLSCHEMAVALIDATOR_P_H +#define QXMLSCHEMAVALIDATOR_P_H + +#include "qabstractmessagehandler.h" +#include "qabstracturiresolver.h" +#include "qautoptr_p.h" +#include "qcoloringmessagehandler_p.h" +#include "qxmlschema.h" +#include "qxmlschema_p.h" + +#include "qxsdschemacontext_p.h" +#include "qxsdschema_p.h" + +#include <QtNetwork/QNetworkAccessManager> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlSchemaValidatorPrivate +{ +public: + QXmlSchemaValidatorPrivate(const QXmlSchema &schema) + : m_namePool(schema.namePool()) + , m_userMessageHandler(0) + , m_uriResolver(0) + , m_userNetworkAccessManager(0) + { + setSchema(schema); + + const QXmlSchemaPrivate *p = schema.d; + + // initialize the environment properties with the ones from the schema + + if (p->m_userNetworkAccessManager) // schema has user defined network access manager + m_userNetworkAccessManager = p->m_userNetworkAccessManager; + else + m_networkAccessManager = p->m_networkAccessManager; + + if (p->m_userMessageHandler) // schema has user defined message handler + m_userMessageHandler = p->m_userMessageHandler; + else + m_messageHandler = p->m_messageHandler; + + m_uriResolver = p->m_uriResolver; + } + + void setSchema(const QXmlSchema &schema) + { + // use same name pool as the schema + m_namePool = schema.namePool(); + m_schema = schema.d->m_schemaParserContext->schema(); + m_schemaDocumentUri = schema.documentUri(); + + // create a new schema context + m_context = QPatternist::XsdSchemaContext::Ptr(new QPatternist::XsdSchemaContext(m_namePool.d)); + m_context->m_schemaTypeFactory = schema.d->m_schemaContext->m_schemaTypeFactory; + m_context->m_builtinTypesFacetList = schema.d->m_schemaContext->m_builtinTypesFacetList; + + m_originalSchema = schema; + } + + QXmlNamePool m_namePool; + QAbstractMessageHandler* m_userMessageHandler; + const QAbstractUriResolver* m_uriResolver; + QNetworkAccessManager* m_userNetworkAccessManager; + QPatternist::ReferenceCountedValue<QAbstractMessageHandler>::Ptr m_messageHandler; + QPatternist::ReferenceCountedValue<QNetworkAccessManager>::Ptr m_networkAccessManager; + + QXmlSchema m_originalSchema; + QPatternist::XsdSchemaContext::Ptr m_context; + QPatternist::XsdSchema::Ptr m_schema; + QUrl m_schemaDocumentUri; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlserializer.cpp b/src/xmlpatterns/api/qxmlserializer.cpp new file mode 100644 index 0000000..5849e16 --- /dev/null +++ b/src/xmlpatterns/api/qxmlserializer.cpp @@ -0,0 +1,653 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdynamiccontext_p.h" +#include "qpatternistlocale_p.h" +#include "qitem_p.h" +#include "qxmlquery_p.h" +#include "qxmlserializer_p.h" +#include "qxmlserializer.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +QXmlSerializerPrivate::QXmlSerializerPrivate(const QXmlQuery &query, + QIODevice *outputDevice) + : isPreviousAtomic(false), + state(QXmlSerializer::BeforeDocumentElement), + np(query.namePool().d), + device(outputDevice), + codec(QTextCodec::codecForMib(106)), /* UTF-8 */ + query(query) +{ + hasClosedElement.reserve(EstimatedTreeDepth); + namespaces.reserve(EstimatedTreeDepth); + nameCache.reserve(EstimatedNameCount); + + hasClosedElement.push(qMakePair(QXmlName(), true)); + + /* + We push the empty namespace such that first of all + namespaceBinding() won't assert on an empty QStack, + and such that the empty namespace is in-scope and + that the code doesn't attempt to declare it. + + We push the XML namespace. Although we won't receive + declarations for it, we may output attributes by that + name. + */ + QVector<QXmlName> defNss; + defNss.resize(2); + defNss[0] = QXmlName(StandardNamespaces::empty, + StandardLocalNames::empty, + StandardPrefixes::empty); + defNss[1] = QXmlName(StandardNamespaces::xml, + StandardLocalNames::empty, + StandardPrefixes::xml); + + namespaces.push(defNss); + + /* If we don't set this flag, QTextCodec will generate a BOM. */ + converterState.flags = QTextCodec::IgnoreHeader; +} + +/*! + \class QXmlSerializer + \brief The QXmlSerializer class is an implementation of QAbstractXmlReceiver for transforming XQuery output into unformatted XML. + + \reentrant + \since 4.4 + \ingroup xml-tools + + QXmlSerializer translates an \l {XQuery Sequence} {XQuery sequence}, usually + the output of an QXmlQuery, into XML. Consider the example: + + \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlserializer.cpp 0 + + First it constructs a \l {QXmlQuery} {query} that gets the + first paragraph from document \c index.html. Then it constructs + an instance of this class with the \l {QXmlQuery} {query} and + \l {QIODevice} {myOutputDevice}. Finally, it + \l {QXmlQuery::evaluateTo()} {evaluates} the + \l {QXmlQuery} {query}, producing an ordered sequence of calls + to the serializer's callback functions. The sequence of callbacks + transforms the query output to XML and writes it to + \l {QIODevice} {myOutputDevice}. + + QXmlSerializer will: + + \list + \o Declare namespaces when needed, + + \o Use appropriate escaping, when characters can't be + represented in the XML, + + \o Handle line endings appropriately, + + \o Report errors, when it can't serialize the content, e.g., + when asked to serialize an attribute that is a top-level node, + or when more than one top-level element is encountered. + + \endlist + + If an error occurs during serialization, result is undefined + unless the serializer is driven through a call to + QXmlQuery::evaluateTo(). + + If the generated XML should be indented and formatted for reading, + use QXmlFormatter. + + \sa {http://www.w3.org/TR/xslt-xquery-serialization/}{XSLT 2.0 and XQuery 1.0 Serialization} + + \sa QXmlFormatter + */ + +/*! + Constructs a serializer that uses the name pool and message + handler in \a query, and writes the output to \a outputDevice. + + \a outputDevice must be a valid, non-null device that is open in + write mode, otherwise behavior is undefined. + + \a outputDevice must not be opened with QIODevice::Text because it + will cause the output to be incorrect. This class will ensure line + endings are serialized as according with the XML specification. + QXmlSerializer does not take ownership of \a outputDevice. + */ +QXmlSerializer::QXmlSerializer(const QXmlQuery &query, + QIODevice *outputDevice) : QAbstractXmlReceiver(new QXmlSerializerPrivate(query, outputDevice)) +{ + if(!outputDevice) + { + qWarning("outputDevice cannot be null."); + return; + } + + if(!outputDevice->isWritable()) + { + qWarning("outputDevice must be opened in write mode."); + return; + } +} + +/*! + \internal + */ +QXmlSerializer::QXmlSerializer(QAbstractXmlReceiverPrivate *d) : QAbstractXmlReceiver(d) +{ +} + +/*! + \internal + */ +bool QXmlSerializer::atDocumentRoot() const +{ + Q_D(const QXmlSerializer); + return d->state == BeforeDocumentElement || + (d->state == InsideDocumentElement && d->hasClosedElement.size() == 1); +} + +/*! + \internal + */ +void QXmlSerializer::startContent() +{ + Q_D(QXmlSerializer); + if (!d->hasClosedElement.top().second) { + d->write('>'); + d->hasClosedElement.top().second = true; + } +} + +/*! + \internal + */ +void QXmlSerializer::writeEscaped(const QString &toEscape) +{ + if(toEscape.isEmpty()) /* Early exit. */ + return; + + QString result; + result.reserve(int(toEscape.length() * 1.1)); + const int length = toEscape.length(); + + for(int i = 0; i < length; ++i) + { + const QChar c(toEscape.at(i)); + + if(c == QLatin1Char('<')) + result += QLatin1String("<"); + else if(c == QLatin1Char('>')) + result += QLatin1String(">"); + else if(c == QLatin1Char('&')) + result += QLatin1String("&"); + else + result += toEscape.at(i); + } + + write(result); +} + +/*! + \internal + */ +void QXmlSerializer::writeEscapedAttribute(const QString &toEscape) +{ + if(toEscape.isEmpty()) /* Early exit. */ + return; + + QString result; + result.reserve(int(toEscape.length() * 1.1)); + const int length = toEscape.length(); + + for(int i = 0; i < length; ++i) + { + const QChar c(toEscape.at(i)); + + if(c == QLatin1Char('<')) + result += QLatin1String("<"); + else if(c == QLatin1Char('>')) + result += QLatin1String(">"); + else if(c == QLatin1Char('&')) + result += QLatin1String("&"); + else if(c == QLatin1Char('"')) + result += QLatin1String("""); + else + result += toEscape.at(i); + } + + write(result); +} + +/*! + \internal + */ +void QXmlSerializer::write(const QString &content) +{ + Q_D(QXmlSerializer); + d->device->write(d->codec->fromUnicode(content.constData(), content.length(), &d->converterState)); +} + +/*! + \internal + */ +void QXmlSerializer::write(const QXmlName &name) +{ + Q_D(QXmlSerializer); + const QByteArray &cell = d->nameCache[name.code()]; + + if(cell.isNull()) + { + QByteArray &mutableCell = d->nameCache[name.code()]; + + const QString content(d->np->toLexical(name)); + mutableCell = d->codec->fromUnicode(content.constData(), + content.length(), + &d->converterState); + d->device->write(mutableCell); + } + else + d->device->write(cell); +} + +/*! + \internal + */ +void QXmlSerializer::write(const char *const chars) +{ + Q_D(QXmlSerializer); + d->device->write(chars); +} + +/*! + \reimp + */ +void QXmlSerializer::startElement(const QXmlName &name) +{ + Q_D(QXmlSerializer); + Q_ASSERT(d->device); + Q_ASSERT(d->device->isWritable()); + Q_ASSERT(d->codec); + Q_ASSERT(!name.isNull()); + + d->namespaces.push(QVector<QXmlName>()); + + if(atDocumentRoot()) + { + if(d->state == BeforeDocumentElement) + d->state = InsideDocumentElement; + else if(d->state != InsideDocumentElement) + { + d->query.d->staticContext()->error(QtXmlPatterns::tr( + "Element %1 can't be serialized because it appears outside " + "the document element.").arg(formatKeyword(d->np, name)), + ReportContext::SENR0001, + d->query.d->expression().data()); + } + } + + startContent(); + d->write('<'); + write(name); + + /* Ensure that the namespace URI used in the name gets outputted. */ + namespaceBinding(name); + + d->hasClosedElement.push(qMakePair(name, false)); + d->isPreviousAtomic = false; +} + +/*! + \reimp + */ +void QXmlSerializer::endElement() +{ + Q_D(QXmlSerializer); + const QPair<QXmlName, bool> e(d->hasClosedElement.pop()); + d->namespaces.pop(); + + if(e.second) + { + write("</"); + write(e.first); + d->write('>'); + } + else + write("/>"); + + d->isPreviousAtomic = false; +} + +/*! + \reimp + */ +void QXmlSerializer::attribute(const QXmlName &name, + const QStringRef &value) +{ + Q_D(QXmlSerializer); + Q_ASSERT(!name.isNull()); + + /* Ensure that the namespace URI used in the name gets outputted. */ + { + /* Since attributes doesn't pick up the default namespace, a + * namespace declaration would cause trouble if we output it. */ + if(name.prefix() != StandardPrefixes::empty) + namespaceBinding(name); + } + + if(atDocumentRoot()) + { + Q_UNUSED(d); + d->query.d->staticContext()->error(QtXmlPatterns::tr( + "Attribute %1 can't be serialized because it appears at " + "the top level.").arg(formatKeyword(d->np, name)), + ReportContext::SENR0001, + d->query.d->expression().data()); + } + else + { + d->write(' '); + write(name); + write("=\""); + writeEscapedAttribute(value.toString()); + d->write('"'); + } +} + +/*! + \internal + */ +bool QXmlSerializer::isBindingInScope(const QXmlName nb) const +{ + Q_D(const QXmlSerializer); + const int levelLen = d->namespaces.size(); + + if(nb.prefix() == StandardPrefixes::empty) + { + for(int lvl = levelLen - 1; lvl >= 0; --lvl) + { + const QVector<QXmlName> &scope = d->namespaces.at(lvl); + const int vectorLen = scope.size(); + + for(int s = vectorLen - 1; s >= 0; --s) + { + const QXmlName &nsb = scope.at(s); + + if(nsb.prefix() == StandardPrefixes::empty) + return nsb.namespaceURI() == nb.namespaceURI(); + } + } + } + else + { + for(int lvl = 0; lvl < levelLen; ++lvl) + { + const QVector<QXmlName> &scope = d->namespaces.at(lvl); + const int vectorLen = scope.size(); + + for(int s = 0; s < vectorLen; ++s) + { + const QXmlName &n = scope.at(s); + if (n.prefix() == nb.prefix() && + n.namespaceURI() == nb.namespaceURI()) + return true; + } + } + } + + return false; +} + +/*! + \reimp + */ +void QXmlSerializer::namespaceBinding(const QXmlName &nb) +{ + /* + * Writes out \a nb. + * + * Namespace bindings aren't looked up in a cache, because + * we typically receive very few. + */ + + Q_D(QXmlSerializer); + Q_ASSERT_X(!nb.isNull(), Q_FUNC_INFO, + "It makes no sense to pass a null QXmlName."); + + Q_ASSERT_X((nb.namespaceURI() != StandardNamespaces::empty) || + (nb.prefix() == StandardPrefixes::empty), + Q_FUNC_INFO, + "Undeclarations of prefixes aren't allowed in XML 1.0 " + "and aren't supposed to be received."); + + if(nb.namespaceURI() == QPatternist::StandardNamespaces::StopNamespaceInheritance) + return; + + if(isBindingInScope(nb)) + return; + + d->namespaces.top().append(nb); + + if(nb.prefix() == StandardPrefixes::empty) + write(" xmlns"); + else + { + write(" xmlns:"); + write(d->np->stringForPrefix(nb.prefix())); + } + + write("=\""); + writeEscapedAttribute(d->np->stringForNamespace(nb.namespaceURI())); + d->write('"'); +} + +/*! + \reimp + */ +void QXmlSerializer::comment(const QString &value) +{ + Q_D(QXmlSerializer); + Q_ASSERT_X(!value.contains(QLatin1String("--")), + Q_FUNC_INFO, + "Invalid input; it's the caller's responsibility to ensure " + "the input is correct."); + + startContent(); + write("<!--"); + write(value); + write("-->"); + d->isPreviousAtomic = false; +} + +/*! + \reimp + */ +void QXmlSerializer::characters(const QStringRef &value) +{ + Q_D(QXmlSerializer); + d->isPreviousAtomic = false; + startContent(); + writeEscaped(value.toString()); +} + +/*! + \reimp + */ +void QXmlSerializer::processingInstruction(const QXmlName &name, + const QString &value) +{ + Q_D(QXmlSerializer); + Q_ASSERT_X(!value.contains(QLatin1String("?>")), + Q_FUNC_INFO, + "Invalid input; it's the caller's responsibility to ensure " + "the input is correct."); + + startContent(); + write("<?"); + write(name); + d->write(' '); + write(value); + write("?>"); + + d->isPreviousAtomic = false; +} + +/*! + \internal + */ +void QXmlSerializer::item(const QPatternist::Item &outputItem) +{ + Q_D(QXmlSerializer); + + if(outputItem.isAtomicValue()) + { + if(d->isPreviousAtomic) + { + startContent(); + d->write(' '); + writeEscaped(outputItem.stringValue()); + } + else + { + d->isPreviousAtomic = true; + const QString value(outputItem.stringValue()); + + if(!value.isEmpty()) + { + startContent(); + writeEscaped(value); + } + } + } + else + { + startContent(); + Q_ASSERT(outputItem.isNode()); + sendAsNode(outputItem); + } +} + +/*! + \reimp + */ +void QXmlSerializer::atomicValue(const QVariant &value) +{ + Q_UNUSED(value); +} + +/*! + \reimp + */ +void QXmlSerializer::startDocument() +{ + Q_D(QXmlSerializer); + d->isPreviousAtomic = false; +} + +/*! + \reimp + */ +void QXmlSerializer::endDocument() +{ + Q_D(QXmlSerializer); + d->isPreviousAtomic = false; +} + +/*! + + Returns a pointer to the output device. There is no corresponding + function to \e set the output device, because the output device must + be passed to the constructor. The serializer does not take ownership + of its IO device. + */ +QIODevice *QXmlSerializer::outputDevice() const +{ + Q_D(const QXmlSerializer); + return d->device; +} + +/*! + Sets the codec the serializer will use for encoding its XML output. + The output codec is set to \a outputCodec. By default, the output + codec is set to the one for \c UTF-8. The serializer does not take + ownership of the codec. + + \sa codec() + + */ +void QXmlSerializer::setCodec(const QTextCodec *outputCodec) +{ + Q_D(QXmlSerializer); + d->codec = outputCodec; +} + +/*! + Returns the codec being used by the serializer for encoding its + XML output. + + \sa setCodec() + */ +const QTextCodec *QXmlSerializer::codec() const +{ + Q_D(const QXmlSerializer); + return d->codec; +} + +/*! + \reimp + */ +void QXmlSerializer::startOfSequence() +{ +} + +/*! + \reimp + */ +void QXmlSerializer::endOfSequence() +{ + /* If this function is changed to flush or close or something like that, + * take into consideration QXmlFormatter, especially + * QXmlFormatter::endOfSequence(). + */ +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qxmlserializer.h b/src/xmlpatterns/api/qxmlserializer.h new file mode 100644 index 0000000..ae0a69e --- /dev/null +++ b/src/xmlpatterns/api/qxmlserializer.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXMLSERIALIZER_H +#define QXMLSERIALIZER_H + +#include <QtXmlPatterns/QAbstractXmlReceiver> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(XmlPatterns) + +class QIODevice; +class QTextCodec; +class QXmlQuery; +class QXmlSerializerPrivate; + +class Q_XMLPATTERNS_EXPORT QXmlSerializer : public QAbstractXmlReceiver +{ +public: + QXmlSerializer(const QXmlQuery &query, + QIODevice *outputDevice); + + virtual void namespaceBinding(const QXmlName &nb); + + virtual void characters(const QStringRef &value); + virtual void comment(const QString &value); + + virtual void startElement(const QXmlName &name); + + virtual void endElement(); + + virtual void attribute(const QXmlName &name, + const QStringRef &value); + + virtual void processingInstruction(const QXmlName &name, + const QString &value); + + virtual void atomicValue(const QVariant &value); + + virtual void startDocument(); + virtual void endDocument(); + virtual void startOfSequence(); + virtual void endOfSequence(); + + QIODevice *outputDevice() const; + + void setCodec(const QTextCodec *codec); + const QTextCodec *codec() const; + + /* The members below are internal, not part of the public API, and + * unsupported. Using them leads to undefined behavior. */ + virtual void item(const QPatternist::Item &item); +protected: + QXmlSerializer(QAbstractXmlReceiverPrivate *d); + +private: + inline bool isBindingInScope(const QXmlName nb) const; + + /** + * Where in the document the QXmlSerializer is currently working. + */ + enum State + { + /** + * Before the document element. This is the XML prolog where the + * XML declaration, and possibly comments and processing + * instructions are found. + */ + BeforeDocumentElement, + + /** + * This is inside the document element, at any level. + */ + InsideDocumentElement + }; + + /** + * If the current state is neither BeforeDocumentElement or + * AfterDocumentElement. + */ + inline bool atDocumentRoot() const; + + /** + * Closes any open element start tag. Must be called before outputting + * any element content. + */ + inline void startContent(); + + /** + * Escapes content intended as text nodes for elements. + */ + void writeEscaped(const QString &toEscape); + + /** + * Identical to writeEscaped(), but also escapes quotes. + */ + inline void writeEscapedAttribute(const QString &toEscape); + + /** + * Writes out @p name. + */ + inline void write(const QXmlName &name); + + inline void write(const char *const chars); + /** + * Encodes and writes out @p content. + */ + inline void write(const QString &content); + + Q_DECLARE_PRIVATE(QXmlSerializer) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlserializer_p.h b/src/xmlpatterns/api/qxmlserializer_p.h new file mode 100644 index 0000000..8aa525d --- /dev/null +++ b/src/xmlpatterns/api/qxmlserializer_p.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QXMLSERIALIZER_P_H +#define QXMLSERIALIZER_P_H + +#include <QtCore/QIODevice> +#include <QtCore/QStack> +#include <QtCore/QTextCodec> +#include <QtXmlPatterns/QXmlQuery> +#include <QtXmlPatterns/QXmlNamePool> +#include <QtXmlPatterns/QXmlSerializer> + +#include "qnamepool_p.h" +#include "qabstractxmlreceiver_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlSerializerPrivate : public QAbstractXmlReceiverPrivate +{ +public: + QXmlSerializerPrivate(const QXmlQuery &q, + QIODevice *outputDevice); + + QStack<QPair<QXmlName, bool> > hasClosedElement; + bool isPreviousAtomic; + QXmlSerializer::State state; + const QPatternist::NamePool::Ptr np; + + /** + * This member worries me a bit. We never use it but nevertheless + * it is pushed and pops linear to startElement() and endElement(). + * An optimization would be to at least merge it with hasClosedElement, + * but even better to push it on demand. That is, namespaceBinding() + * pushes it up to the tree depth first when it is needed. + */ + QStack<QVector<QXmlName> > namespaces; + + QIODevice * device; + const QTextCodec * codec; + QTextCodec::ConverterState converterState; + /** + * Name cache. Since encoding QStrings are rather expensive + * operations to do, and we on top of that would have to do + * it each time a name appears, we here map names to their + * encoded equivalents. + * + * This means that when writing out large documents, the serialization + * of names after a while is reduced to a hash lookup and passing an + * existing byte array. + * + * We use QXmlName::Code as key as opposed to merely QName, because the + * prefix is of significance. + */ + QHash<QXmlName::Code, QByteArray> nameCache; + const QXmlQuery query; + + inline void write(const char c); + +private: + enum Constants + { + EstimatedTreeDepth = 10, + + /** + * We use a high count to avoid rehashing. We can afford it since we + * only allocate one hash for this. + */ + EstimatedNameCount = 60 + }; +}; + +void QXmlSerializerPrivate::write(const char c) +{ + device->putChar(c); +} +QT_END_NAMESPACE +QT_END_HEADER + +#endif |