/****************************************************************************+ −
**+ −
** Copyright (C) 2010 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+ −
+ −