PDA

View Full Version : Parsing XML



Tomasz
9th December 2010, 23:33
Hello!

I'm trying to parse xml document:


<xml_api_reply version="1">
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0">

<forecast_information>
<city data="Gdansk, Pomerania"/>
<postal_code data="Gdansk,Poland"/>
<latitude_e6 data=""/>
<longitude_e6 data=""/>
<forecast_date data="2010-12-09"/>
<current_date_time data="2010-12-09 23:00:00 +0000"/>
<unit_system data="SI"/>
</forecast_information>

<current_conditions>
<condition data="Zachmurzenie"/>
<temp_f data="30"/>
<temp_c data="-1"/>
<humidity data="Wilgotność: 86%"/>
<icon data="/ig/images/weather/cloudy.gif"/>
<wind_condition data="Wiatr: płn.-zach. z szybkością 26 km/h"/>
</current_conditions>
[...]


My code:


ByteArray newData = NetRepl->read(2048);

out << newData << endl;

QXmlStreamReader xmlStream(newData);
while(!xmlStream.atEnd())
{
xmlStream.readNext();
if(xmlStream.isStartElement())
{
QString sec(xmlStream.name().toString());
out << sec << endl;

while (!xmlStream.isEndElement())
{
xmlStream.readNext();
QString sec(xmlStream.name().toString());
out << "***" << sec << endl;

QXmlStreamAttributes attrs = xmlStream.attributes();
out << attrs.value("data").toString() << endl;
}
}
}


And it sometimes returns "data" correctly, and sometimes it's empty:



xml_api_reply
***weather

***forecast_information

***city
Gdansk, Pomerania //OK
***city

postal_code
***postal_code

latitude_e6
***latitude_e6

longitude_e6
***longitude_e6

forecast_date
***forecast_date

current_date_time
***current_date_time

unit_system
***unit_system

current_conditions
***condition
Zachmurzenie //OK
***condition

temp_f
***temp_f

temp_c
***temp_c

humidity
***humidity

icon
***icon

wind_condition
***wind_condition


How should I do It correctly?

thanks in advance
best regards
Tomasz

wysota
10th December 2010, 00:36
What I usually do is that I break such code into several methods where each single method is responsible for parsing one tag (or level) of xml. Then it's easier to spot errors. You are not checking errors anywhere here and you should be since the data comes from the network. Try finding a pattern in failures of your parser.

xiaokui
10th December 2010, 03:14
the following code can help you.
you can get every value of "data".


QXmlStreamAttributes attrs = xmlStream.attributes();
if (attrs.hasAttribute("data")) {
xmlStream.readNextStartElement();
} else {
xmlStream.readNext();
}

Tomasz
10th December 2010, 11:30
I've broke code in couple methods and, and used attrs.hasAttribute() and now it works fine. One more question connected with thread. I'm reading XML document with:

header file:


private:
QNetworkAccessManager NetAccMan;
QNetworkReply *NetRepl;


main file:


void MainWindow::getXML()
{
QNetworkRequest request(QUrl("http://www.google.com/ig/api?weather=Gdansk,Poland&hl=pl"));
NetRepl = NetAccMan.get(request);
connect(NetRepl, SIGNAL(readyRead()), this, SLOT(parseXML()));
}

void MainWindow::parseXML()
{
}


But I'm wondering if I need to clear NetRepl or something after each read/parse, because as I assume QNetworkAccessManager creates QNetworkReply, and returns pointer to it each time I call getXML(); Maybe I should use same clearing function of QNetworkReply?

thanks in advance
best regards
Tomasz

wysota
10th December 2010, 13:44
QNetworkAccessManager docs should specify who is the owner of the network reply object.

Tomasz
11th December 2010, 17:26
QNetworkAccessManager docs should specify who is the owner of the network reply object.

It says about QNetworkReply * QNetworkAccessManager::get ( const QNetworkRequest & request ): "It returns a new QNetworkReply object opened for reading which emits its QIODevice::readyRead() signal whenever new data arrives.". So is QNetworkAccessManager owner of networ reply object? And takes care about this object after downloading data?

thanks in advance
best regards
Tomasz

wysota
11th December 2010, 17:42
I think this is more important:


Note: After the request has finished, it is the responsibility of the user to delete the QNetworkReply object at an appropriate time. Do not directly delete it inside the slot connected to finished(). You can use the deleteLater() function.

Tomasz
11th December 2010, 18:20
I was searching in function description. I didn't noticed that part in detailed description of class - sorry. So It would be all right if I put deleteLater() in my getXML() function at the end of it? Or Is it necessary to put it in slot connected to 'finished' signal?

thanks in advance
best regards
Tomasz

wysota
11th December 2010, 18:29
It's your responsibility to delete the object so you can do it whenever you want.