C++ TinyXML解析案例详解
本文详细介绍如何使用C++开源库TinyXML解析和操作XML文件。通过提供从配置目录到具体增删改查操作的完整代码示例,帮助开发者快速上手并解决实际的配置文件解析需求。
TinyXML核心机制与类结构
TinyXML是一个基于DOM(文档对象模型)的轻量级XML解析库,适用于Windows和Linux平台。它通过将整个XML文档转化为内存中的树状结构,使开发者能够方便地遍历和处理数据。在该库的设计中,各种XML组件对应特定的C++类:
TiXmlBase:所有TinyXML类的基类。TiXmlDocument:代表整个XML文档,用于加载文件或作为顶层容器。TiXmlElement:对应XML中的元素(标签),支持获取属性、子节点等操作。TiXmlNode:DOM结构中的节点基类,其他节点如评论(TiXmlComment)、文本(TiXmlText)均继承于此。TiXmlAttribute:对应元素的属性,可通过链式调用获取下一个属性。TiXmlDeclaration:处理声明部分,如<?xml version="1.0" ?>。
项目准备与编译环境
使用前需下载源码并整理目录结构。典型的工程组织方式如下所示,确保头文件、源码及示例代码位置清晰:
tinyxml/ //工作根目录
|-- include //头文件根目录
| |-- tinyxml //tinyxml头文件,包括tinystr.h tinyxml.h
|-- src //cpp源码文件根目录
|-- tinyxml //tinyxml源码文件夹,包括tinystr.cpp tinyxml.cpp tinyxmlerror.cpp tinyxmlparser.cpp
|-- main.cpp //主函数入口,包含调用示例代码
|-- conf //示例XML配置文件目录
|-- makefile //编译脚本
在代码中包含 #include "tinyxml.h" 即可开始使用,注意源码文件中包含的 .cpp 文件需一并编译。
读取与遍历XML文件
读取XML的核心步骤是创建文档对象并加载文件,随后通过链式调用 FirstChildElement() 和 NextSiblingElement() 实现树的遍历。以下示例展示如何读取学生信息并打印属性及子节点内容:
第1步:加载并验证XML文档
目的:建立内存中的DOM模型,确认文件加载成功。
动作:调用 doc.LoadFile() 并检查返回值。若失败则输出错误日志。
完成状态:doc.RootElement() 不再为空,可获取根节点。
第2步:遍历目标节点并提取数据
目的:定位特定层级的元素并读取其属性值与内部文本。
操作逻辑:
- 获取根元素后,逐级向下寻找子节点(如 School → Class → Student)。
- 使用
FirstAttribute()配合循环Next()遍历当前节点的所有属性。 - 对于文本节点或子元素,使用
FirstChildElement()获取第一个兄弟节点,再通过Value()获取标签名,GetText()获取纯文本内容。
void readSchoolXml() {
const char * xmlFile = "conf/school.xml";
TiXmlDocument doc;
if (doc.LoadFile(xmlFile)) {
doc.Print();
} else {
cout << "can not parse xml conf/school.xml" << endl;
return;
}
// 获取根节点 School
TiXmlElement* rootElement = doc.RootElement();
// 获取第一层子节点 Class
TiXmlElement* classElement = rootElement->FirstChildElement();
// 获取第二层子节点 Student
TiXmlElement* studentElement = classElement->FirstChildElement();
// 遍历所有学生节点
for (; studentElement != NULL; studentElement = studentElement->NextSiblingElement() ) {
// 打印属性:name, number等
TiXmlAttribute* attributeOfStudent = studentElement->FirstAttribute();
for (;attributeOfStudent != NULL; attributeOfStudent = attributeOfStudent->Next() ) {
cout << attributeOfStudent->Name() << " : " << attributeOfStudent->Value() << std::endl;
}
// 遍历学生的子节点内容,如 email 和 address
TiXmlElement* studentContactElement = studentElement->FirstChildElement();
for (; studentContactElement != NULL; studentContactElement = studentContactElement->NextSiblingElement() ) {
string contactType = studentContactElement->Value();
string contactValue = studentContactElement->GetText();
cout << contactType << " : " << contactValue << std::endl;
}
}
}
构建与写入新的XML文件
当需要生成新的XML时,需先在堆内存中分配节点对象,并通过 SetAttribute() 设置属性,使用 LinkEndChild() 将子节点挂载到父节点上。最后调用 SaveFile() 持久化保存。
void writeSchoolXml() {
const char * xmlFile = "conf/school-write.xml";
TiXmlDocument doc;
// 添加声明
TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", "");
// 构建层级:School > Class > Student
TiXmlElement * schoolElement = new TiXmlElement( "School" );
TiXmlElement * classElement = new TiXmlElement( "Class" );
classElement->SetAttribute("name", "C++");
// 创建第一个学生节点 stu1
TiXmlElement * stu1Element = new TiXmlElement("Student");
stu1Element->SetAttribute("name", "tinyxml");
stu1Element->SetAttribute("number", "123");
TiXmlElement * stu1EmailElement = new TiXmlElement("email");
stu1EmailElement->LinkEndChild(new TiXmlText("tinyxml@163.com") );
TiXmlElement * stu1AddressElement = new TiXmlElement("address");
stu1AddressElement->LinkEndChild(new TiXmlText("中国"));
stu1Element->LinkEndChild(stu1EmailElement);
stu1Element->LinkEndChild(stu1AddressElement);
// 创建第二个学生节点 stu2
TiXmlElement * stu2Element = new TiXmlElement("Student");
stu2Element->SetAttribute("name", "jsoncpp");
stu2Element->SetAttribute("number", "456");
TiXmlElement * stu2EmailElement = new TiXmlElement("email");
stu2EmailElement->LinkEndChild(new TiXmlText("jsoncpp@163.com"));
TiXmlElement * stu2AddressElement = new TiXmlElement("address");
stu2AddressElement->LinkEndChild(new TiXmlText("美国"));
stu2Element->LinkEndChild(stu2EmailElement);
stu2Element->LinkEndChild(stu2AddressElement);
// 组装树结构
classElement->LinkEndChild(stu1Element);
classElement->LinkEndChild(stu2Element);
schoolElement->LinkEndChild(classElement);
// 加入文档并保存
doc.LinkEndChild(decl);
doc.LinkEndChild(schoolElement);
doc.SaveFile(xmlFile);
}
节点的修改与删除操作
在处理现有XML数据时,常涉及查找特定节点并进行更新或删除。操作前请注意指针的有效性判断。
查找并修改属性值
例如将 <mfid val="1234" /> 中的属性值修改。通过 IterateChildren() 可以逐个查找指定名称的子节点,找到后通过 ToElement() 转换为元素指针,再获取属性进行修改:
TiXmlNode* lpnode = NULL;
// 假设 tixml 为已加载的文档根节点或当前上下文
lpnode = tixml.RootElement()->IterateChildren("mfid",lpnode);
if(lpnode) { // 确保找到了该节点
TiXmlAttribute* tiattr = lpnode->ToElement()->FirstAttribute();
// 修改第一个属性的值为新的字符串
tiattr->SetValue(mfid.c_str());
}
移除节点
从父节点A中移除子节点B,直接调用父节点的 RemoveChild() 方法:
TiXmlNode nodeA;
// 传入要删除的目标节点指针
nodeA.RemoveChild( removeThisNodePointer );
或者移除元素上的指定名称属性:
TiXmlAttribute attrA;
attrA.RemoveAttribute(const char * name);
替换节点
如果需要将一个节点整体替换为另一个不同的节点实例,可使用 ReplaceChild():
parent.ReplaceChild(old_node_ptr, new_node_instance);
以上就是C++使用TinyXML解析、读写、修改XML文件的详细内容,更多关于C++ TinyXML应用技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













