使用tinyxml2在C++中删除XML指定子元素失败求助
问题排查:tinyxml2删除XML元素无效果
问题背景
使用tinyxml2处理XML文件,目标是删除最后3个<boy>元素,但执行代码后文件无任何变化。
XML文件结构
<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>
问题代码
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"); }
问题分析
- 遍历中删除元素导致迭代失效:在for循环里直接删除当前
boy元素后,boy->NextSiblingElement("boy")会因为节点已被销毁而无法正确获取下一个元素,遍历会提前终止,后续需要删除的元素不会被处理。 - 关键字冲突:
class是C++的关键字,不能用作变量名,这会导致编译错误(若代码未实际编译通过,自然不会产生任何修改效果)。 - 边界条件错误:目标是删除最后3个元素(共6个
<boy>),前3个需保留。代码中i>3的条件仅会删除索引为4、5的2个元素,遗漏了索引为3的元素,且逻辑不符合需求。
修正后的代码
#include <tinyxml2.h> #include <cassert> #include <iostream> #include <vector> void cropData(char *titlecity) { tinyxml2::XMLNode *city = nullptr; tinyxml2::XMLNode *school = nullptr; tinyxml2::XMLNode *classNode = nullptr; // 替换关键字class为合法变量名 tinyxml2::XMLDocument doccity; // 增加文件加载错误检查 tinyxml2::XMLError loadResult = doccity.LoadFile(titlecity); if (loadResult != tinyxml2::XML_SUCCESS) { std::cout << "Cannot open file, error code: " << loadResult << std::endl; return; } city = doccity.FirstChildElement("city"); assert(city); school = city->FirstChildElement("school"); assert(school); classNode = school->FirstChildElement("class"); assert(classNode); // 先收集所有需要删除的节点,避免遍历中修改DOM结构导致的迭代问题 std::vector<tinyxml2::XMLElement*> boysToDelete; int i = 0; for (tinyxml2::XMLElement *boy = classNode->FirstChildElement("boy"); boy; boy = boy->NextSiblingElement("boy")) { // 前3个元素保留(i=0,1,2),从第4个开始加入删除列表 if (i >= 3) { boysToDelete.push_back(boy); } i++; } // 统一删除收集到的节点 for (auto boy : boysToDelete) { classNode->DeleteChild(boy); } // 增加文件保存错误检查 tinyxml2::XMLError saveResult = doccity.SaveFile("DeleteAttribute_demo_file.txt"); if (saveResult != tinyxml2::XML_SUCCESS) { std::cout << "Failed to save file, error code: " << saveResult << std::endl; } }
修正说明
- 替换
class变量名为classNode,规避C++关键字冲突。 - 先收集需要删除的节点再统一删除,避免遍历过程中修改DOM结构导致的迭代异常。
- 调整判断条件为
i >= 3,确保删除最后3个<boy>元素。 - 增加文件加载和保存的错误检查,便于排查IO问题。
内容的提问来源于stack exchange,提问作者janullo789
相关产品推荐
相关产品推荐

