diff options
-rw-r--r-- | doc/src/examples/qxmlstreambookmarks.qdoc | 13 | ||||
-rw-r--r-- | examples/network/googlesuggest/googlesuggest.cpp | 7 | ||||
-rw-r--r-- | examples/xml/streambookmarks/xbelreader.cpp | 107 | ||||
-rw-r--r-- | examples/xml/streambookmarks/xbelreader.h | 1 | ||||
-rw-r--r-- | src/corelib/xml/qxmlstream.cpp | 49 | ||||
-rw-r--r-- | src/corelib/xml/qxmlstream.h | 3 | ||||
-rw-r--r-- | tests/auto/qxmlstream/tst_qxmlstream.cpp | 19 |
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; |