zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++ XML 库 TinyXML2 的基本使用

C++XML 使用 基本
2023-06-13 09:11:24 时间

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

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);
}

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