1.概述
tinyxml2 github地址
本文涵盖了日常编码中会使用tinyxml2库进行的一些操作,包括:解析xml文件或者xml格式内容的字符串、获取xml节点属性与内容、增加节点或属性、删除节点或属性、将doc对象保存为xml文件或者字符串、从一个文档拷贝节点到另一个文档中等。
本文以类似svg内容存储的数据来进行实例操作,以下为实例操作涉及到的数据。
<?xml version="1.0" encoding="UTF-8"?>
<draw width="200" height="100" version="1" original="true" author="FabianD" createtime="2021-04-08">
<geometry id="1">
<line x1="5" y1="5" x2="5" y2="10"/>
<circle cx="5" cy="5" r="5"/>
</geometry>
<remark>势均力敌,才能生生不息</remark>
</draw>
2.构造数据并创建xml文件
using namespace tinyxml2;
XMLDocument doc;//定义doc对象
//<1.增加xml文档声明
//方式1
const char* declaration="<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
XMLError result = doc.Parse(declaration);
//方式2,生成的内容同上
XMLDeclaration* declarationElement = doc.NewDeclaration();
doc.InsertFirstChild(declarationElement);
//<2.添加节点
XMLElement* drawElement = doc.NewElement("draw");
doc.InsertEndChild(drawElement);
//<3.添加属性并设置属性值
drawElement->SetAttribute("width", 200.0);//double类型
drawElement->SetAttribute("height", 100.0);//double类型
drawElement->SetAttribute("version", 1);//int类型
drawElement->SetAttribute("original", true);//bool类型
std::string author = "FabianD";
drawElement->SetAttribute("author", author.c_str());//const char*类型
drawElement->SetAttribute("createtime", "2021-04-08");//const char*类型
//<4.添加子节点
XMLElement* geometryElement = doc.NewElement("");//暂不设置节点名称
geometryElement->SetName("geometry");//通过SetName函数设置节点名称
geometryElement->SetAttribute("id", 1);
drawElement->InsertEndChild(geometryElement);
//添加直线节点至geometryElement
XMLElement* lineElement = doc.NewElement("line");
lineElement->SetAttribute("x1", 5);
lineElement->SetAttribute("y1", 5);
lineElement->SetAttribute("x2", 5);
lineElement->SetAttribute("y2", 10);
geometryElement->InsertEndChild(lineElement);
//添加圆节点至geometryElement
XMLElement* circleElement = doc.NewElement("circle");
circleElement->SetAttribute("cx", 5);
circleElement->SetAttribute("cy", 5);
circleElement->SetAttribute("r", 5);
geometryElement->InsertEndChild(circleElement);
//添加remarkElement至根节点
XMLElement* remarkElement = doc.NewElement("remark");
remarkElement->SetText("势均力敌,才能生生不息");//设置节点内容
drawElement->InsertEndChild(remarkElement);
//<5.保存至文件中
result = doc.SaveFile("Draw.xml");//会清除原来文件中的内容
3.解析xml文件并读取数据
using namespace tinyxml2;
XMLDocument doc;
XMLError result;
//<1.加载解析文件
result = doc.LoadFile("Draw.xml");
if (result == XML_SUCCESS) {
//<2.获取根节点
XMLElement* drawElement = doc.RootElement();//获取根节点
if (drawElement) {
//<3.获取属性值
//方式1
double width = 0;
result = drawElement->QueryDoubleAttribute("width", &width);
if (result == XML_SUCCESS) {
std::cout << "Width:" << width << std::endl;
}else {
std::cout << "根节点没有width属性" << std::endl;
}
//方式2
const char* heightPtr = drawElement->Attribute("height");
if (heightPtr) {
double height = std::stod(heightPtr);//stod为新特性下的函数
std::cout << "Height:" << height << std::endl;
}else {
std::cout << "根节点没有height属性" << std::endl;
}
//方式3
int version = drawElement->IntAttribute("version", 0);//第二个参数为默认返回值,这种方式在找不到属性时会返回默认值,适合确定有属性存在的情况
std::cout << "Version:" << version << std::endl;
//获取其他类型属性值
bool original = false;
result = drawElement->QueryBoolAttribute("original", &original);
if (result == XML_SUCCESS) {
std::cout << "Original:" << original << std::endl;
}
const char* authorPtr = drawElement->Attribute("author");
if (authorPtr) {
std::cout << "Author:" << authorPtr << std::endl;
}
//<4.获取子节点
XMLElement* geometryElement = drawElement->FirstChildElement("geometry");//传入节点名称
if (geometryElement) {
XMLElement* childElement = geometryElement->FirstChildElement();//不传入节点名称,返回第一个子节点
//遍历获取子节点
while (childElement) {
if (!std::strcmp(childElement->Name(), "line")) {
//获取直线节点相关属性
double x1 = childElement->DoubleAttribute("x1");
double y1 = childElement->DoubleAttribute("y1");
std::cout << "LineX1:" << x1 << std::endl;
//...
}else if (!std::strcmp(childElement->Name(), "circle")) {
//获取圆节点相关属性
double cx = childElement->DoubleAttribute("cx");
double cy = childElement->DoubleAttribute("cy");
std::cout << "CircleCx:" << cx << std::endl;
//...
}
childElement = childElement->NextSiblingElement();//获取同一级的下一节点
}
}
//获取remark子节点
XMLElement* remarkElement = drawElement->FirstChildElement("remark");
if (remarkElement) {
const char* remark = remarkElement->GetText();//获取节点内容
std::cout << "Remark:" << remark << std::endl;
}
//<5.修改节点
//修改节点属性值及内容
if (remarkElement) {
remarkElement->SetText("至死不渝");
remarkElement->SetAttribute("type", "love");
}
//删除属性及节点
drawElement->DeleteAttribute("version");//删除version属性
geometryElement->DeleteChild(geometryElement->FirstChildElement("line"));//删除line节点
//geometryElement->DeleteChildren();//删除所有子节点
doc.SaveFile("Draw.xml");//重新保存
}else {
std::cout << "文件没有根节点" << std::endl;
}
}else {
std::cout << "解析失败:" << result << std::endl;
}
4.其他一些操作
using namespace tinyxml2;
XMLDocument doc;
XMLError result = doc.LoadFile("Draw.xml");
if (result == XML_SUCCESS) {
//<1.读取xml文件内容至const char*中
XMLPrinter printer;
doc.Print(&printer);
const char* contentPtr = printer.CStr();
std::cout << "xml content:" << contentPtr << std::endl;
//<2.解析字符串内容
XMLDocument docx;
result = docx.Parse(contentPtr);
if(result==XML_SUCCESS){
if (docx.RootElement()) {
std::cout << docx.RootElement()->Name();
}
}
//<3.复制doc中的节点到另一个doc中
XMLDocument docTarget;
result = docTarget.LoadFile("Draw.xml");
if (result == XML_SUCCESS) {
XMLElement* drawElementSource = doc.RootElement();
XMLElement* drawElementTarget = docTarget.RootElement();
if (drawElementTarget) {
XMLElement* geometryElementTarget = drawElementTarget->FirstChildElement("geometry");
if (geometryElementTarget) {
XMLNode* geometryElementSource = geometryElementTarget->DeepClone(&doc);//复制节点到新doc中
drawElementSource->InsertFirstChild(geometryElementSource);//执行插入操作
result = doc.SaveFile("Draw.xml");
}
}
}
}
5.总结
tinyxml2经常用到的几个对象:
1.tinyxml2::XMLNode:XMLDocment、XMLElement的基类
- XMLNode* InsertFirstChild(XMLNode* node): 在对象(文档/节点)最前面插入节点node。
- XMLNode* InsertEndChild(XMLNode* node): 在对象(文档/节点)最后面插入节点node。
- XMLNode* InsertAfterChild(XMLNode* afterNode,XMLNode* node): 在节点afterNode后面插入节点node。
- void DeleteChild(XMLNode*): 删除子节点node。
- void DeleteChildren(): 删除所有子节点。
- static void DeleteChild(XMLNode*): 删除节点node。
- XMLNode* DeepClone(XMLDocument* target): 拷贝一份数据到target文档中,返回有同样数据的XMLNode*。
- XMLElement* FirstChildElement(const char* name==NULL): 获取对象(文档/节点)下节点名称为name的第一个子节点。
- XMLElement* LastChildElement(const char* name==NULL): 获取对象(文档/节点)下节点名称为name的最后一个子节点。
- XMLNode* Parent(): 获取(文档/节点)的父节点。
- XMLElement* NextSiblingElement(const char* name==NULL): 获取对象(文档/节点)同级中往后名称为name的节点。
- XMLElement* PreviousSiblingElement(const char* name==NULL): 获取对象(文档/节点)同级中往前名称为name的节点。
2.tinyxml2::XMLDocument:
- XMLError LoadFile(const char*): 用来加载解析xml文件。
- XMLError SaveFile(const char*): 用来保存数据至xml文件。
- XMLError Parse(const char*): 用来解析字符串内容。
- XMLDeclaration* NewDeclaration(): 用来创建doc的文档声明,创建后,还需要将其插入XMLDocument对象中才有作用。
- XMLElement* NewElement(): 用来创建doc的节点,创建后,还需要将其插入XMLDocument对象中才有作用。
3.tinyxml2::XMLElement:
- void SetAttribute(const char*, T value): 设置属性,T可以是任意基础类型。
- void SetName( const char* str, bool staticMem=false ): 设置节点名称。
- XMLError QueryIntAttribute( const char* name, int* value ): 获取名称为name,type为int的属性的值,如果该值不是int类型,返回值将不是XML_SUCCESS。同类型的函数还有:QueryDoubleAttribute、QueryBoolAttribute等。
- const char* XMLElement::Attribute( const char* name, const char* value ): 获取名称为name的属性值,如果没有该属性,则返回默认值value。
- int IntAttribute(const char* name, int defaultValue): 获取名称为name的属性值,如果没有该属性,则返回默认值defaultValue。