summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com>2009-08-17 14:55:58 (GMT)
committerThorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com>2009-08-18 17:10:56 (GMT)
commit393f5d5b2705c0ed7e6e1a3a69cc9cdf16cf334d (patch)
tree3b20e5280bf629e6360eaa35b23019e77b66a4c4
parente08ca6bcaf5fc746fdf8f3e379c17bf0a9daa771 (diff)
downloadQt-393f5d5b2705c0ed7e6e1a3a69cc9cdf16cf334d.zip
Qt-393f5d5b2705c0ed7e6e1a3a69cc9cdf16cf334d.tar.gz
Qt-393f5d5b2705c0ed7e6e1a3a69cc9cdf16cf334d.tar.bz2
Added two convenience functions to QXmlStreamReader
QXmlStreamReader::readNextStartElement reads until the next start element within the current element, or returns false when no such element is encountered before the end element is reached. It simplifies the common case of iterating over the elements in an XML document. QXmlStreamReader::skipCurrentElement reads until the end element of the current element, skipping any child elements. This functionality was requested in two tasks, and a similar function 'readUnknownElement' was present in Qt's stream reader example. Autotest is included, example and documentation have been updated. Task-number: 238793 Reviewed-by: mae
-rw-r--r--doc/src/examples/qxmlstreambookmarks.qdoc13
-rw-r--r--examples/network/googlesuggest/googlesuggest.cpp7
-rw-r--r--examples/xml/streambookmarks/xbelreader.cpp107
-rw-r--r--examples/xml/streambookmarks/xbelreader.h1
-rw-r--r--src/corelib/xml/qxmlstream.cpp49
-rw-r--r--src/corelib/xml/qxmlstream.h3
-rw-r--r--tests/auto/qxmlstream/tst_qxmlstream.cpp19
7 files changed, 114 insertions, 85 deletions
diff --git a/doc/src/examples/qxmlstreambookmarks.qdoc b/doc/src/examples/qxmlstreambookmarks.qdoc
index def4c47..26964c4 100644
--- a/doc/src/examples/qxmlstreambookmarks.qdoc
+++ b/doc/src/examples/qxmlstreambookmarks.qdoc
@@ -106,19 +106,18 @@
of reading only takes place if the file is a valid XBEL 1.0 file.
Note that the XML input needs to be well-formed to be accepted by
QXmlStreamReader. Otherwise, the \l{QXmlStreamReader::raiseError()}
- {raiseError()} function is used to display an error message.
+ {raiseError()} function is used to display an error message. Since the
+ XBEL reader is only concerned with reading XML elements, it makes
+ extensive use of the \l{QXmlStreamReader::readNextStartElement()}
+ convenience function.
\snippet examples/xml/streambookmarks/xbelreader.cpp 1
- The \c readUnknownElement() function reads an unknown element. The
- Q_ASSERT() macro is used to provide a pre-condition for the function.
-
- \snippet examples/xml/streambookmarks/xbelreader.cpp 2
-
The \c readXBEL() function reads the name of a startElement and calls
the appropriate function to read it, depending on whether if its a
"folder", "bookmark" or "separator". Otherwise, it calls
- \c readUnknownElement().
+ \l{QXmlStreamReader::skipCurrentElement()}. The Q_ASSERT() macro is used
+ to provide a pre-condition for the function.
\snippet examples/xml/streambookmarks/xbelreader.cpp 3
diff --git a/examples/network/googlesuggest/googlesuggest.cpp b/examples/network/googlesuggest/googlesuggest.cpp
index ada0edf..4142511 100644
--- a/examples/network/googlesuggest/googlesuggest.cpp
+++ b/examples/network/googlesuggest/googlesuggest.cpp
@@ -134,7 +134,6 @@ bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev)
void GSuggestCompletion::showCompletion(const QStringList &choices, const QStringList &hits)
{
-
if (choices.isEmpty() || choices.count() != hits.count())
return;
@@ -204,16 +203,16 @@ void GSuggestCompletion::handleNetworkData(QNetworkReply *networkReply)
QXmlStreamReader xml(response);
while (!xml.atEnd()) {
xml.readNext();
- if (xml.tokenType() == QXmlStreamReader::StartElement)
+ if (xml.isStartElement()) {
if (xml.name() == "suggestion") {
QStringRef str = xml.attributes().value("data");
choices << str.toString();
}
- if (xml.tokenType() == QXmlStreamReader::StartElement)
- if (xml.name() == "num_queries") {
+ else if (xml.name() == "num_queries") {
QStringRef str = xml.attributes().value("int");
hits << str.toString();
}
+ }
}
showCompletion(choices, hits);
diff --git a/examples/xml/streambookmarks/xbelreader.cpp b/examples/xml/streambookmarks/xbelreader.cpp
index 47c8c3d..729fcf8 100644
--- a/examples/xml/streambookmarks/xbelreader.cpp
+++ b/examples/xml/streambookmarks/xbelreader.cpp
@@ -62,59 +62,31 @@ bool XbelReader::read(QIODevice *device)
{
setDevice(device);
- while (!atEnd()) {
- readNext();
-
- if (isStartElement()) {
- if (name() == "xbel" && attributes().value("version") == "1.0")
- readXBEL();
- else
- raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
- }
+ if (readNextStartElement()) {
+ if (name() == "xbel" && attributes().value("version") == "1.0")
+ readXBEL();
+ else
+ raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
}
return !error();
}
//! [1]
-//! [2]
-void XbelReader::readUnknownElement()
-{
- Q_ASSERT(isStartElement());
-
- while (!atEnd()) {
- readNext();
-
- if (isEndElement())
- break;
-
- if (isStartElement())
- readUnknownElement();
- }
-}
-//! [2]
-
//! [3]
void XbelReader::readXBEL()
{
Q_ASSERT(isStartElement() && name() == "xbel");
- while (!atEnd()) {
- readNext();
-
- if (isEndElement())
- break;
-
- if (isStartElement()) {
- if (name() == "folder")
- readFolder(0);
- else if (name() == "bookmark")
- readBookmark(0);
- else if (name() == "separator")
- readSeparator(0);
- else
- readUnknownElement();
- }
+ while (readNextStartElement()) {
+ if (name() == "folder")
+ readFolder(0);
+ else if (name() == "bookmark")
+ readBookmark(0);
+ else if (name() == "separator")
+ readSeparator(0);
+ else
+ readUnknownElement();
}
}
//! [3]
@@ -132,10 +104,12 @@ void XbelReader::readTitle(QTreeWidgetItem *item)
//! [5]
void XbelReader::readSeparator(QTreeWidgetItem *item)
{
+ Q_ASSERT(isStartElement() && name() == "separator");
+
QTreeWidgetItem *separator = createChildItem(item);
separator->setFlags(item->flags() & ~Qt::ItemIsSelectable);
separator->setText(0, QString(30, 0xB7));
- readElementText();
+ skipCurrentElement();
}
//! [5]
@@ -147,24 +121,17 @@ void XbelReader::readFolder(QTreeWidgetItem *item)
bool folded = (attributes().value("folded") != "no");
treeWidget->setItemExpanded(folder, !folded);
- while (!atEnd()) {
- readNext();
-
- if (isEndElement())
- break;
-
- if (isStartElement()) {
- if (name() == "title")
- readTitle(folder);
- else if (name() == "folder")
- readFolder(folder);
- else if (name() == "bookmark")
- readBookmark(folder);
- else if (name() == "separator")
- readSeparator(folder);
- else
- readUnknownElement();
- }
+ while (readNextStartElement()) {
+ if (name() == "title")
+ readTitle(folder);
+ else if (name() == "folder")
+ readFolder(folder);
+ else if (name() == "bookmark")
+ readBookmark(folder);
+ else if (name() == "separator")
+ readSeparator(folder);
+ else
+ skipCurrentElement();
}
}
@@ -177,18 +144,12 @@ void XbelReader::readBookmark(QTreeWidgetItem *item)
bookmark->setIcon(0, bookmarkIcon);
bookmark->setText(0, QObject::tr("Unknown title"));
bookmark->setText(1, attributes().value("href").toString());
- while (!atEnd()) {
- readNext();
-
- if (isEndElement())
- break;
-
- if (isStartElement()) {
- if (name() == "title")
- readTitle(bookmark);
- else
- readUnknownElement();
- }
+
+ while (readNextStartElement()) {
+ if (name() == "title")
+ readTitle(bookmark);
+ else
+ skipCurrentElement();
}
}
diff --git a/examples/xml/streambookmarks/xbelreader.h b/examples/xml/streambookmarks/xbelreader.h
index 80f0a28..2debadc 100644
--- a/examples/xml/streambookmarks/xbelreader.h
+++ b/examples/xml/streambookmarks/xbelreader.h
@@ -62,7 +62,6 @@ public:
private:
//! [2]
- void readUnknownElement();
void readXBEL();
void readTitle(QTreeWidgetItem *item);
void readSeparator(QTreeWidgetItem *item);
diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp
index a08b167..8b2462e 100644
--- a/src/corelib/xml/qxmlstream.cpp
+++ b/src/corelib/xml/qxmlstream.cpp
@@ -622,6 +622,55 @@ QXmlStreamReader::TokenType QXmlStreamReader::tokenType() const
return d->type;
}
+/*!
+ Reads until the next start element within the current element. Returns true
+ when a start element was reached. When the end element was reached, or when
+ an error occurred, false is returned.
+
+ The current element is the element matching the most recently parsed start
+ element of which a matching end element has not yet been reached. When the
+ parser has reached the end element, the current element becomes the parent
+ element.
+
+ This is a convenience function for when you're only concerned with parsing
+ XML elements. The \l{QXmlStream Bookmarks Example} makes extensive use of
+ this function.
+
+ \since 4.6
+ */
+bool QXmlStreamReader::readNextStartElement()
+{
+ while (readNext() != Invalid) {
+ if (isEndElement())
+ return false;
+ else if (isStartElement())
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Reads until the end of the current element, skipping any child nodes.
+ This function is useful for skipping unknown elements.
+
+ The current element is the element matching the most recently parsed start
+ element of which a matching end element has not yet been reached. When the
+ parser has reached the end element, the current element becomes the parent
+ element.
+
+ \since 4.6
+ */
+void QXmlStreamReader::skipCurrentElement()
+{
+ int depth = 1;
+ while (depth && readNext() != Invalid) {
+ if (isEndElement())
+ --depth;
+ else if (isStartElement())
+ ++depth;
+ }
+}
+
/*
* Use the following Perl script to generate the error string index list:
===== PERL SCRIPT ====
diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h
index 420a66a..21dcb40 100644
--- a/src/corelib/xml/qxmlstream.h
+++ b/src/corelib/xml/qxmlstream.h
@@ -321,6 +321,9 @@ public:
bool atEnd() const;
TokenType readNext();
+ bool readNextStartElement();
+ void skipCurrentElement();
+
TokenType tokenType() const;
QString tokenString() const;
diff --git a/tests/auto/qxmlstream/tst_qxmlstream.cpp b/tests/auto/qxmlstream/tst_qxmlstream.cpp
index 375528c..f496dcf 100644
--- a/tests/auto/qxmlstream/tst_qxmlstream.cpp
+++ b/tests/auto/qxmlstream/tst_qxmlstream.cpp
@@ -550,6 +550,7 @@ private slots:
void setEntityResolver();
void readFromQBuffer() const;
void readFromQBufferInvalid() const;
+ void readNextStartElement() const;
void crashInUTF16Codec() const;
void hasAttributeSignature() const;
void hasAttribute() const;
@@ -1107,6 +1108,24 @@ void tst_QXmlStream::readFromQBufferInvalid() const
QVERIFY(reader.hasError());
}
+void tst_QXmlStream::readNextStartElement() const
+{
+ QLatin1String in("<?xml version=\"1.0\"?><A><!-- blah --><B><C/></B><B attr=\"value\"/>text</A>");
+ QXmlStreamReader reader(in);
+
+ QVERIFY(reader.readNextStartElement());
+ QVERIFY(reader.isStartElement() && reader.name() == "A");
+
+ int amountOfB = 0;
+ while (reader.readNextStartElement()) {
+ QVERIFY(reader.isStartElement() && reader.name() == "B");
+ ++amountOfB;
+ reader.skipCurrentElement();
+ }
+
+ QCOMPARE(amountOfB, 2);
+}
+
void tst_QXmlStream::crashInUTF16Codec() const
{
QEventLoop eventLoop;