blob: e8127e03583e13349369b3704c1186463bdda06d [file] [log] [blame]
/****************************************************************************
**
** 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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $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