Search code examples
c++xmlparsingtinyxml2

Why does this code produce 4 times nothing and the fifth time the correct data?


I got an XML-file:

<weatherdata>
	<location>
		<name>Vlaardingen</name>
		<type/>
		<country>NL</country>
		<timezone/>
		<location altitude="0"
				latitude="51.912498"
				longitude="4.34167"
				geobase="geonames"
				geobaseid="2745467"/>
	</location>
	<credit/>
	<meta>
		<lastupdate/>
		<calctime>0.0152</calctime>
		<nextupdate/>
	</meta>
	<sun rise="2016-02-23T06:40:58"
			set="2016-02-23T17:11:47"/>
	<forecast>
		<time day="2016-02-23">
			<symbol number="500"
					name="lichte regen"
					var="10d"/>
			<precipitation/>
			<windDirection deg="316"
					code="NW"
					name="Northwest"/>
			<windSpeed mps="9.01"
					name="Fresh Breeze"/>
			<temperature day="6.06"
					min="5.57"
					max="6.06"
					night="5.66"
					eve="5.57"
					morn="6.06"/>
			<pressure unit="hPa"
					value="1027.72"/>
			<humidity value="96"
					unit="%"/>
			<clouds value="clear sky"
					all="8"
					unit="%"/>
		</time>
		<time day="2016-02-24">
			<symbol number="501"
					name="matige regen"
					var="10d"/>
			<precipitation value="3.15"
					type="rain"/>
			<windDirection deg="283"
					code="WNW"
					name="West-northwest"/>
			<windSpeed mps="6.21"
					name="Moderate breeze"/>
			<temperature day="4.98"
					min="4.17"
					max="5.11"
					night="4.17"
					eve="4.85"
					morn="4.32"/>
			<pressure unit="hPa"
					value="1030.97"/>
			<humidity value="100"
					unit="%"/>
			<clouds value="scattered clouds"
					all="48"
					unit="%"/>
		</time>
		<time day="2016-02-25">
			<symbol number="500"
					name="lichte regen"
					var="10d"/>
			<precipitation value="1.23"
					type="rain"/>
			<windDirection deg="295"
					code="WNW"
					name="West-northwest"/>
			<windSpeed mps="5.71"
					name="Moderate breeze"/>
			<temperature day="5.43"
					min="4.92"
					max="5.48"
					night="5.34"
					eve="5.48"
					morn="4.92"/>
			<pressure unit="hPa"
					value="1026.18"/>
			<humidity value="100"
					unit="%"/>
			<clouds value="broken clouds"
					all="68"
					unit="%"/>
		</time>
	</forecast>
</weatherdata>

This is my C++ code which reads the XML-file:

#include <iostream>
#include <string>
#include "tinyxml2.h"

using namespace std;

struct weatherData
{
    // date of day
    string time_day;
    // symbol data for weathericon and display of weather type
    string symbol_number;
    string symbol_name;
    string symbol_var;
    // windspeed
    string windSpeed_mps;
    // min. and max. temperature
    string temp_min;
    string temp_max;
};


int main()
{
    weatherData forecast[3];

    int counter = 0;

    tinyxml2::XMLDocument doc;
    if(doc.LoadFile("daily.xml") == tinyxml2::XML_SUCCESS)
    {
        tinyxml2::XMLElement* root = doc.FirstChildElement();

        for(tinyxml2::XMLElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement())
        {
            std::string elemName = elem->Value();

            for (tinyxml2::XMLElement* e = elem->FirstChildElement("time"); e != NULL; e = e->NextSiblingElement("time"))
            {

                if (e)
                {
                    const char *time = e->Attribute("day");

                    forecast[counter].time_day = time;
                    counter++;
                }


            }
            cout << "Time dates: " << endl;
            for (int i = 0; i < 3;i++)
            {
            cout << forecast[i].time_day << endl;
            }
            counter = 0;
        }
    }
}

I am a novice in coding. I'm using the example code from a blog and adapted it for my needs. I know the for-loops just run across the elements in the XML-file. And every time it finds the element 'time' it looks if it has an attribute 'day'. What I don't get is why it runs 4 times and the fifth time it produces the attributes of the three 'time' parts.

This is the output:

Time dates:

Time dates:

Time dates:

Time dates:

Time dates:

2016-02-23 2016-02-24 2016-02-25


Solution

  • It is because your outer loop iterates over all direct successors of root element weatherdata, i.e. it iterates over the element nodes location, credit, meta, sun, and forecast. For each of these elements, you search for the time-elements, in which you are actually interested. But the first 4 elements, i.e. location, credit, meta and sun, do not comprise any time-element, such that the first 4 iterations of the outer loop cannot extract any time data, whereas the 5th iteration then selects element node forecast, which has the three time-elements that you are looking for.

    I suppose that it works if you change your code as follows (note the "forecast"-parameter in the call to FirstChildElement):

    ....
    if(doc.LoadFile("daily.xml") == tinyxml2::XML_SUCCESS)
    {
        tinyxml2::XMLElement* root = doc.FirstChildElement();
    
        for(tinyxml2::XMLElement* elem = root->FirstChildElement("forecast"); elem != NULL; elem = elem->NextSiblingElement())
        {
        ....