c++parsingtinyxml2

Removing selected child elements in a XML file C++


I'm using tinyxml2. I have xml file with many elements on one node. My xml file:

<city>
    <school>
        <class>
            <boy name="Jose">
                <age>14</age>
            </boy>
            <boy name="Jim">
                <age>15</age>
            </boy>
            <boy name="Mike">
                <age>13</age>
            </boy>
            <boy name="Ben">
                <age>14</age>
            </boy>
            <boy name="Eddy">
                <age>14</age>
            </boy>
            <boy name="Jim">
                <age>16</age>
            </boy>
        </class>
    </school>
</city>

For example, I have to remove the last three boys. I wrote this, but it don't work.

void cropData(char *titlecity)
{
    tinyxml2::XMLNode *city = nullptr;
    tinyxml2::XMLNode *school = nullptr;
    tinyxml2::XMLNode *class = nullptr;
    tinyxml2::XMLError result;

    tinyxml2::XMLDocument doccity;
    doccity.LoadFile(titlecity);
    tinyxml2::XMLNode* root = doccity.FirstChild();
    if(root == nullptr)
        std::cout << "Cannot open file" << std::endl;

    city = doccity.FirstChildElement("city");
    assert(city);
    school = city->FirstChildElement("school");
    assert(school);
    class = school->FirstChildElement("class");
    assert(class);

    int i = 0;

    for (tinyxml2::XMLElement *boy = class->FirstChildElement("boy"); boy; boy = boy->NextSiblingElement("boy"))
    {
        if(i>3)
        {
            boy->Parent()->DeleteChild(boy);
        }
        i++;
    }

    doccity.SaveFile("DeleteAttribute_demo_file.txt");
}

This code does not change file. I'm really sorry, if my english is bad.


Solution

  • You have two errors in that code. One is a syntax error and the other is a logical error.

    The syntax error is that you can't name a variable "class" because "class" is a reserved word in C++.

    The logical error is that your for loop is iterating over elements by incrementing using the element's NextSiblingElement getter function; however, once you delete an element its next element will no longer be valid.

    See below:

    void cropData(tinyxml2::XMLDocument& doccity)
    {
        auto* city = doccity.FirstChildElement("city");
        auto* school = city->FirstChildElement("school");
        auto* class_ = school->FirstChildElement("class");
        int i = 0;
        auto* boy = class_->FirstChildElement("boy");
        while (boy != nullptr) {
            auto next = boy->NextSiblingElement("boy");
            if (i > 3) {
                boy->Parent()->DeleteChild(boy);
            }
            boy = next;
            ++i;
        }
    
        doccity.SaveFile("DeleteAttribute_demo_file.txt");
    }
    
    int main() {
    
        static const char* xml =
            "<?xml version=\"1.0\"?>"
            "<city>"
            "    <school>"
            "        <class>"
            "            <boy name=\"Jose\">"
            "                <age>14</age>"
            "            </boy>"
            "            <boy name=\"Jim\">"
            "                <age>15</age>"
            "            </boy>"
            "            <boy name=\"Mike\">"
            "                <age>13</age>"
            "            </boy>"
            "            <boy name=\"Ben\">"
            "                <age>14</age>"
            "            </boy>"
            "            <boy name=\"Eddy\">"
            "                <age>14</age>"
            "            </boy>"
            "            <boy name=\"Jim\">"
            "                <age>16</age>"
            "            </boy>"
            "        </class>"
            "    </school>"
            "</city>";
    
        tinyxml2::XMLDocument doc;
        doc.Parse(xml);
        cropData(doc);
    }