I know there's probably some extremely obvious thing I'm missing here, but this has been driving me crazy for a few days now.

Here is a simple function I've written that is just supposed to find the first tag in the XML document for now:

void parse_weather_file(const char* weatherFileName, WeatherDataAsPWMValues *wd)
{
    if (wd == NULL) return;

    std::cout << weatherFileName << std::endl;

    tinyxml2::XMLDocument doc(weatherFileName);
    tinyxml2::XMLNode *root = doc.FirstChild();
    if (root == NULL) std::cout << "Error" << std::endl;
}

Here is the XML document I'm trying to parse:

<!-- Sample output of openWeatherMap API -->
<?xml version="1.0" encoding="utf-8"?>
<current>
    <city id="2643741" name="City of London">
        <coord lon="-0.09" lat="51.51">
        <country>GB</country>
    <sun rise="2015-06-30T03:46:57" set="2015-06-30T20:21:12">
    </city>
    <temperature value="72.34" min="66.2" max="79.88" unit="fahrenheit"/>
    <humidity value="43" unit="%">
    <pressure value="1020" unit="hPa">
    <wind>
        <speed value="7.78" name="Moderate breeze">
        <direction value="140" code="SE" name="SouthEast">
    </wind>
    <clouds value="0" name="clear sky">
    <visibility value="10000">
    <precipitation mode="no">
    <weather number="800" value="Sky is Clear" icon="01d">
    <lastupdate value="2015-06-30T08:36:14">
</current>

And here is the output I get from the function:

test.xml
Error

This would suggest that root is NULL at the end of the function, but I'm not sure why that would be the case.

2

There are 2 best solutions below

0
On

I made your XML well-formed by adding closing / on single elements.
This is how it looks:

<?xml version="1.0" encoding="utf-8"?>
<current>
    <city id="2643741" name="City of London">
        <coord lon="-0.09" lat="51.51" />
        <country>GB</country>
        <sun rise="2015-06-30T03:46:57" set="2015-06-30T20:21:12" />
    </city>
    <temperature value="72.34" min="66.2" max="79.88" unit="fahrenheit" />
    <humidity value="43" unit="%" />
    <pressure value="1020" unit="hPa" />
    <wind>
        <speed value="7.78" name="Moderate breeze" />
        <direction value="140" code="SE" name="SouthEast" />
    </wind>
    <clouds value="0" name="clear sky" />
    <visibility value="10000" />
    <precipitation mode="no" />
    <weather number="800" value="Sky is Clear" icon="01d" />
    <lastupdate value="2015-06-30T08:36:14" />
</current>

Hope this helps you identifying errors...

0
On

As @zx485 explained, your XML is malformed. But, even after fixing that, your code will still fail. Per the TinyXML-2 documentation, the tinyxml2::XMLDocument class DOES NOT have a constructor that accepts a filename as input. It does, however, have a constructor that accepts a bool as input:

XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );

A const char* is implicitly convertible to a bool, which is why your code compiles, but you are not actually loading the file at all, which is why root is NULL.

You need to call the class's LoadFile() method instead:

XMLError LoadFile( const char* filename );

For example:

void parse_weather_file(const char* weatherFileName, WeatherDataAsPWMValues *wd)
{
    if (wd == NULL) return;

    std::cout << weatherFileName << std::endl;

    tinyxml2::XMLDocument doc;

    XMLError err = doc.LoadFile(weatherFileName);
    if (err != XML_SUCCESS) {
        std::cout << "Error loading file: " << (int)err << std::endl;

        /* or:

        std::cout << "Error loading file: " << doc.ErrorName() << std::endl;

        std::cout << "Error loading file: " << tinyxml2::XMLDocument::ErrorIDToName(err) << std::endl;

        std::cout << "Error loading file: " << doc.ErrorStr() << std::endl;

        std::cout << "Error loading file" <<< endl;
        doc.PrintError();

        */

        return;
    }

    tinyxml2::XMLNode *root = doc.FirstChild();
    if (root == NULL) {
        std::cout << "Error root is null" << std::endl;
        return;
    }

    // use root as needed...
}

Also, you should be using the RootElement() method instead of the FirstChild() method:

tinyxml2::XMLElement *root = doc.RootElement();