diff options
author | Qt by Nokia <qt-info@nokia.com> | 2011-04-27 12:05:43 +0200 |
---|---|---|
committer | axis <qt-info@nokia.com> | 2011-04-27 12:05:43 +0200 |
commit | e1b2c9deb5943faae2b29be6a5c006f75bb73f06 (patch) | |
tree | fc79e45367c0a8fc71185e9afc33f7503a58653c /src/xmlpatterns/api | |
download | qtxmlpatterns-e1b2c9deb5943faae2b29be6a5c006f75bb73f06.tar.gz |
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:
http://qt.gitorious.org/qt/pages/GitIntroductionWithQt
If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.
Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
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 |