IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ XML文件读写及简单封装 -> 正文阅读

[C++知识库]C++ XML文件读写及简单封装

背景

????????在我们平时的开发中通常会将一些用户信息或是一些配置信息写入到文件中保存起来,但是使用最简单的 .txt 文件文件进行存储显得不够高级。准确的说,打开任意程序安装目录,虽然能看到文件文件的存在,但基本都是 ReadMe.txt,基本看不到有把这类信息保存在文本文件中的情况。
????????进而我们寻求一种更加常见的信息存储方式,使用 xml 文件。至于 xml 文件的格式和基本知识,如果有不熟悉的同学请
-------> 戳这

1. xml 文件结构简介

????????xml 文件的格式一般是树形结构,如下图:
在这里插入图片描述
????????如上图,绿色部分是 xml 的文件头信息,这里的问号是一种特殊格式,属于正常的 xml 文件内容。
????????绿色这一样的内容可以这样解释:这个标签的标签名为 xml ,它的版本 version 为 1.0,文件编码 encoding 为 UTF-8。在这里,xml 标识标签值,而有等号连接的是属性,等号左侧为属性名,右侧为属性值。如这个标签有两个属性,它们的属性名分别是 version 和 encoding,属性值分别为 1.0 和 UTF-8。那么下面的标签也是这样解释。
????????标签语言有起始标签和结束标签。即<></>。在起始标签和结束标签之间的内容属于本标签的内容。若起始标签和结束标签之间还有别的起始标签和结束标签,那么里面的标签就是当前标签的子级,而当前标签就是内部标签的父级,这样标签之间就有了父子级关联关系,就如同数据结构中的树一般。
????????如上图的 excel 标签,他的起始标签和结束标签之间还有两个 table 标签。而 table 标签的起始标签和结束标签之间又有三个 colum 标签。也就是说,excel 标签有两个 table 标签作为子级标签,而每个 table 标签又拥有 colum 标签作为它的子级标签。
????????就这样,我们可以根据父子级关系找到任意标签所在位置,亦可以根据位置查找到指定的标签。
????????值得一提的是,一个 xml 文件中除去头文件标签后还会剩下一个一个标签作为所有后续加入的标签的祖先节点。如上图中的 excel 标签。xml 文件的读写操作也是建立在这一特性之上的。

2. xml 文件读写

2.1 前期准备

编程环境:

Visual Studio 2015 ;	Windows 10 ;

第三方库源文件下载:

https://sourceforge.net/projects/tinyxml/

在这里插入图片描述
????????如上图,解压后我们只需要这几个文件就可以了,把它们加入到我们项目中。


????????如果您知道如何将这些文件添加至项目中,可以跳过下面的内容,直接看 2.2。


????????新建 vs 控制台应用程序,并将文件拷贝至 stdafx.h 文件所在目录下(这里是防止后面引入后编译过程中引发的 是否忘记添加 #include “stdafx.h”? 的编译错误。对新手并不友好,干脆先简单一点,能用再说。)。如下图所示:
在这里插入图片描述
????????然后将这些文件添加到 vs 项目当中,如下图所示:
在这里插入图片描述
????????如果不会创建文件夹的话,可以右击你的项目名称,点击添加,选择新建筛选器即可。
在这里插入图片描述
????????将文件加入到项目中也是一样的。
在这里插入图片描述
????????这些做完后我们需要打开所有 .cpp 文件,并在顶部加上一行预编译头,保证能够编译通过。

#include "stdafx.h"

????????如下图所示:
在这里插入图片描述

2.2 验证导入效果

????????在 main 函数中加入以下测试代码,编译通过即可。

#include "stdafx.h"
#include <iostream>
#include <string>
#include "tinystr.h"
#include "tinyxml.h"

const std::string strXmlFile = "这里写一个xml文件所在位置,是绝对路径,不要直接照抄哦。";

int main()
{
	TiXmlDocument *pDocument = new TiXmlDocument();
	if (NULL == pDocument)
	{
		std::cout << "NULL == pDocument" << std::endl;
		return -1;
	}
	
	if (!pDocument ->LoadFile(strXmlFile .c_str(), TIXML_ENCODING_UNKNOWN))
	{
		std::cout << "无法加载xml文件!" << std::endl;
		return -1;
	}

	TiXmlElement* pRootElement = pDocument->RootElement();
	if (NULL == pRootElement)
	{
		std::cout << "NULL == pRootElement" << std::endl;
		return -1;
	}
	
	system("pause");
	
    return 0;
}

????????如果没有 xml 文件的话就先用我的吧,新建一个文件文件,更改后缀为 .xml 即可。然后用记事本打开,写入以下内容并保存。

<?xml version="1.0" encoding="UTF-8" ?>
<excel version="1.0" author="huangzhihui">
    <table id="1">
        <colum id="1.1" name="Mike1" width="1" height="1" />
        <colum id="1.2" name="John1" width="2" height="2" />
        <colum id="1.3" name="Lucy1" width="3" height="3" />
    </table>
    <table id="2">
        <colum id="2.1" name="Mike1" width="1" height="1" />
        <colum id="2.2" name="John1" width="2" height="2" />
        <colum id="2.3" name="Lucy1" width="3" height="3" />
    </table>
</excel>

2.3 读取 xml 文件内容

/**
*	读取 xml 文件
*	@param [in]  const std::string &strXmlFilePath		  // xml 文件所在路径
*/
void ReadXmlDocument(const std::string &strXmlFilePath)
{
	if (strXmlFilePath.empty())
	{
		std::cout << "strXmlFilePath is empty!" << std::endl;
		return;
	}

	// 1. 创建 xml 文档对象
	TiXmlDocument *pDocument = new TiXmlDocument();
	if (NULL == pDocument)
	{
		std::cout << "NULL == pDocument" << std::endl;
		return ;
	}

	// 2. 加载 xml 文件
	if (!pDocument->LoadFile(strXmlFilePath.c_str(), TIXML_ENCODING_UNKNOWN))
	{
		std::cout << "无法加载 xml 文件!" << std::endl;
		return ;
	}

	// 3. 打印文件内容
	pDocument->Print();
}

2.4 向 xml 文件中写入内容

/**
*	写入 xml 文件
*	@param [in]  strXmlFilePath		xml 文件所在路径
*/
void WriteXmlDocument(const std::string &strXmlFilePath)
{
	if (strXmlFilePath.empty())
	{
		return;
	}

	// 1. 创建XML文档指针
	TiXmlDocument *pDocument = new TiXmlDocument(strXmlFilePath.c_str());
	if (NULL == pDocument)
	{
		return;
	}

	// 2. 创建声明标签
	TiXmlDeclaration *pDeclaration = new TiXmlDeclaration("1.0", "UTF-8", "");
	if (NULL == pDeclaration)
	{
		return;
	}
	pDocument->LinkEndChild(pDeclaration);

	// 3. 创建祖先标签
	TiXmlElement *pRoot = new TiXmlElement("111");	// 这里可以指定标签名,将其作为参数传入即可
	if (NULL == pRoot)
	{
		return;
	}

	// 4. 为标签设置属性	参数:属性名,属性值
	pRoot->SetAttribute("name", "111");

	// 5. 关联XML文档,成为 XML 文档的根节点
	pDocument->LinkEndChild(pRoot);

	// 6. 为祖先标签添加子级标签
	TiXmlElement *pChildFir = new TiXmlElement("222");
	pChildFir->SetAttribute("name", "222");
	pChildFir->SetAttribute("age", "18");

	pRoot->LinkEndChild(pChildFir);	// 关联成为先祖标签的子级标签

	// 7. 保存文件
	pDocument->SaveFile(strXmlFilePath.c_str());
}

写入效果如下,看看是否符合你的预期呢:
在这里插入图片描述

3. 简单封装

????????根据标签的特征,抽取出一个基类,用于表示一个标签对象。

3.1 xml 标签节点基类 IXmlNode.h

//
// 文件名称:IXmlNode.h
// 功能描述:xml节点基类
// 创建标识:huang_3366 2021/11/27 21:27:54
//

#include "stdafx.h"
#include <string>
#include <vector>
#include "..\inc\tinystr.h"
#include "..\inc\tinyxml.h"

typedef std::vector<TiXmlAttribute *>	TiXmlAttributes;	// 属性集合

class IXmlNode
{
public:
	/**
	*	获取当前原始数据节点
	*	@return TiXmlElement *
	*/
	virtual TiXmlElement *GetNode() = 0;

	/**
	*	获取节点名称
	*	@return std::string
	*/
	virtual std::string GetNodeName() = 0;

	/**
	*	获取节点属性集合
	*	@return TiXmlAttributes *
	*/
	virtual TiXmlAttributes *GetNodeAttributes() = 0;
	
	/**
	*	获取子级数量
	*	@return int 
	*/
	virtual int GetChildCount() = 0;

	/**
	*	获取属性数量
	*	@return int
	*/
	virtual int GetAttributesCount() = 0;

	/**
	*	在指定位置添加子级节点
	*	@param [in]  TiXmlElement *pInsertNode		// 要插入的节点
	*	@param [in]  int nIndex						// 插入位置索引
	*	@return bool
	*/
	virtual bool InsertChildAt(IXmlNode *pInsertNode, int nIndex) = 0;

	/**
	*	删除指定位置的子级节点
	*	@param [in]  int nIndex						// 删除位置索引
	*	@return bool
	*/
	virtual bool DeleteChildAt(int nIndex) = 0;

	/**
	*	删除所有子集节点
	*	@return bool
	*/
	virtual bool RemoveAllChilds() = 0;

	/**
	*	修改节点名称
	*	@param [in]  const std::string &strNodeName		// 要修改的节点新名称
	*/
	virtual void SetNodeName(const std::string &strNodeName) = 0;

	/**
	*	获取指定属性名的属性值
	*	@param [in]  const std::string &strAttriName	// 属性名
	*	@return std::string								// 属性值
	*/
	virtual std::string GetSpecifiedAttribute(const std::string &strAttriName) = 0;

	/**
	*	设置指定属性名的属性值
	*	@param [in]  const std::string &strAttriName	// 属性名
	*	@param [in]  const std::string &strAttriValue	// 属性值
	*	@return bool
	*/
	virtual bool SetSpecifiedAttribute(const std::string &strAttriName, const std::string &strAttriValue) = 0;

	/**
	*	获取指定位置的子级
	*	@param [in] const int &nIndex		// 位置索引
	*	@return IXmlNode *
	*/
	virtual IXmlNode *GetChildAt(const int &nIndex) = 0;

	/**
	*	根据节点名称获取节点
	*	@param [in]  strNodeName	
	*	@return IXmlNode *
	*/
	virtual IXmlNode *GetChildByName(const std::string &strNodeName) = 0;

	/**
	*	获取父级节点
	*	@return IXmlNode *
	*/
	virtual IXmlNode *GetParent() = 0;

	/**
	*	设置父级节点
	*	@param [in] IXmlNode *pParent	
	*	@return
	*/
	virtual bool SetParent(IXmlNode *pParent) = 0;

protected:

	/**
	*	初始化节点,递归调用
	*	@param [in]  TiXmlElement *pInitNode
	*	@return bool  操作是否成功
	*/
	virtual bool InitXmlNodes(TiXmlElement *pInitNode, IXmlNode *pParent) = 0;
};

typedef std::vector<IXmlNode *>		XmlNodeElements;	// 子级节点集合

3.2 xml 标签节点实现 CXmlNode.h

//
// 文件名称:CXmlNode.h
// 功能描述:xml节点实现类
// 创建标识:huang_3366 2021/11/28 21:55:59
//
#pragma once

#include "IXmlNode.h"

class CXmlNode : public IXmlNode
{
public:
	///
	//			   标准构造析构函数				 //
	///
	
	CXmlNode(TiXmlElement *pInitNode, IXmlNode *pParent);
	~CXmlNode();

public:
	///
	//			   继承 IXmlNode 接口				 //
	///

	virtual TiXmlElement *GetNode() override;

	/**
	*	获取节点名称
	*	@return std::string
	*/
	virtual std::string GetNodeName() override;

	/**
	*	获取节点属性集合
	*	@return TiXmlAttributes *
	*/
	virtual TiXmlAttributes *GetNodeAttributes() override;

	/**
	*	获取子级数量
	*	@return int
	*/
	virtual int GetChildCount() override;

	/**
	*	获取属性数量
	*	@return int
	*/
	virtual int GetAttributesCount() override;

	/**
	*	在指定位置添加子级节点
	*	@param [in]  TiXmlElement *pInsertNode		// 要插入的节点
	*	@param [in]  int nIndex						// 插入位置索引
	*	@return bool
	*/
	virtual bool InsertChildAt(IXmlNode *pInsertNode, int nIndex) override;

	/**
	*	删除指定位置的子级节点
	*	@param [in]  int nIndex						// 删除位置索引
	*	@return bool
	*/
	virtual bool DeleteChildAt(int nIndex) override;

	/**
	*	删除所有子集节点
	*	@return bool
	*/
	virtual bool RemoveAllChilds() override;

	/**
	*	修改节点名称
	*	@param [in]  const std::string &strNodeName		// 要修改的节点新名称
	*/
	virtual void SetNodeName(const std::string &strNodeName) override;

	/**
	*	获取指定属性名的属性值
	*	@param [in]  const std::string &strAttriName	// 属性名
	*	@return std::string								// 属性值
	*/
	virtual std::string GetSpecifiedAttribute(const std::string &strAttriName) override;

	/**
	*	设置指定属性名的属性值
	*	@param [in]  const std::string &strAttriName	// 属性名
	*	@param [in]  const std::string &strAttriValue	// 属性值
	*	@return bool
	*/
	virtual bool SetSpecifiedAttribute(const std::string &strAttriName, const std::string &strAttriValue) override;

	/**
	*	获取指定位置的子级
	*	@param [in] const int &nIndex		// 位置索引
	*	@return TiXmlElement *
	*/
	virtual IXmlNode *GetChildAt(const int &nIndex) override;

	/**
	*	根据节点名称获取节点
	*	@param [in]  strNodeName
	*	@return TiXmlElement *
	*/
	virtual IXmlNode *GetChildByName(const std::string &strNodeName) override;

	/**
	*	获取父级节点
	*	@return TiXmlElement *
	*/
	virtual IXmlNode *GetParent() override;

	/**
	*	设置父级节点
	*	@param [in] TiXmlElement *pParent
	*	@return
	*/
	virtual bool SetParent(IXmlNode *pParent) override;

public:
	///
	//			    本类自定义接口				     //
	///

	/**
	*	获取子级节点集合
	*	@return TiXmlElements *
	*/
	virtual XmlNodeElements *GetChildNodes();

	/**
	*	添加或替换子级节点集合
	*	@param [in]  TiXmlElements *pNewChilds		// 要添加或替换的子级节点集合
	*	@return bool
	*/
	virtual bool AddOrReplaceChilds(const XmlNodeElements &NewChilds);

protected:

	/**
	*	初始化节点
	*	@param [in]  TiXmlElement *pInitNode
	*	@return bool  操作是否成功
	*/
	virtual bool InitXmlNodes(TiXmlElement *pInitNode, IXmlNode *pParent) override;

private:
	TiXmlElement		*_pNode				= NULL;		// 当前节点
	IXmlNode			*_pParent			= NULL;		// 父节点
	XmlNodeElements		_ChildNodes	;					// 子级节点集合
	TiXmlAttributes		_Attributes	;					// 节点属性集合
};

3.3 xml 标签节点实现 CXmlNode.cpp

#include "stdafx.h"
#include "CXmlNode.h"

///
//			   标准构造析构函数				 //
///

CXmlNode::CXmlNode(TiXmlElement *pInitNode, IXmlNode *pParent)
{
	InitXmlNodes(pInitNode, pParent);
}

CXmlNode::~CXmlNode()
{
	if (_pNode != NULL)
	{
		_pNode = NULL;
	}

	if (_pParent != NULL)
	{
		_pParent = NULL;
	}

	if (!_ChildNodes.empty())
	{
		RemoveAllChilds();
	}

	if (!_Attributes.empty())
	{
		_Attributes.clear();
	}
}

///
//			   继承 IXmlNode 接口				 //
///

std::string CXmlNode::GetNodeName()
{
	return std::string(_pNode->Value());
}

TiXmlAttributes *CXmlNode::GetNodeAttributes() 
{
	return &_Attributes;
}

XmlNodeElements *CXmlNode::GetChildNodes()
{
	return &_ChildNodes;
}

int CXmlNode::GetChildCount() 
{
	return _ChildNodes.size();
}

int CXmlNode::GetAttributesCount() 
{
	return _ChildNodes.size();
}

bool CXmlNode::InsertChildAt(IXmlNode *pInsertNode, int nIndex)
{
	if (pInsertNode == NULL || nIndex < 0 || nIndex >= GetChildCount())
	{
		return false;
	}
	
	_ChildNodes.insert(_ChildNodes.begin() + nIndex, pInsertNode);

	return true;
}

bool CXmlNode::AddOrReplaceChilds(const XmlNodeElements &NewChilds)
{
	if (NewChilds.empty())
	{
		return false;
	}

	RemoveAllChilds();

	_ChildNodes = NewChilds;

	return true;
}

bool CXmlNode::DeleteChildAt(int nIndex) 
{
	if (_ChildNodes.empty() || _ChildNodes.size() <= nIndex || nIndex < 0)
	{
		return false;
	}

	IXmlNode *pDeleteNode = _ChildNodes[nIndex];
	_ChildNodes.erase(_ChildNodes.begin() + nIndex);
	if (pDeleteNode != NULL)
	{
		delete pDeleteNode;
	}

	return true;
}

bool CXmlNode::RemoveAllChilds() 
{
	if (!_ChildNodes.empty())
	{
		for (int i = 0; i < _ChildNodes.size(); ++i)
		{
			IXmlNode *pTemp = _ChildNodes[i];
			if (pTemp != NULL)
			{
				//pTemp->RemoveAllChilds();
				delete pTemp;
			}
		}

		_ChildNodes.clear();
	}

	return true;
}

void CXmlNode::SetNodeName(const std::string &strNodeName) 
{
	_pNode->SetValue(strNodeName.c_str());
}

std::string CXmlNode::GetSpecifiedAttribute(const std::string &strAttriName) 
{
	if (_Attributes.empty())
	{
		return "Not Exist.";
	}

	for (int i = 0; i < _Attributes.size(); ++i)
	{
		if (_Attributes[i] == NULL)
		{
			continue;
		}

		if (_Attributes[i]->Name() == strAttriName)
		{
			return _Attributes[i]->Value();
		}
	}

	return "Not Exist.";
}

bool CXmlNode::SetSpecifiedAttribute(const std::string &strAttriName, const std::string &strAttriValue) 
{
	if (_Attributes.empty())
	{
		return false;
	}

	for (int i = 0; i < _Attributes.size(); ++i)
	{
		if (_Attributes[i] == NULL)
		{
			continue;
		}

		if (_Attributes[i]->Name() == strAttriName)
		{
			_Attributes[i]->SetValue(strAttriValue.c_str());

			return true;
		}
	}

	return false;
}

IXmlNode *CXmlNode::GetChildAt(const int &nIndex)
{
	if (_ChildNodes.empty() || _ChildNodes.size() <= nIndex || nIndex < 0)
	{
		return NULL;
	}

	return _ChildNodes[nIndex];
}

IXmlNode *CXmlNode::GetChildByName(const std::string &strNodeName)
{
	if (_ChildNodes.empty() || strNodeName.empty())
	{
		return NULL;
	}

	for (int i = 0; i < _ChildNodes.size(); ++i)
	{
		if (_ChildNodes[i] == NULL)
		{
			continue;
		}

		if (_ChildNodes[i]->GetNodeName() == strNodeName)
		{
			return _ChildNodes[i];
		}
	}

	return NULL;
}

IXmlNode *CXmlNode::GetParent()
{
	return _pParent;
}

bool CXmlNode::SetParent(IXmlNode *pParent)
{
	_pParent = pParent;

	return true;
}

bool CXmlNode::InitXmlNodes(TiXmlElement *pInitNode, IXmlNode *pParent)
{
	this->_pNode = pInitNode;
	this->_pParent = pParent;

	if (_pNode == NULL)
	{
		return false;
	}

	// 1. 遍历当前节点的全部属性
	TiXmlAttribute *pAttr = _pNode->FirstAttribute();//第一个属性
	while (NULL != pAttr) //输出所有属性
	{
		_Attributes.push_back(pAttr);
		pAttr = pAttr->Next();
	}

	// 2. 递归遍历子级节点
	for (TiXmlElement *StuElement = _pNode->FirstChildElement();//第一个子元素
		StuElement != NULL;
		StuElement = StuElement->NextSiblingElement())//下一个兄弟元素
	{
		_ChildNodes.push_back(new CXmlNode(StuElement, this));
	}

	return true;
}

TiXmlElement *CXmlNode::GetNode()
{
	return _pNode;
}

3.4 封装验证

int Test()
{
	TiXmlDocument *_pDocument = new TiXmlDocument();
	if (!_pDocument->LoadFile("..\\配置文件\\a.xml", TIXML_ENCODING_UNKNOWN))
	{
		std::cout << "无法加载xml文件!" << std::endl;
		return -1;
	}

	TiXmlElement* pRootElement = _pDocument->RootElement();		//根节点
	if (pRootElement == NULL)
	{
		std::cout << "Can not get the root node of xml document." << std::endl;
		return -1;
	}

	IXmlNode *_pRootNode = new CXmlNode(pRootElement, NULL);
	if (NULL == _pRootNode)
	{
		return -1;
	}

	int nChildCount = _pRootNode->GetChildCount();
	if (nChildCount != 1)
	{
		IXmlNode *pChildFir = _pRootNode->GetChildAt(0);
		if (pChildFir == NULL)
		{
			std::cout << "Error" << std::endl;
			return -1;
		}

		CXmlNode *pChildFirEx = dynamic_cast<CXmlNode *>(pChildFir);
		std::cout << pChildFir->GetSpecifiedAttribute("id") << std::endl;
	}
}

4. 整套操作流程封装

????????第3节只是将 xml 标签进行了封装,对于标签操作只需要使用我们自定义的对象即可,接口的多少及扩展都看自己喜好而定。然而我们还是要实现打开文件,获取根节点,并将根节点传入自定义对象中,也就是说我还想偷懒,干脆一步到位好了。那么接下来就是对文件和节点类进行封装。

4.1 IFileDocument.h 文档操作基类

//
// 文件名称:IFileDocument.h
// 功能描述:文件文档基类
// 创建标识:huang_3366 2021/12/01 22:47:04
//
#pragma once

#include <string>

class IFileDocument
{
public:
	/**
	*	纯虚函数,读取文档
	*/
	virtual void ReadDocument() = 0;

	/**
	*	纯虚函数,向指定文档中写入
	*	@param [in]  const std::string &strDestFile	指定文件的文件名
	*/
	virtual void WriteDocument(const std::string &strDestFile) = 0;
};

4.2 CXmlDocument.h xml文档操作实现类

//
// 文件名称:CXmlDocument.h
// 功能描述:xml 文件实现类
// 创建标识:huang_3366 2021/12/01 22:51:31
//
#pragma once

#include "IFileDocument.h"
#include "CXmlNode.h"

class CXmlDocument : public IFileDocument
{
public:
	CXmlDocument(const std::string &strXmlFile);
	~CXmlDocument();

public:
	/**
	*	纯虚函数,读取文档
	*/
	virtual void ReadDocument() override;

	/**
	*	纯虚函数,向指定文档中写入
	*	@param [in]  const std::string &strDestFile	指定文件的文件名
	*/
	virtual void WriteDocument(const std::string &strDestFile) override;

public:
	/**
	*	获取xml文件的根节点
	*	@return IXmlNode *
	*/
	IXmlNode *GetRootNode();

private:
	/**	
	*	拷贝节点属性
	*	@param [in]  pRootSrc	
	*	@param [in]  pRootDest	
	*/
	void CopyNodeAttributes(TiXmlElement *pRootSrc, TiXmlElement *pRootDest);

	/**
	*	拷贝节点
	*	@param [in]  pRootSrc	
	*	@param [in]  pRootDest	
	*/
	void CopyNodeChilds(IXmlNode *pRootSrc, TiXmlElement *pRootDest);

private:
	std::string		_strXmlFileName;		// xml 文件名
	IXmlNode		*_pRootNode;			// xml 根节点
	TiXmlDocument	*_pDocument;			// xml 文档对象
};

4.3 CXmlDocument.cpp

#include "stdafx.h"
#include "CXmlDocument.h"

CXmlDocument::CXmlDocument(const std::string &strXmlFile)
{
	_strXmlFileName = strXmlFile;
	_pRootNode = NULL;
	_pDocument = NULL;
}

CXmlDocument::~CXmlDocument()
{
	if (_pRootNode != NULL)
	{
		//_pRootNode->RemoveAllChilds();
		delete _pRootNode;
	}
	
	if (_pDocument != NULL)
	{
		delete _pDocument;
	}
}

void CXmlDocument::ReadDocument()
{
	_pDocument = new TiXmlDocument();
	if (!_pDocument->LoadFile(_strXmlFileName.c_str(), TIXML_ENCODING_UNKNOWN))
	{
		std::cout << "无法加载xml文件!" << std::endl;
		return;
	}

	TiXmlElement* pRootElement = _pDocument->RootElement();		//根节点
	if (pRootElement == NULL)
	{
		std::cout << "Can not get the root node of xml document." << std::endl;
		return;
	}

	_pRootNode = new CXmlNode(pRootElement, NULL);
}

void CXmlDocument::WriteDocument(const std::string & strDestFile)
{
	if (strDestFile.empty())
	{
		return;
	}

	// 1. 创建XML文档指针
	TiXmlDocument *pDocument = new TiXmlDocument(strDestFile.c_str());
	if (NULL == pDocument)
	{
		return;
	}

	// 2. 声明XML
	TiXmlDeclaration *pDeclaration = new TiXmlDeclaration("1.0", "UTF-8", "");
	if (NULL == pDeclaration)
	{
		return;
	}
	pDocument->LinkEndChild(pDeclaration);

	// 3. 获取源数据根节点
	TiXmlElement *pRootSrc = GetRootNode()->GetNode();
	if (pRootSrc == NULL)
	{
		return;
	}

	// 4. 创建写入数据根节点
	TiXmlElement *pRoot = new TiXmlElement(pRootSrc->Value());
	if (NULL == pRoot)
	{
		return;
	}
	// 6. 关联XML文档,成为 XML 文档的根节点
	pDocument->LinkEndChild(pRoot);

	// 7. 拷贝节点
	CopyNodeChilds(GetRootNode(), pRoot);

	// 8. 保存文件
	pDocument->SaveFile(strDestFile.c_str());
}

IXmlNode * CXmlDocument::GetRootNode()
{
	if (_pRootNode == NULL)
	{
		ReadDocument();
	}

	return _pRootNode;
}

void CXmlDocument::CopyNodeAttributes(TiXmlElement *pRootSrc, TiXmlElement *pRootDest)
{
	if (pRootSrc == NULL || pRootDest == NULL)
	{
		return;
	}

	// 遍历当前节点的全部属性
	TiXmlAttribute *pAttr = pRootSrc->FirstAttribute();//第一个属性
	while (NULL != pAttr) //输出所有属性
	{
		pRootDest->SetAttribute(pAttr->Name(), pAttr->Value());

		pAttr = pAttr->Next();
	}
}

void CXmlDocument::CopyNodeChilds(IXmlNode *pRootSrc, TiXmlElement *pRootDest)
{
	if (pRootSrc == NULL || pRootDest == NULL)
	{
		return;
	}

	CXmlNode *pRootSrcEx = dynamic_cast<CXmlNode *>(pRootSrc);
	if (pRootSrcEx == NULL)
	{
		return;
	}

	CopyNodeAttributes(pRootSrcEx->GetNode(), pRootDest);

	XmlNodeElements *pChilds = pRootSrcEx->GetChildNodes();
	for (int i = 0; i < pChilds->size(); ++i)
	{
		TiXmlElement *pTempSrc = pChilds->at(i)->GetNode();
		if (pTempSrc == NULL)
		{
			continue;
		}

		TiXmlElement *pTempDest = new TiXmlElement(pTempSrc->Value());
		if (pTempDest == NULL)
		{
			continue;
		}

		// 1. 先拷贝子级属性
		CopyNodeAttributes(pTempSrc, pTempDest);

		// 2.递归拷贝子级
		CopyNodeChilds(pChilds->at(i), pTempDest);

		// 3.成为子级
		pRootDest->LinkEndChild(pTempDest);
	}
}

4.4 封装验证

int Test()
{
	CXmlDocument xmlDoc("..\\配置文件\\a.xml");
	IXmlNode *pRootNode = xmlDoc.GetRootNode();
	if (pRootNode == NULL)
	{
		std::cout << "Error" << std::endl;
		return -1;
	}

	std::string strNodeName = pRootNode->GetNodeName();

	IXmlNode *pChildEle = pRootNode->GetChildAt(0);
	if (pChildEle == NULL)
	{
		std::cout << "Error1" << std::endl;
		return -1;
	}

	xmlDoc.WriteDocument("..\\配置文件\\b.xml");
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-06 15:04:14  更:2021-12-06 15:04:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:00:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码