TinyXML2 入门教程

TinyXML2 入门教程TinyXML2是simple、small、efficient开源的C++XML文件解析库,可以很方便的应用到现有的项目之中。非常适合存储简单数据,配置文件,对象序列化等数据量不是很大的操作。TinyXML2详细介绍与源码获取方法详见:TinyXML2官网。

大家好,又见面了,我是你们的朋友全栈君。

代码编译运行环境:Linux 64bits + Debug + g++ -m64(-m 表示生成 64bits 的程序)


1.TinyXML2 概述

TinyXML2 是 simple、small、efficient 的开源 C++ XML 文件解析库,可以很方便地应用到现有的项目中。

TinyXML2 详细介绍与源码获取详见:TinyXML2 官网

2. TinyXML1 与 TinyXML2 对比

TinyXML1 与 TinyXML2 这两个著名的开源 XML 文件解析库均出自 Lee Thomason 之手,让我们向这位满怀开源精神的大家致敬。

TinyXML1 开发已经停止,所有的开发都转移到了 TinyXML2。TinyXML2 适用于大部分 C/C++ 的项目,经得住考验,是最好的选择。较 TinyXML1 而言,TinyXML2 化繁为简,使用时只需要包含两个文件,而 TinyXML1 需要包含 6 个文件,一般生成静态链接库供项目使用。TinyXML1 详细介绍与源码见:TinyXML1官网。TinyXML1 用法用例可以参考博文:TinyXML快速入门

TinyXML2 使用了与 TinyXML1 相似的 API,并且拥有丰富的测试案例。但 TinyXML2 解析器相对 TinyXML1 在代码上是完全重写,使其更适合于游戏开发。它使用更少的内存,效率更高。

TinyXML2 无需 STL,也放弃了对 STL 支持。所有字符串查询均使用 C 风格字符串const char*来表示,省去 string 类型对象的构造,使代码更加简洁。

二者共同点:
(1)都使用了简单易用的 API。
(2)都是基于 DOM(Document Object Model,文档对象模型)的解析器。
(3)都支持 UTF-8 编码。

TinyXML2 的优点:
(1)对大部分大部分的 C/C++ 项目具有普适性;
(2)使用较少的内存(约 TinyXML1 的 40%),速度变得更快;
(3)没有 C++ 的 STL 的要求;
(4)更接近现代 C++ 的特性,如使用了适当的命名空间;
(5)适当有效的处理了的空白字符(空格,Tab 和回车)。

TinyXML1 的优点:
(1)可以报告分析错误的位置;
(2)提供一些 C++ STL 公约支持:流和字符串;
(3)拥有非常成熟和良好的调试代码库。

3. TinyXML2 用法用例

TinyXML2 的网上教程并不多见,醍醐灌顶、受益匪浅的教程更是凤毛麟角。有的也是蜻蜓点水、参差不齐的泛泛而谈。最终,所能参考的资料也就是官网文档和示例代码,但却有点晦涩难懂。因此,本文就为了解决这个尴尬的局面,结合官网资料和网上资源,尽量详细地列出 TinyXML2 的常见用法用例,不足之处,请留言补充,后续增加修改。

XML 文件本质就是小型的数据库,换个角度来说就是,对数据库有什么操作,那么对 XML 文件就应能实现什么操作。一般而言,对数据库的操作包括以下几种:新建数据库和对数据库增删查改。那么对应 XML 文件就是新建 XML 文件、增加 XML 文件的节点,删除XML文件的指定节点,查询 XML 文件指定节点的值,修改 XML 文件节点的值。

使用方法:将 tinyxml2.cpp 和 tinyxml2.h 拷贝至项目目录,使用时包含头文件和引入名字空间。

#include "tinyxml2.h"
using namespace tinyxml2

使用场景:存储用户信息。

用户数据表设计如下:

变量名 描述 类型 长度(字节) 不为空 主键
UserName 用户名 Vchar 3-20 Y Y
Password 密码 Char 32 Y N
Gender 性别 Int 1 N N
Mobile 电话 Char 11 N N
Email 电子邮箱 Varchar 1-50 N N

对应 XML 文件实现如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<DBUSER>
	<User Name=”lvlv” Password =”123456”>
		<Gender></Gender>
		<Mobile ></ Mobile>
		<Email ></ Email >
	</User>
	<!-- This is a comment --> 
<DBUSER>

从中可以看出,XML 由三大部分组成,分别是声明、根节点和其它节点。其中 XML 文件的声明包括三方面的内容:Version、Standalone 和 Encoding。下面将详细列出常见 TinyXML2 的用法。

注意:以下示例代码针对本人下载使用的 TinyXML2,官网的 TinyXML2 在不断地完善和更新当中,最新的 TinyXML2 和本文的示例代码可能会有出入。本人使用的 TinyXML2 是 2015.9.23 从官网下载的,已上传至 CSDN,下载见:TinyXML2

3.1 创建 XML 文件

示例代码:

//function:create a xml file
//param:xmlPath:xml文件路径
//return:0,成功;非0,失败
int createXML(const char* xmlPath)
{ 
   
	const char* declaration ="<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>";
	XMLDocument doc;
	doc.Parse(declaration);//会覆盖xml所有内容
	
	//添加申明可以使用如下两行
	//XMLDeclaration* declaration=doc.NewDeclaration();
	//doc.InsertFirstChild(declaration);

	XMLElement* root=doc.NewElement("DBUSER");
	doc.InsertEndChild(root);

	return doc.SaveFile(xmlPath);
}

创建结果:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<DBUSER/>

3.2 增加 XML 文件的节点

示例代码:

//用户类
class User
{ 
   
public:
	User()
	{ 
   
		gender=0;
	};
	
	User(const string& userName, const string& password, int gender, const string& mobile, const string& email){ 
   
		this->userName=userName;
		this->password=password;
		this->gender=gender;
		this->mobile=mobile;
		this->email=email;
	};
	
	string userName;
	string password;
	int gender;
	string mobile;
	string email;
};

//function:insert XML node
//param:xmlPath xml 文件路径; user 用户对象
//return:0 成功; 非 0 失败
int insertXMLNode(const char* xmlPath,const User& user) { 
   
	XMLDocument doc;
	int res=doc.LoadFile(xmlPath);
	if(res!=0)
	{ 
   
		cout<<"load xml file failed"<<endl;
		return res;
	}
	XMLElement* root=doc.RootElement();
	
	XMLElement* userNode = doc.NewElement("User");
	userNode->SetAttribute("Name", user.userName.c_str());
	userNode->SetAttribute("Password", user.password.c_str());
	root->InsertEndChild(userNode);
	
	XMLElement* gender = doc.NewElement("Gender");
	XMLText* genderText=doc.NewText(itoa(user.gender));
	gender->InsertEndChild(genderText);
	userNode->InsertEndChild(gender);
					
	XMLElement* mobile = doc.NewElement("Mobile");
	mobile->InsertEndChild(doc.NewText(user.mobile.c_str()));
	userNode->InsertEndChild(mobile);
	
	XMLElement* email = doc.NewElement("Email");
	email->InsertEndChild(doc.NewText(user.email.c_str()));
	userNode->InsertEndChild(email);
	
	return doc.SaveFile(xmlPath);
}

创建结果:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<DBUSER>
    <User Name="lvlv" Password ="123456">
        <Gender>1</Gender>
        <Mobile>15813354926</Mobile>
        <Email>1589276509@qq.com</Email>
    </User>
</DBUSER>

3.3 查询 XML 文件的指定节点

Xml文件中,一个用户节点存储一个用户的信息。因此,对用户信息的增删查改,即无论查询节点、删除节点、修改节点和增加节点,都需要获取需要操作的节点。那么先实现一个根据用户名获取节点指针的函数:

//function:根据用户名获取用户节点
//param:root:xml文件根节点;userName:用户名
//return:用户节点
XMLElement* queryUserNodeByName(XMLElement* root,const string& userName) { 
   
	XMLElement* userNode=root->FirstChildElement("User");
	while(userNode!=NULL) { 
   
		if(userNode->Attribute("Name")==userName)
			break;
		userNode=userNode->NextSiblingElement();//下一个兄弟节点
	}
	return userNode;
}

在以上函数的基础上,获取用户信息的函数:

User* queryUserByName(const char* xmlPath,const string& userName) { 
   
	XMLDocument doc;
	if(doc.LoadFile(xmlPath)!=0) { 
   
		cout<<"load xml file failed"<<endl;
		return NULL;
	}
	XMLElement* root=doc.RootElement();
	XMLElement* userNode=queryUserNodeByName(root,userName);
	
	if(userNode!=NULL) { 
     //searched successfully 
		User* user=new User();
		user->userName=userName;
		user->password=userNode->Attribute("Password");
		XMLElement* genderNode=userNode->FirstChildElement("Gender");
		user->gender=atoi(genderNode->GetText());
		XMLElement* mobileNode=userNode->FirstChildElement("Mobile");
		user->mobile=mobileNode->GetText();		
		XMLElement* emailNode=userNode->FirstChildElement("Email");
		user->email=emailNode->GetText();			
		return user;
	}
	return NULL;
}

3.4 修改 XML 文件的指定节点

//function:修改指定节点内容
//param:xmlPath:xml文件路径;user:用户对象
//return:bool
bool updateUser(const char* xmlPath,User* user) { 
   
	XMLDocument doc;
	if(doc.LoadFile(xmlPath)!=0) { 
   
		cout<<"load xml file failed"<<endl;
		return false;
	}
	XMLElement* root=doc.RootElement();
	XMLElement* userNode=queryUserNodeByName(root,user->userName);
	
	if(userNode!=NULL) { 
   
		if(user->password!=userNode->Attribute("Password")) { 
   
			userNode->SetAttribute("Password",user->password.c_str());  //修改属性
		}
		XMLElement* genderNode=userNode->FirstChildElement("Gender");
		if(user->gender!=atoi(genderNode->GetText())) { 
   
			genderNode->SetText(itoa(user->gender).c_str());   //修改节点内容
		}
		XMLElement* mobileNode=userNode->FirstChildElement("Mobile");
		if(user->mobile!=mobileNode->GetText()) { 
   
			mobileNode->SetText(user->mobile.c_str());
		}
		XMLElement* emailNode=userNode->FirstChildElement("Email");
		if(user->email!=emailNode->GetText()) { 
   
			emailNode->SetText(user->email.c_str());
		}
		if(doc.SaveFile(xmlPath)==0)
			return true;
	}
	return false;
}

验证代码:

int main(int argc,char* argv[]) { 
   
	//修改用户信息
	User user("lvlv","00001111",0,"13995648666","1586666@qq.com");
	if(updateUser("./user.xml",&user))
		cout<<"update successfully"<<endl;
	else
		cout<<"update failed"<<endl;
	return 0;
}

修改结果:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<DBUSER>
    <User Name="lvlv" Password="00001111">
        <Gender>0</Gender>
        <Mobile>13995648666</Mobile>
        <Email>1586666@qq.com</Email>
</User>
</DBUSER>

3.5 删除 XML 文件的指定节点内容

//function:删除指定节点内容
//param:xmlPath:xml文件路径;userName:用户名称
//return:bool
bool deleteUserByName(const char* xmlPath,const string& userName) { 
   
	XMLDocument doc;
	if(doc.LoadFile(xmlPath)!=0) { 
   
		cout<<"load xml file failed"<<endl;
		return false;
	}
	XMLElement* root=doc.RootElement();
	//doc.DeleteNode(root);//删除xml所有节点
	XMLElement* userNode=queryUserNodeByName(root,userName);
	if(userNode != NULL) { 
   
		userNode->DeleteAttribute("Password");//删除属性
		XMLElement* emailNode=userNode->FirstChildElement("Email");
		userNode->DeleteChild(emailNode); //删除指定节点
		//userNode->DeleteChildren();//删除节点的所有孩子节点
		if(doc.SaveFile(xmlPath)==0)
			return true;
	}
	return false;
}

验证代码:

int main(int argc, char* argv[]) { 
   
	//删除用户某些信息
	if(deleteUserByName("./user.xml","lvlv"))
		cout<<"delete successfully"<<endl;
	else
		cout<<"delete failed"<<endl;
	return 0;
}

删除结果:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<DBUSER>
    <User Name="lvlv">
        <Gender>10</Gender>
        <Mobile>13995648666</Mobile>
</User>
</DBUSER>

4.其它常见用例

4.1 获取 XML 文件申明

//function:获取xml文件申明
//param:xmlPath:xml文件路径;strDecl:xml申明
//return:bool
bool getXMLDeclaration(const char* xmlPath,string& strDecl) { 
   
	XMLDocument doc;
	if(doc.LoadFile(xmlPath)!=0) { 
   
		cout<<"load xml file failed"<<endl;
		return false;
	}
	XMLNode* decl=doc.FirstChild();  
	if (NULL!=decl) { 
     
        XMLDeclaration* declaration =decl->ToDeclaration();  
        if (NULL!=declaration)  
        { 
     
              strDecl = declaration->Value();
			  return true;
        } 
    }
   	return false;
}

验证代码:

int main(int argc,char* argv[]) { 
   
	//获取xml文件申明
	string strDecl;
	if(getXMLDeclaration("./user.xml",strDecl))
	{ 
   
		cout<<"declaration:"<<strDecl<<endl;
	}
	return 0;
}

验证结果:

declaration:xml version="1.0" encoding="UTF-8" standalone="no"

4.2 打印 XML 文件至标准输出

//function:将xml文件内容输出到标准输出
//param:xmlPath:xml文件路径
void print(const char* xmlPath) { 
   
	XMLDocument doc;
	if(doc.LoadFile("./user.xml")!=0) { 
   
		cout<<"load xml file failed"<<endl;
		return;
	}
	doc.Print();
}

4.3 XML 文件内容输出至内存

XMLPrinter printer;
doc.Print( &printer );
// printer.CStr() has a const char* to the XML

其它实例待以后用到再补充。


参考文献

TinyXML2 官网
leethomason github.TinyXML2

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/129971.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月26日 下午4:20
下一篇 2022年4月26日 下午4:20


相关推荐

  • SSH_三大框架简单介绍

    SSH_三大框架简单介绍

    2021年7月10日
    111
  • Java中InvocationHandler接口中第一个参数proxy详解

    Java中InvocationHandler接口中第一个参数proxy详解这两天在学习 Java 动态代理 上一篇文章我们详细的讲解了创建代理类的调用处理程序 实现 InvocationHa 接口的类 获得代理对象的 Proxy 类 但是就发现 InvocationHa 中的 invoke 方法中的第一个参数 proxy 好像从来没有用过 所以就开始在网上查询 proxy 的用途 最后在国外的网站上找到了不错的讲解 stackoverflo com 下面就根据自己的学习心得

    2026年3月18日
    2
  • python产生随机数的方法_产生随机数的代码

    python产生随机数的方法_产生随机数的代码Python产生随机数:一.Python自带的random库1.参生n–m范围内的一个随机数:random.randint(n,m)2.产生0到1之间的浮点数:random.random()3.产生n—m之间的浮点数:random.uniform(1.1,5.4)4.产生从n—m间隔为k的整数:random.randrange(n,m,k)5.从序列中随机选取一个元素:random.choice([1,2,3,4,5,6,7

    2025年7月4日
    5
  • Pycharm的基本使用以及如何配置Python运行环境

    Pycharm的基本使用以及如何配置Python运行环境编译器介绍 Pycharm 一个 code 编译器 主要用于 python 语言开发 功能很强大 有社区版本和专业版本 付费 社区版是提供给编程爱好者进行学术交流的 所以它免费的 功能不如专业版强大 专业版需要付费 但专业版可以激活成功教程 如果不想激活成功教程可以选择 VScode 等其他编译器 具体选择根据个人情况而定 编译器的基本使用首次打开编译器 会看到新手指引 可以根据这个新手指引快速上手 如果不想看可以直接关掉 code 样式设置路径 file Settings Editor General F

    2026年3月27日
    3
  • PHP环境搭建单独安装「建议收藏」

    PHP环境搭建单独安装「建议收藏」Php环境的搭建主要内容:1、知识回顾2、几种常见的PHP环境安装方式3、安装php的运行环境4、php运行环境的介绍1.知识回顾1.1动态网站和静态网站web1.0(静态网站):不支

    2022年7月3日
    28
  • spring boot的基本配置——spring boot的web开发——Thymeleaf模板引擎———通过HttpSession session的session.setAttribute返回数据给…

    spring boot的基本配置——spring boot的web开发——Thymeleaf模板引擎———通过HttpSession session的session.setAttribute返回数据给…packagecom.test.controller;importorg.springframework.stereotype.Controller;importorg.springframework.ui.Model;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springf…

    2022年10月16日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号