C++ XML 库 TinyXML2 的基本使用_tinyxml2::xmldocument-程序员宅基地

技术标签: TinyXML2  C++ XML  C++ 没有结局的开始  

0.前言

TinyXML-2 是一个简单,小型,高效的 C ++ XML 解析器,可以轻松集成到其他程序中,直接引用源文件的话只需要包含两个文件(h 和 cpp,此外还有个测试文件里面带有 demo)。

TinyXML-2 解析 XML 文档,并以此为基础构建可读取,修改和保存的文档对象模型(DOM)。文档说,在解释 XML 时仅使用 UTF-8 ,假定所有 XML 为 UTF-8 (看了下使用 MSVC 编译器时生成的 XML 文件文本编码使用的本地编码)。该库还支持打印到文件或内存,使用 XMLPrinter 类。

GitHub 链接:https://github.com/leethomason/tinyxml2

(在线文档我的网访问不了,但是下载库 GitHub 上的项目后带有离线文档,用谷歌浏览器在线翻译即可)

1.基本使用

引入头文件:

#include "tinyxml2.h"

//tinyxml2的类在tinyxml2命名空间
using namespace tinyxml2;

使用 XMLDocument 加载和保存 XML 文件:

//构造一个xml文档类
XMLDocument doc;
//读取文件
//从磁盘加载XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
XMLError error = doc.LoadFile(xmlPath);
//也可以解析字符串
//XMLError tinyxml2::XMLDocument::Parse(const char *xml,size_t nBytes = static_cast<size_t>(-1));
if (error != XMLError::XML_SUCCESS)
	return;
//存储到文件,参数2 compact紧凑默认false
doc.SaveFile(xmlPath);

可以借助 XMLDocument 生成节点(元素、属性、文本、注释等),也可以直接 new 生成对象,但还要使用 Insert 方法才能插入到结构中:

//元素
XMLElement * tinyxml2::XMLDocument::NewElement (const char *name)
//注释
XMLComment * tinyxml2::XMLDocument::NewComment (const char *comment)
//文本
XMLText * tinyxml2::XMLDocument::NewText (const char *text) 
//XML文件头描述
XMLDeclaration * tinyxml2::XMLDocument::NewDeclaration (const char *text=0)
//未知类型
XMLUnknown * tinyxml2::XMLDocument::NewUnknown (const char *text)

//插入到末尾
XMLNode * tinyxml2::XMLNode::InsertEndChild (XMLNode *addThis)
//插入到开头
XMLNode * tinyxml2::XMLNode::InsertFirstChild (XMLNode *addThis)
//插入到节点的下一个位置
XMLNode * tinyxml2::XMLNode::InsertAfterChild (XMLNode *afterThis, XMLNode *addThis)

删除子节点:

//删除所有子节点
void tinyxml2::XMLNode::DeleteChildren ()
//删除指定子节点
void tinyxml2::XMLNode::DeleteChild (XMLNode *node)

对于查找,可通过父子兄弟节点进行遍历:

//是否不包含子节点
bool tinyxml2::XMLNode::NoChildren () const
//第一个子节点
const XMLNode * tinyxml2::XMLNode::FirstChild () const
//第一个子元素 
const XMLElement * tinyxml2::XMLNode::FirstChildElement (const char *name=0) const
//最后一个子节点
const XMLNode * tinyxml2::XMLNode::LastChild () const
//最后一个子元素
const XMLElement * tinyxml2::XMLNode::LastChildElement (const char *name=0) const
//上一个兄弟节点 
const XMLNode * tinyxml2::XMLNode::PreviousSibling () const
//上一个兄弟元素 
const XMLElement * tinyxml2::XMLNode::PreviousSiblingElement (const char *name=0) const
//下一个兄弟节点
const XMLNode * tinyxml2::XMLNode::NextSibling () const
//下一个兄弟元素
const XMLElement * tinyxml2::XMLNode::NextSiblingElement (const char *name=0) const

如果要遍历整个文档,可从 XMLDocument 开始遍历,XXXChild + XXXSibling 遍历所有的子节点和兄弟节点。

2.简单的示例

第一生成的 XML 结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<ElementA Level="A" Value="1992">ElementA text<!--ElementA comment--><ElementB Level="B">ElementB text<!--ElementB comment--></ElementB>
</ElementA>

<!--My TinyXml2 Test... ...-->Some Test
<!Unknown>

第二次生成的 XML 结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <GroupA Type="A">
        <Name>中文<Content>111111</Content>
        </Name>
        <Name>English<Content>222222</Content>
        </Name>
        <Name>123<Content>333333</Content>
        </Name>
    </GroupA>
    <GroupB Type="B"/>
    <GroupC Type="C"/>
</Root>

完整代码:

#include <iostream>
#include <string>

#include "tinyxml2.h"

//tinyxml2的类在tinyxml2命名空间
using namespace tinyxml2;

//测试生成xml
void create_xml(const char* xmlPath);
//测试解析xml
void parse_xml(const char* xmlPath);
//遍历xml node
void traversal_node(XMLNode* node);
//遍历xml element
void traversal_element(XMLNode* node, int level);
//生成预定格式xml
void create_xml2(const char* xmlPath);
//解析预定义格式xml
void parse_xml2(const char* xmlPath);

int main()
{
	const char* path = "./test.xml";
	create_xml(path);
	parse_xml(path);

	const char* path2 = "./test2.xml";
	create_xml2(path2);
	parse_xml2(path2);

	system("pause");
	return 0;
}

void create_xml(const char* xmlPath)
{
	std::cout << "\ncreate_xml:" << xmlPath << std::endl;
	//【】构造一个xml文档类
	XMLDocument doc;
	//【】操作文档相关接口
	//创建与此文档关联的新声明。对象的内存由文档管理。
	//如果'text'参数为null,则使用标准声明:
	//<?xml version="1.0" encoding="UTF-8"?>
	XMLDeclaration* declaration = doc.NewDeclaration();
	//创建与此文档关联的新元素。元素的内存由文档管理。
	XMLElement* element = doc.NewElement("ElementA");
	//创建与此文档关联的新注释。注释的内存由文档管理。
	XMLComment* comment = doc.NewComment("My TinyXml2 Test... ...");
	//创建与此文档关联的新文本。文本的存储由文档管理。
	XMLText* text = doc.NewText("Some Test");
	//创建与此文档关联的新的未知节点。对象的内存由文档管理。
	XMLUnknown* unknown = doc.NewUnknown("Unknown");
	//【】创建了节点还要插入文档中
	//添加一个子节点作为最后一个(右)子节点。如果子节点已经是文档的一部分,则将其从其旧位置移至新位置。
	//XMLNode* tinyxml2::XMLNode::InsertEndChild(XMLNode * addThis);
	//添加一个子节点作为第一个(左)子节点。如果子节点已经是文档的一部分,则将其从其旧位置移至新位置。
	//XMLNode* tinyxml2::XMLNode::InsertFirstChild(XMLNode* addThis);
	//在指定的子节点之后添加一个节点。如果子节点已经是文档的一部分,则将其从其旧位置移至新位置。
	//XMLNode* tinyxml2::XMLNode::InsertAfterChild(XMLNode * afterThis, XMLNode * addThis);
	doc.InsertFirstChild(declaration);
	doc.InsertAfterChild(declaration, element);
	doc.InsertEndChild(comment);
	doc.InsertEndChild(text);
	doc.InsertEndChild(unknown);

	//【】操作节点相关接口
	//将命名属性设置为对应类型的value
	element->SetAttribute("Level", "A");
	element->SetAttribute("Value", 1992);
	//设置文本
	element->SetText("ElementA text");
	//注释
	element->InsertNewComment("ElementA comment");
	//添加子节点,接口已经带insert功能了
	XMLElement* sub_element = element->InsertNewChildElement("ElementB");
	sub_element->SetAttribute("Level", "B");
	sub_element->SetText("ElementB text");
	sub_element->InsertNewComment("ElementB comment");


	//【】存储到文件,参数2 compact紧凑默认false
	//结构写的不规范,感觉应该拿一个根节点把那些注释,文本包起来
	//不然解析的时候没法访问啊
	doc.SaveFile(xmlPath);
}

void parse_xml(const char* xmlPath)
{
	std::cout << "\nparse_xml:" << xmlPath << std::endl;
	//【】构造一个xml文档类
	XMLDocument doc;
	//【】读取文件
	//从磁盘加载XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
	XMLError error = doc.LoadFile(xmlPath);
	//也可以解析字符串
	//从字符串解析XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
	//XMLError tinyxml2::XMLDocument::Parse(const char *xml,size_t nBytes = static_cast<size_t>(-1));
	if (error != XMLError::XML_SUCCESS)
		return;
	//注意,实际解析时返回的指针记得判空,不然遇到解析失败异常就遭了

	//【】解析根元素
	//返回DOM的根元素。等效于FirstChildElement。要获取第一个节点,请使用FirstChild。
	XMLElement* root = doc.RootElement();
	std::cout << "RootElement name:" << root->Name() << std::endl;
	//获取第一个子元素,或者选择具有指定名称的第一个子元素。
	XMLElement* first = doc.FirstChildElement("ElementA");
	//给定一个属性名称,Attribute返回该名称的属性的值;如果不存在,则返回null。
	std::cout << "FirstChildElement Attr Level:" << first->Attribute("Level") << std::endl;
	std::cout << "FirstChildElement Attr Value:" << first->Attribute("Value") << std::endl;
	//如果'this'的第一个Child是XMLText,则GetText返回Text节点的字符串,否则返回null。
	std::cout << "FirstChildElement Text:" << first->GetText() << std::endl;

	//【】解析子元素
	XMLElement* sub = root->FirstChildElement("ElementB");
	std::cout << "SubElement Attr Level:" << sub->Attribute("Level") << std::endl;
	std::cout << "SubElement Text:" << sub->GetText() << std::endl;

	//【】
	//可使用FirstChild+NextSibling遍历子节点
	std::cout << "\ntraversal_xml:" << std::endl;
	traversal_node(&doc);
	//或者FirstChildElement+NextSiblingElement遍历子元素
	std::cout << "\ntraversal_element:" << std::endl;
	traversal_element(&doc, 0);
}

void traversal_node(XMLNode* node)
{
	if (!node)
		return;
	for (XMLNode* current = node->FirstChild(); current != nullptr; current = current->NextSibling())
	{
		XMLNode* temp = current;
		if (temp->Value() != nullptr)
			std::cout << temp->Value() << std::endl;
		if (!temp->NoChildren())
			traversal_node(temp);
	}
}

void traversal_element(XMLNode* node, int level)
{
	if (!node)
		return;
	for (XMLElement* current = node->FirstChildElement(); current != nullptr; current = current->NextSiblingElement())
	{
		XMLElement* temp = current;
		//这里我使用点号来表示层级缩进
		std::cout << std::string(level * 5, '.') << temp->Name() << std::endl;
		if (temp->GetText() != nullptr)
			std::cout << std::string(level * 5, '.') << "> Text" << ":" << temp->GetText() << std::endl;
		const XMLAttribute* attr = temp->FirstAttribute();
		if (attr != nullptr)
			std::cout << std::string(level * 5, '.') << "> Attr" << ":" << attr->Value() << std::endl;
		if (temp->FirstChildElement() != nullptr)
			traversal_element(temp, level + 1);
	}
}

void create_xml2(const char* xmlPath)
{
	std::cout << "\ncreate_xml2:" << xmlPath << std::endl;
	//【】构造一个xml文档类
	XMLDocument doc;

	//【】构建我们的xml数据结构
	XMLDeclaration* declaration = doc.NewDeclaration();
	doc.InsertFirstChild(declaration);
	//创建与此文档关联的新元素。元素的内存由文档管理。
	XMLElement* root = doc.NewElement("Root");
	doc.InsertEndChild(root);
	//子节点
	XMLElement* group_a = root->InsertNewChildElement("GroupA");
	group_a->SetAttribute("Type", "A");
	XMLElement* a_1 = group_a->InsertNewChildElement("Name");
	a_1->SetText("中文");
	XMLElement* a_1_sub = a_1->InsertNewChildElement("Content");
	a_1_sub->SetText("111111");
	XMLElement* a_2 = group_a->InsertNewChildElement("Name");
	a_2->SetText("English");
	XMLElement* a_2_sub = a_2->InsertNewChildElement("Content");
	a_2_sub->SetText("222222");
	XMLElement* a_3 = group_a->InsertNewChildElement("Name");
	a_3->SetText("123");
	XMLElement* a_3_sub = a_3->InsertNewChildElement("Content");
	a_3_sub->SetText("333333");
	XMLElement* group_b = root->InsertNewChildElement("GroupB");
	group_b->SetAttribute("Type", "B");
	XMLElement* group_c = root->InsertNewChildElement("GroupC");
	group_c->SetAttribute("Type", "C");


	//【】存储到文件,参数2 compact紧凑默认false
	doc.SaveFile(xmlPath);
}

void parse_xml2(const char* xmlPath)
{
	std::cout << "\nparse_xml2:" << xmlPath << std::endl;
	//【】构造一个xml文档类
	XMLDocument doc;
	//【】读取文件
	//从磁盘加载XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
	XMLError error = doc.LoadFile(xmlPath);
	//也可以解析字符串
	//从字符串解析XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
	//XMLError tinyxml2::XMLDocument::Parse(const char *xml,size_t nBytes = static_cast<size_t>(-1));
	if (error != XMLError::XML_SUCCESS)
		return;
	//注意,实际解析时返回的指针记得判空,不然遇到解析失败异常就遭了

	//【】解析根节点
	//返回DOM的根元素。等效于FirstChildElement。要获取第一个节点,请使用FirstChild。
	XMLElement* root = doc.RootElement();
	//【】查找
	XMLElement* find_ele = root->FirstChildElement("GroupA");
	if (find_ele) {
		std::cout << find_ele->Name() << std::endl;
		const XMLAttribute* attr = find_ele->FindAttribute("Type");
		if (attr) {
			std::cout << attr->Name() << ":" << attr->Value() << std::endl;
		}
		XMLElement* find_sub = find_ele->FirstChildElement("Name");
		if (find_sub && find_sub->GetText()) {
			std::cout << find_sub->GetText() << std::endl;
		}
	}

	//【】遍历
	std::cout << "\ntraversal_element:" << std::endl;
	traversal_element(&doc, 0);
}

 

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

智能推荐

IE10开发中会遇到的_ie10中.catch-程序员宅基地

文章浏览阅读1k次。2012年微软做的最有诚意的一件事就是对HTML5的支持了:a) IE10对HTML5很好的支持,彻底洗刷了IE9稚嫩残缺的形象,绝大多数为Webkit优化的网页都可以完美的在IE10上运行,且性能非常的好,直接秒杀其他浏览器。做web应用,最担心的就是性能问题,特别是游戏类型的应用。在js性能被人四处诟病时,IE的表现给开发者打了一剂强心针。b) 把js提升到原生语言的地位,可以直接调用_ie10中.catch

GitHub&nbsp;使用教程图文详解_github 使用 指导图-程序员宅基地

文章浏览阅读360次。大纲:一、前言二、GitHub简介三、注册GitHub账号四、配置GitHub五、使用GitHub六、参与GitHub中其它开源项目七、总结注,GitHub官网:https://github.com/,客户端版本:gitversion 1.9.2.msysgit.0。所有软件请到这里下载:http://msysgit.github.io/。 一、前言在前面_github 使用 指导图

邻接表(链式向前星)_链式向前星的优点-程序员宅基地

文章浏览阅读892次,点赞13次,收藏6次。邻接表(链式向前星)链式向前星:用来储存边的信息的以中方法。优点:速度快,节省空间,很常用如果我们用 Vector 来建边,相当于开的是一个动态的二维数组,较数组模拟来说比较慢。有时候还卡空间(被某一道题卡崩的YMF学长:我再用Vector建边我是_链式向前星的优点

CV学习-直方图均衡化_直方图均衡化 cv-程序员宅基地

文章浏览阅读959次。利用直方图均衡化增强图像利用直方图均衡化增强图像概述灰度直方图核心思想证明过程代码测试结果概述 图像对比度增强的方法可以分成两类:一类是直接对比度增强方法;另一类是间接对比度增强方法。直方图拉伸和直方图均衡化是两种最常见的间接对比度增强方法。直方图拉伸是通过对比度拉伸对直方图进行调整,从而“扩大”前景和背景灰度的差别,以达到增强对比度的目的,这种方法可以利用线性或非线性的方法来实_直方图均衡化 cv

git 命令检索_ubuntu 没有git命令-程序员宅基地

文章浏览阅读484次。git_ubuntu 没有git命令

详细的漏洞复现:Shellshock CVE-2014-6271 CVE-2014-7169-程序员宅基地

文章浏览阅读1.3k次。目录 前言 漏洞原理 利用方式 复现过程 1. 环境准备 (1) 为容器配置固定IP地址 (2) 查看bash版本 2. 本地验证:测试镜像系统是否存在漏洞 3. 远程模拟验证(原理验证)..._cve-2014-7169

随便推点

Silvaco_Atlas_LED_ledex01学习笔记_silvaco能仿真量子阱-程序员宅基地

文章浏览阅读7.3k次,点赞21次,收藏68次。# (c) Silvaco Inc., 2018go atlas ## GaN LED Device Simulation## Blue single-quantum well LED## Parameter used for this blue SQW LED#############################################################..._silvaco能仿真量子阱

深蓝学院【视觉SLAM十四讲】汇总_深蓝学院课程合集百度网盘-程序员宅基地

文章浏览阅读3.9k次,点赞4次,收藏42次。SLAM14讲汇总1、安装包及其所在位置:安装包:clion-2021.1.1、eigen-3.2.10、OpenCV、ORB_SLAM2、Pangolin、g2o、所在位置:/home/zhe/1/orb-slam和/home/zhe/Software学习记录:代码_深蓝学院课程合集百度网盘

Linux常用命令_linux 常用命令-程序员宅基地

文章浏览阅读4k次,点赞3次,收藏13次。摘要:采用命令行模式操控Linux系统非常重要。本文总结Linux常用的命令,包括命令的含义,命令的用法以及命令的拓展。关键词:命令行模式 Linux常用命令给Linux系统下达命令,即写Linux命令操控Linux系统做事情,是重要的手段之一。Linux的命令很多,不同类型或版本的Linux系统,Linux命令 在数量上和具体命令上会存在些许差异。但是,Linux常用命_linux 常用命令

layui设置table的各种背景色-程序员宅基地

文章浏览阅读1.2w次,点赞4次,收藏14次。添加以下内容到指定CSS文件,并引入项目即可生效/* 偶数行背景色 */.layui-table[lay-even] tr:nth-child(even) { /* background-color: #aaffaa; */ background-color: #eeffee;}/* 鼠标指向表格时,奇数行背景颜色 */.layui-table tbody tr:h..._layui table 背景色

程序员职业规划-程序员宅基地

文章浏览阅读6.1k次。每个程序员的职业生涯无非以下几种情况:一、帮别人挣钱(打工)不管你是刚入职的小兵,还是管人的经理,甚至是唬人的总监,都属于这一阶段。通常程序员在这一阶段的职业发展分两条线,专家(技术)线和管理线。专家线主要跟机器打交道,搞搞性能调优,高并发处理等等高精尖的问题;管理线主要跟人打交道,了解下属的状态,控制资源和进度。这一阶段的特点是稳定,低风险也低门槛。缺点是有天花板,一切按部就班,不会有太大起伏。_不管你是刚入职的小兵,还是管人的经理,甚至是唬人的总监,都属于这一阶段

ActiveMQ 主备_activemq主备-程序员宅基地

文章浏览阅读2.2k次。Replicated LevelDB Store 主备的方式是用Apache Zookeeper从一组broker中选举一个Master。然后所有的Slave 与Master同步,与Master保持一致。Replicated LevelDB Store_activemq主备