TinyXML2 入门教程-程序员宅基地

技术标签: TinyXML2  开源源码分析与使用  

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

1.概述

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>[email protected]</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","[email protected]");
	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>[email protected]</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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/K346K346/article/details/48750417

智能推荐

【数据结构】查找1——线性表的查找(顺序查找、折半查找、分块查找)_图顺序查找-程序员宅基地

文章浏览阅读2.8k次。【数据结构】查找1——线性表的查找(顺序查找、折半查找、分块查找)_图顺序查找

zip包解压时报malformed input off : 0, length : 1-程序员宅基地

文章浏览阅读843次。使用ZipArchiveInputStream而非ZipInputStream的原因主要有以下两点:支持更多的压缩格式:ZipArchiveInputStream是Apache Commons Compress库中提供的类,能够支持多种压缩格式,包括Zip、Gzip、Tar、Jar等。而ZipInputStream是Java标准库中的类,只能读取普通的Zip文件。因此,如果需要处理多种压缩格式的文件,使用ZipArchiveInputStream会更加方便。更多的选项和功能:ZipArchiveInp_malformed input off : 0, length : 1

switch case结合枚举值使用,借助枚举的值来做case分支判断_switch case 枚举-程序员宅基地

文章浏览阅读8.3k次,点赞9次,收藏22次。https://blog.csdn.net/m0_37754981/article/details/80022169参考资料_switch case 枚举

rpc简介及原理-程序员宅基地

文章浏览阅读5.1k次,点赞2次,收藏30次。1.RPC简介及原理介绍RPC技术内部原理是通过两种技术的组合来实现的:本地方法调用 和 网络通信技术。1.1 RPC简介在上述本地过程调用的例子中,我们是在一台计算机上执行了计算机上的程序,完成调用。随着计算机技术的发展和需求场景的变化,有时就需要从一台计算机上执行另外一台计算机上的程序的需求,因此后来又发展出来了RPC技术。特别是目前随着互联网技术的快速迭代和发展,用户和需求几乎都是以指数式的方式在高速增长,这个时候绝大多数情况下程序都是部署在多台机器上,就需要在调用其他物理机器上的程序的情况。_rpc

AI大视觉(十七) | PANet(路径聚合网络)-程序员宅基地

文章浏览阅读7k次,点赞6次,收藏70次。本文来自公众号“AI大道理​目标检测或者实例分割不仅要关心语义信息,还要关注图像的精确到像素点的浅层信息。所以需要对骨干网络中的网络层进行融合,使其同时具有深层的语义信息和浅层的纹理信息。PANet整体结构PANet(Path Aggregation Network)最大的贡献是提出了一个自顶向下和自底向上的双向融合骨干网络,同时在最底层和最高层之间添加了一条“short-cut”,用于缩短层之间的路径。PANet还提出了自适应特征池化和全连接融合两个模块。其中自适应特征_panet

OperationalError: (sqlite3.OperationalError) unable to open database file解决方案_sqlite3.operationalerror: unable to open database -程序员宅基地

文章浏览阅读1.3w次,点赞13次,收藏14次。本文主要介绍了OperationalError: (sqlite3.OperationalError) unable to open database file解决方案,希望能对使用langchain读取sqlite文件的同学们有所帮助。文章目录1. 问题描述2. 解决方案_sqlite3.operationalerror: unable to open database file

随便推点

PID控制详解-程序员宅基地

文章浏览阅读10w+次,点赞551次,收藏3.2k次。PID控制详解一、PID控制简介 PID( Proportional Integral Derivative)控制是最早发展起来的控制策略之一,由于其算法简单、鲁棒性好和可靠性高,被广泛应用于工业过程控制,尤其适用于可建立精确数学模型的确定性控制系统。 在工程实际中,应用最为广泛的调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节,它实际上是一种算法。PID控制器问..._pid控制

搭建静态网站-程序员宅基地

文章浏览阅读329次。搭建Http静态服务器环境任务时间:15min ~ 30min搭建静态网站,首先需要部署环境。下面的步骤,将告诉大家如何在服务器上通过 Nginx 部署 HTTP 静态服务。00、安装 Nginx在 CentOS 上,可直接使用yum来安装 Nginxyum install nginx -y安装完成后,使用nginx命令启动 Nginx:n..._在一个目录下创建静态站点

HTML5网页设计 (一)_html5网页制作-程序员宅基地

文章浏览阅读7k次,点赞2次,收藏23次。初始HTML5记事本简单实现HTML5页面_html5网页制作

CentOS 固定IP配置_centos配置ip地址-程序员宅基地

文章浏览阅读6.8k次。1、打开 VMware Workstation,点击 “编辑” -> "虚拟网络编辑器"2、选择 “更改设置”(若界面内没有,则不用理会)3、选择 “VMnet8”,更改为192.168.88.0(按需填写)、为255.255.255.0,点击 “NAT设置”4、更改为192.168.88.2(按需填写),当前界面点击确定,“虚拟网络编辑器”界面再点击确定。_centos配置ip地址

MATLAB 调用 p文件,Matlab中使用.p文件的方法-程序员宅基地

文章浏览阅读2.9k次。首先,P文件为了保护知识产权设计的一种加密文件,是不能查看的。运行比较简单,和调用m文件方法一样。下面是一些解释。P文件是对应M文件的一种预解析版本(preparsedversion)。因为当你第一次执行M文件时,Matlab需要将其解析(parse)一次(第一次执行后的已解析内容会放入内存作第二次执行时使用,即第二次执行时无需再解析),这无形中增加了执行时间。所以我们就预先作解释,那么以后再使用..._matlab怎么调用p文件

[CSS] 内联元素内的文字居中显示(按钮、链接等)_a-button居中-程序员宅基地

文章浏览阅读2.1k次。最近在做一个移动端的响应式页面,对自定义样式要求较高,很多地方需要细微的调整,比如按钮、链接等内联元素,不能只是让它看起来居中,而要做到“响应式”居中……水平居中很简单,但是垂直居中的问题困扰了我很久,直到我研究过bootstrap的_variables.scss文档后,才仔细地了解到一些组件的构造。如果修改了inline/inline-block元素的默认样式后,里面的文字不居中了,试试这个方法,只需要5步~_a-button居中

推荐文章

热门文章

相关标签