c++xmltinyxml

c++ Read contents of xml file


I am still learning c++ and need some help reading the contents of an xml file.

Here's the format of my xml file:

<Rotary>
  <UserInformation>
    <Name>myName</Name>
    <Age>myAge</Age>
  </UserInformation>
</Rotary>

My c++ program needs to read the values of Name and Age so that I can check it on a SQL DB. I'm really struggling with using tinyxml. Someone gave me some code to try to help me, but I'm still not getting it. Here's the code below:

    TiXmlHandle docHandle(&doc);

    string tinyData = "null";

    TiXmlNode* tinySet = docHandle.FirstChild("Rotary").FirstChild("UserInformation").ToNode();

    if (tinySet)
    {
        for (TiXmlNode* tinyChild = tinySet->FirstChild(); tinyChild; tinyChild = tinyChild->NextSibling())
        {
            if (tinyChild)
            {
                if (tinyChild->TINYXML_ELEMENT != tinyChild->Type())
                {
                    continue;
                }
                //TODO: Change this to reflect my xml structure. Past this point I'm not sure what I'm doing.
                tinyData = tinyChild->ToElement()->Attribute("Name");

                if (strcmp(tinyData.c_str(), "Name") == 0)
                {
                    localName = tinyChild->ToElement()->FirstChild()->Value();
                }
                else if (strcmp(tinyData.c_str(), "Age") == 0)
                {
                    localAge = tinyChild->ToElement()->FirstChild()->Value();
                }
            }
        }
    }

Any help would be greatly appreciated!


Solution

  • Uhoh. That API looks hypercomplicated. TinyXML is geared for performance, but nothing else really.

    So. Choosing your library is the most important step: What XML parser should I use in C++?

    Now, in most circumstances where you can use TinyXML you can use PugiXML. PugiXML has a much friendlier interface. Most importantly it's less error-prone (w.r.t resource management, e.g.). It also supports XPath.

    That helps a lot here. Because, in my humble opinion, as soon as you find yourself looping over nodes¹, the case is lost. You'll end up with christmas tree code and it's really hard to get correct or maintain.

    Here's my take using PugiXML:

    #include <pugixml.hpp>
    #include <iostream>
    using namespace pugi;
    
    int main() {
        xml_document doc;
        doc.load_file("input.xml");
        
        auto rotary = doc.root();
        // rotary.print(std::cout); // prints the entire thing
    
        auto name = rotary
            .select_single_node("//UserInformation/Name/text()")
            .node();
        auto age =  rotary
            .select_single_node("//UserInformation/Age/text()")
            .node();
    
        std::cout << "\nName is " << name.value() << "\n";
        std::cout << "Age is " << age.text().as_double() << "\n";
    }
    

    It's still tricky (mostly the part where element text is child text nodes which you can get using different methods). But at least the end result is reasonably maintainable. Oh, it prints:

    <Rotary>
        <UserInformation>
            <Name>myName</Name>
            <Age>42.7</Age>
        </UserInformation>
    </Rotary>
    
    Name is myName
    Age is 42.7
    

    There are no leaks in this code.


    (¹not even mentioning the atrocious interface that TinyXML uses...)