[Qt-interest] QXmlStreamReader: Usage of readNextStartElement()?
Constantin Makshin
cmakshin at gmail.com
Tue Dec 21 22:42:35 CET 2010
The general idea is:
If you use readNextStartElement() and want to get to the next element
on the same level, then before calling this function again use
readElementText() if the current element may have text and
skipCurrentElement() otherwise.
On Tue, Dec 21, 2010 at 11:14 PM, Constantin Makshin <cmakshin at gmail.com> wrote:
> This works:
>
> QXmlStreamReader streamReader(&file);
> while (streamReader.readNextStartElement()) {
> printf("name: %s\n", qPrintable(streamReader.name().toString()));
> QXmlStreamAttributes attributes = streamReader.attributes();
> foreach(QXmlStreamAttribute attribute, attributes) {
> printf(" Attribute: name: %s, value: %s\n",
> qPrintable(attribute.name().toString()),
> qPrintable(attribute.value().toString()));
> }
> // !!!
> if (streamReader.name() != "foo")
> streamReader.readElementText();
> // !!!
> }
>
> The problem in your version is that when QXmlStreamReader encounters
> the "bar" element and reads its attributes, the current token is still
> QXmlStreamReader::StartElement and the next call to the
> readNextStartElement() tries to recurse into it, i.e. read child
> elements of the "bar" one. But since the "bar" element doesn't have
> any "subelements", the next token readNextStartElement() finds is
> QXmlStreamReader::EndElement, so the function returns "false" and your
> loop ends.
> readElementText(), on the other hand, reads element's text, so the
> token after if returns is QXmlStreamReader::EndElement. Then
> readNextStartElement() gets the next token, which is
> QXmlStreamReader::StartElement and therefore everything works as
> expected.
>
> On Tue, Dec 21, 2010 at 8:06 PM, <Oliver.Knoll at comit.ch> wrote:
>> Hi,
>>
>> I am having difficulties understanding the proper usage of QXmlStreamReader#readNextStartElement():
>>
>> When I have the following code snippet which should print out all element names and attributes:
>>
>> QXmlStreamReader streamReader(&file);
>> while (streamReader.readNextStartElement()) {
>>
>> qDebug("name: %s", qPrintable(streamReader.name().toString()));
>> QXmlStreamAttributes attributes = streamReader.attributes();
>> foreach(QXmlStreamAttribute attribute, attributes) {
>> qDebug(" Attribute: name: %s, value: %s", qPrintable(attribute.name().toString()), qPrintable(attribute.value().toString()));
>> }
>>
>> }
>>
>> And I have e.g.
>>
>> <?xml version="1.0" encoding="UTF-8"?>
>> <!DOCTYPE screenie>
>> <foo version="1.0">
>> <bar enabled="true" bgcolor="#ffffff"/>
>> <foobar baz="42"/>
>> <rabarber>Some text</rabarber>
>> </foo>
>>
>> I only get:
>>
>> name: foo
>> Attribute: name: version, value: 1.0
>> name: bar
>> Attribute: name: enabled, value: true
>> Attribute: name: bgcolor, value: #ffffff
>>
>> That is the parsing seems to stop after the 2nd element <bar .../>.
>>
>> >From the Qt docs http://doc.trolltech.com/4.7/qxmlstreamreader.html#readNextStartElement: "Reads until the next start element within the current element. [...]The current element is the element matching the most recently parsed start element of which a matching end element has not yet been reached."
>>
>> So let's assume that <foo> - the outermost "start element" as it seems to me - is the "current element", should I not get also the <foobar /> and <rababer /> elements? What really twists my mind is that I /do/ get the <bar> element, but why not the <foobar> and <rabarber> elements, which are at the same level as <bar>? So the time when readNextStartElement seems to stop is a mistery to me...
>>
>>
>> If on the other hand I iterate over the XML like this with readNext():
>>
>> while ((tokenType = streamReader.readNext()) != QXmlStreamReader::EndDocument) {
>> if (tokenType == QXmlStreamReader::StartElement) {
>> qDebug("name: %s", qPrintable(streamReader.name().toString()));
>> QXmlStreamAttributes attributes = streamReader.attributes();
>> foreach(QXmlStreamAttribute attribute, attributes) {
>> qDebug(" Attribute: name: %s, value: %s", qPrintable(attribute.name().toString()), qPrintable(attribute.value().toString()));
>> }
>> }
>>
>> I do get all elements as expected.
>>
>>
>> The only difference between my readNextStartElement() version and the http://doc.trolltech.com/4.7/xml-streambookmarks.html example seems to be that in the later they do a readElementText() and a skipCurrentElement() in between (and this example seems to work for me, at least with a simple *.xbel bookmark file. I have yet to try out a more complex one, e.g. with several "folders" or so). But other than that also this Qt example seems to simply iterate over the entire XML with readNextStartElement().
>>
>>
>> So what am I doing wrong? Is this supposed to work like I assume, or is this a bug? This is on Qt 4.7.1. Example code and test file attached.
>>
>> Cheers, Oliver
>>
>>
>>
>>
>>
>> --
>> Oliver Knoll
>> Dipl. Informatik-Ing. ETH
>> COMIT AG - ++41 79 520 95 22
More information about the Qt-interest-old
mailing list